如何确定lightuserdata的类型?

我正在使用Lua C API将Lua脚本添加到我的游戏引擎(C++)中。

我使用 lua_pushlightuserdata(lua_State *L, void *p) 推入我的对象,当我想要获取这个对象时,我使用 lua_touserdata(lua_State *L, int idx),但我不知道使用 lua_touserdata() 获取的是什么对象。

我该怎么检查呢?

以下是一些示例代码:

bool LuaScript::InitScript(const char* code, GameObject * container)
{
   CloseLua();

   bool ret = false;
   luaState = LuaNewState();
   luaL_openlibs(luaState);
   RegisterAPI(luaState);

   /*将代码加载到 .lua 脚本中,并设置“this”引用包含脚本的 GameObject,并引用 SpriteRenderer 类(GameObject 组件)
   来显示示例。*/
   if (luaL_loadstring(luaState, code) == 0) {
       lua_pushlightuserdata(luaState, container);
       lua_setglobal(luaState, "this");

       SpriteRenderer* spr = new SpriteRenderer();
       lua_pushlightuserdata(luaState, spr);
       lua_setglobal(luaState, "renderer");
       ret = LuaUtils::CallFunction(luaState, NULL);
   }
   else {
       LOG_WARNING("无法加载脚本文件 '%s': %s", container->name.c_str(), lua_tostring(luaState, -1));
   }
   return ret;
}

void LuaScript::RegisterAPI(lua_State* luaState)
{
   luaL_Reg GameObjectAPI[] =
   {
       { "SetActive", SetGameObjectActive },
       { NULL, NULL }
   };
   LuaUtils::RegisterLibrary(luaState, GameObjectAPI, "gameObject");
}

int LuaScript::SetGameObjectActive(lua_State * luaState)
{
   int arguments = lua_gettop(luaState);
   if (arguments != 2) {
       LOG_WARNING("SetActive(GameObject, bool) 需要 2 个参数!");
   }
   else {
       if (lua_islightuserdata(luaState, 1)) {
/*---> 这是问题所在。我假设这个数据是一个 GameObject,但它可能是其他类型的数据,如 SpriteRenderer。*/
           GameObject* go = (GameObject*)lua_touserdata(luaState, 1);
           bool active = lua_toboolean(luaState, 2);
           go->SetActive(active);
       }
   }
   return 0;
}

.lua Script:

function Start()
   gameObject.SetActive(this,false)
   gameObject.SetActive(renderer,false)
end

在以上示例中,gameObject.SetActive(this,false) 可以工作因为 this 是一个 GameObject,但 gameObject.SetActive(renderer,false) 不应该工作,因为 renderer 不是一个 GameObject。但它可以工作,因为我不知道如何检查它是 GameObject 还是 SpriteRenderer,并且 LuaScript::SetGameObjectActive(lua_State * luaState) 中的变量 go 在行 GameObject* go = (GameObject*)lua_touserdata(luaState, 1); 中是错误的(nullptr、内存错误等),因为我将数据分配为 GameObject。

点赞
用户5129715
用户5129715

更好的方法是使用完整的用户数据,因为它与更多的信息绑定。然而,使用轻量级用户数据会更容易一些,因为它可以避免一些代码。

如果你将轻量级用户数据的类型派生自同一个基类,并且你拥有运行时类型信息,那么你可以使用 C++ 语言来查询对象的真实类型。

否则,使用完整的用户数据是最好的方法。

void * mem = lua_newuserdata( L, sizeof( Type) );

这将为你返回一个新的内存块。

new (mem) Type( params );

这将创建合适的类型。

lua_setmetatable

这允许 lua 理解该类型,并且可以在 C/C++ 中通过 lua_getmetatable 进行查询。

Programming in lua 是最值得推荐的关于此话题的书籍。

你的代码的最简单版本如下,但这并不是最正确的方法...

   // 初始化设置
   luaL_newmetadata( L, "some string" );

然后在创建 lua 对象时...

   SpriteRenderer* spr = new SpriteRenderer();
   SpriteRenderer ** data = (SpriteRenderer**)lua_newuserdata( L, sizeof( SpriteRenderer *) ); // 持有指针。
   *data = spr; // 现在 spr 在用户数据中。
   luaL_getmetadata( L, "some string" );
   lua_setmetadata( L, -2 ); // 为此对象设置元数据。

现在你可以测试其类型是否正确...

   luaL_checkudata( L, idx, "some string" ); // 只有当类型正确时才会起作用。
2017-05-25 18:04:32