lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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.