[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.