Re: Best Practice Scoping Different Scripts+Expose Object/ luabind:resume with optional return value
Nigel Atkinson <[email protected]> Wed, 13 Jun 2012 20:24:44 +1000
| Newsgroups | gmane.comp.lang.lua.bind.user |
|---|---|
| Message-ID | <[email protected]> |
Perhaps my example was too brief.
In each "actor" script (actor1.lua, actor2.lua, actor_bob.lua, etc) the
actor is referenced simply as "actor". Perhaps a better example for you:
---actor1.lua----
local namespace = {} -- call this table whatever you want.
function namespace.initActor( actor )
actor.name = 'Actor number 1'
end
function namespace.sayhello( actor )
print( 'Hello from ' .. actor.name )
end
return namespace -- will be returned by the call to require
---actor_little_dog.lua-----
local namespace = {}
function namespace.initActor( actor )
actor.name = 'Fido'
actor.legs = 4
actor.can_fly = false
end
return namespace
----Some C++----
// Here's kinda what I do with my Quest scripts. Hope this is
enlightening
// Load or retrieve already loaded script for this actor...
luabind::object require = globals(L)["require"];
luabind::object actor_scripts = require( script_file );
// actor_scripts is a table of functions that where defined in the
script.
luabind::object initActor = actor_scripts["initActor"];
initActor( ptrActor );
-------8<--------
I've skipped over all the error checking etc.
It should be possible to hide the namespace table and the return statement at
the end from the 'end user' with some Lua hijinks, perhaps with a custom require
function - I'd have to think more on how to do that however.
I've attached a couple of files that demonstrate loading a script and using
a function from it without polluting the global table, which allows you to
load lots of them with functions with the same names and not collide.
Note that 'require' caches loaded scripts. So if you call it again with the same file name it
just returns the table of functions again, with out reading and interpreting the file again.
Regards
Nigel
On Tue, 2012-06-12 at 04:29 -0700, Harakiri wrote:
> Thanks for your reply - however i dont think this is the design i had
> in mind.
>
> I dont want to create actor objects in scripts - these are all managed
> in c++ - moreover i dont want to refer to each actor with a unique
> name in scripts - each script should be for one actor and in each
> script i just want to refer with "actor" to the current object - not
> actor1 actor2 etc.
>
> I want to make this as easy as possible because im not the one writing
> scripts and want to make sure that there is basically no way to make
> mistakes.
>
> Can you elaborate more on the table thing?
>
> Alternatively i thought i have to NOT expose my actor objects to a
> script within a table but just via function parameter e.g.
>
> function onInit(Actor)
> actor->SubscribeEvent(SPECIAL_EVENT,myEvent)
> end
>
> function myEvent(Actor)
> actor:doSomething)
> end
>
> Now - even in this case were i dont have to use a global= var actor -
> how do i make sure there is no collision with other actor scripts
> which also implement onInit and create a function myEvent ? How do i
> scope this from c++ - i want to make this is painless as possible and
> dont want to require script writers to know about modules etc - it
> would be no issue to load the lua file in my code and prepend
> something like module myModule { .. } if this is required - but is
> this the way todo it? Is there a better design approach?
>
> Thanks
>
>
> --- On Tue, 6/12/12, Nigel Atkinson <[email protected]> wrote:
>
> From: Nigel Atkinson <[email protected]>
> Subject: Re: [luabind] Best Practice Scoping Different Scripts
> +Expose Object/ luabind:resume with optional return value
> To: [email protected]
> Date: Tuesday, June 12, 2012, 1:13 AM
>
> Hi there!
>
> As far as scoping your actors, this might help. I do a
> similar thing with loadable "Quests' in a game.
>
> See http://lua-users.org/wiki/LuaModuleFunctionCritiqued for a
> rather in-depth look at 'modules' in Lua. This jist of it is
> you could use the module key word in your actor files however
> a better technique is to define a table, put all your
> functions in it, and then return that table at the end of the
> file. This is then returned from the 'require' function.
>
> So each actor file would look something like...
>
> -- local makes it local to the file as the whole file is run
> as a function by require.
>
> local actor = {}
>
> function actor.sayhello()
>
> print( 'Hello from actor 1!' )
>
> end
>
> ...and so on ...
>
> return actor
>
> -----8<-------
>
> actor1 = require('actor1')
>
> -----8<-------
>
> You can run require in a number of ways, using
> luabind::object, or luaL_dostring, or as part of a larger
> script etc.
>
> HTH
>
> Nigel
>
>
>
> On Tue, June 12, 2012 10:09 am, Harakiri wrote:
> > 1. Resuming a coroutine which has yields forces me to always
> have a final
> > "return 0" in my function to not produce any error e.g.
> consider
> >
> > luabind::object m_CoroutineFunc = ...
> > m_CoroutineFunc.push(m_CoroutineFunc.interpreter());
> > lua_State * pThread =
> lua_tothread(m_CoroutineFunc.interpreter(), -1);
> > lua_pop(m_CoroutineFunc.interpreter(), 1);
> > int yieldTime = luabind::resume<int>(pThread);
> >
> > in my coroutine i use coroutine.yield(seconds*1000) - so
> this value will
> > be returned and i know when i should call luabind::resume in
> my c++ logic
> > again.
> > However the issue arises that this forces me to always use
> return 0 at the
> > end of my coroutines - otherwise "luabind::resume<int>" will
> throw an
> > error which is not pretty - is there another way?
> >
> > Additionally - i set this coroutine to c++ via a callback
> e.g. in lua i
> > have myobj->addCoroutine(coroutine.create(myLuaFunc)) - the
> c++ side
> > checks if luabind::object is (luabind::type(obj) ==
> LUA_TTHREAD) - now for
> > simplicity i dont want to use "coroutine.create" in lua but
> simply give
> > the myLuaFunc to my callback of type LUA_TFUNCTION - how can
> i "convert"
> > this function to a coroutine? e.g. LUA_TFUNCTION to
> LUA_TTHREAD in c++ as
> > opposed by doing this in lua?
> >
> > 2. I want to create an AI engine with different scripts for
> each actor -
> > lets call them actor1.lua actor2.lua - im binding my actor
> class with
> > luabind - and want to expose my actor1 obj to actor1.lua and
> actor2 obj to
> > actor2.lua - while only using one lua_state for everything
> (i think this
> > is the best if you have many actors..)
> >
> > Currently i use luabind::globals(myLuaState)["actor"] =
> actor1; - for the
> > sake of simplicity i want that every actorX.lua script
> simply refers to
> > his own object as "actor" and not have a different object
> name for every
> > actor - e.g. in actor1.lua i might use actor->Print("Im
> actor 1") and in
> > actor2.lua i use actor->Print("Im actor 2") - how do i scope
> this
> > correctly ? That once i call a function defined in lua from
> c++ in script
> > actor1.lua with actor1 obj and the other time with actor2
> obj and
> > actor2.lua.
> >
> > Moreover i read that by default everything in lua is global
> - so how do i
> > make sure that there is no function name collision when
> actor1.lua defines
> > "function OnEventX" and actor2.lua does the same ? I also
> like to compile
> > these script once at startup only...
> >
> > Thanks!
> >
> >
> ------------------------------------------------------------------------------
> > Live Security Virtual Conference
> > Exclusive live event will cover all the ways today's
> security and
> > threat landscape has changed and how IT managers can
> respond. Discussions
> > will include endpoint security, mobile security and the
> latest in malware
> > threats.
> http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
> > _______________________________________________
> > luabind-user mailing list
> > [email protected]
> > https://lists.sourceforge.net/lists/listinfo/luabind-user
> >
>
>
>
> -----Inline Attachment Follows-----
>
> ------------------------------------------------------------------------------
> Live Security Virtual Conference
> Exclusive live event will cover all the ways today's security
> and
> threat landscape has changed and how IT managers can respond.
> Discussions
> will include endpoint security, mobile security and the latest
> in malware
> threats.
> http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
>
> -----Inline Attachment Follows-----
>
> _______________________________________________
> luabind-user mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/luabind-user
>
> ------------------------------------------------------------------------------
> Live Security Virtual Conference
> Exclusive live event will cover all the ways today's security and
> threat landscape has changed and how IT managers can respond. Discussions
> will include endpoint security, mobile security and the latest in malware
> threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
> _______________________________________________ luabind-user mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/luabind-user
------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and
threat landscape has changed and how IT managers can respond. Discussions
will include endpoint security, mobile security and the latest in malware
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
luabind-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/luabind-user
quest1.lua
(text/x-lua, 275 B)
local questscripts = {}
print 'Loading Quest Scripts'
function questscripts.initQuest( quest )
print 'Initialising quest'
quest.title = 'Arrow with your name on it (to the knee).'
print 'Quest initialised'
end
print 'Quest Scripts Loaded'
return questscripts
quests.cpp
(text/x-c++src, 1.4 KB)
#include <iostream>
#include <lua.hpp>
#include <luabind/luabind.hpp>
#include <luabind/object.hpp>
using std::cout;
using std::endl;
class Quest
{
std::string mTitle;
public:
std::string getTitle() { return mTitle; }
void setTitle( std::string title ) { mTitle = title; }
};
void test( lua_State* L )
{
using namespace luabind;
module( L )
[
class_<Quest>("Quest")
.def( constructor<>() )
.property("title", &Quest::getTitle, &Quest::setTitle )
];
Quest *q = new Quest;
object require = globals(L)["require"];
object script_table = require( "quest1" );
object initQuest = script_table["initQuest"];
initQuest( q );
cout << "Quest name is: " << q->getTitle() << endl;
delete q;
const char* script =
"print( 'Dumping _G. There should be no Quest functions in the global table' )\n"
"for k,v in pairs(_G) do\n"
" print( k, v )\n"
"end\n"
;
if( luaL_dostring( L, script ) )
{
cout << lua_tostring( L, -1 ) << endl;
}
}
int main( int argc, char *argv[] )
{
lua_State* L;
L = lua_open();
luaL_openlibs( L );
luabind::open( L );
try
{
test( L );
}
catch( luabind::error &e )
{
cout << "Luabind threw an error: " << e.what();
}
lua_close( L );
return 0;
}