[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: calling functions on metatables
- From: "Littlefield, Tyler" <tyler@...>
- Date: Thu, 17 Nov 2011 10:08:56 -0700
Hello all:
I have a rather odd setup, hopefully you'll bare with me. First, if
there's a cleaner way of doing this, I'd love to know about it.
I'm writing a c++ game engine, and in this engine I'm using Lua as my
scripting language. Events are held by an EventManager, which is stored
on -all- objects as a "events" property.
Now, events can have both c++ functions and Lua functions, which is
where my problem comes in.
I created an events table for lua, so you can do something like:
events.AddCallback(this, "enterevent", "enterfunc")
on a room where enterevent is the name of the event, and enterfunc is
the name of the function to call when the enterevent is invoked.
Now, I have the following code to execute scripting, when any object is
loaded:
void Script::Execute(Entity* obj, const std::string &code)
{
lua_State* state = Script::GetState();
int ret = 0;
World* world = World::GetPtr();
if (!luaL_loadbuffer(state, code.c_str(), code.length(),
"execution")) // chunk is at -1
{
//we need to create the metatable and store it in the registry:
lua_pushinteger(state, obj->GetOnum());
lua_newtable(state); // create shadow environment table at -1
lua_settable(state, LUA_REGISTRYINDEX);
//now we get the table back again:
lua_pushinteger(state, obj->GetOnum());
lua_gettable(state, LUA_REGISTRYINDEX);
ObjectToStack(state, obj);
lua_setfield(state, -2, "this");
lua_getfield(state, LUA_REGISTRYINDEX, "meta"); //our metatable
is at -1
lua_setmetatable(state, -2); //set table and pop
lua_setfenv(state, -2); //sets the environment
ret = lua_pcall(state, 0, 0, 0);
if (ret)
{
world->WriteLog(lua_tostring(state, -1), SCRIPT, "script");
lua_pop(state, 1);
}
}
}
So, I get the vnum of the object, (each object has an id), then I add it
along with it's table to the registry.
The table is used as a sort of environment per object, so that if I have
3 rooms with an "enterfunc," I won't have name clashes for example.
Now:
int SCR_AddCallback(lua_State* l)
{
UserData* udata = NULL;
const char* func = NULL;
const char* event = NULL;
if (lua_gettop(l) != 3)
{
SCR_Error(l, "Invalid number of arguments to 'AddCallback'");
return 0;
}
func = lua_tostring(l, -1);
if (!func)
{
SCR_Error(l, "Argument 3 to 'AddCallback' must be the name of the
function to call.");
return 0;
}
event = lua_tostring(l, -2);
if (!event)
{
SCR_Error(l, "Argument 2 to 'AddCallback' must be the name of the
event to add a callback to.");
return 0;
}
udata = (UserData*)lua_touserdata(l, -3);
if (!IsObject(l, udata))
{
SCR_Error(l, "Argument 1 to 'AddCallback' must be the object to
add the callback to.");
return 0;
}
(((Entity*)udata->ptr)->events).AddScriptCallback(udata->ptr, event,
func);
return 0;
}
is my addcallback function. it just adds the object, the name of the
event annd the function to call, pretty easy.
Now here comes the fun bit--when my event gets invoked, I need to know
the metatable of the object. Here's the code, and here I think is the
problem--for some reason it's not finding the function. Any help here
would be appreciated:
BOOL SCR_CallEvent(Entity* obj, const char* func, EventArgs* args, void*
caller)
{
EventArgsUserData* udata = NULL;
lua_State* l = Script::GetState();
lua_pushinteger(l, obj->GetOnum());
lua_gettable(l, LUA_REGISTRYINDEX);
//we get the function we need to call.
lua_getfield(l, -1, func);
if (!lua_isfunction(l, -1))
{
std::cout << "Not a function." << std::endl;
return 0;
}
//we create the event args user data and push it.
udata = (EventArgsUserData*)lua_newuserdata(l,
sizeof(EventArgsUserData));
udata->args = args;
lua_call(l, 1, 0);
return true;
}
Any help/info would be appreciated.
--
Take care,
Ty
Web: http://tds-solutions.net
The Aspen project: a light-weight barebones mud engine
http://code.google.com/p/aspenmud
Sent from my toaster.