cocos创建一个新的绑定类型的时候会在注册表(Rigister)中进行如下操作
1 创建绑定对象对应的元表,例如
["cc.ClippingNode"] = {--table: 0x00320220
["__le"] = "function: 0x00320328",
["tolua_ubox"] = "table: 0x002c86f0" , -- loop table,
["getStencil"] = "function: 0x00320a00",
["__lt"] = "function: 0x00320308",
[".metatable"] = table: 0x002ca9c8
......
}
2 在注册中插入一条一元表为key,类型名为value的数据,例如
["table: 0x00320220"] = [==[cc.ClippingNode]==]
3 根据创建类型的“基类”,更新并维护"tolua_super"表,也就是cocos+lua的继承关系表,例如
["tolua_super"] = {--table: 0x002c19f8
["table: 0x00320220"] = {--table: 0x00320510
["const cc.ClippingNode"] = "true",
["const cc.Node"] = "true",
["cc.Ref"] = "true",
["cc.Node"] = "true",
[""] = "true",
["const cc.Ref"] = "true",
},
["table: 0x0428e180"] = {--table: 0x0428ef50
["const cc.Node"] = "true",
["const cc.ProtectedNode"] = "true",
["const "] = "true",
["const ccui.Widget"] = "true",
["const cc.Ref"] = "true",
}
......
}
tolua_super表位于注册表中,这个表主要用来为c++接口提供userdata的校验工作。这张表里面里面存放了很张以元表为key的表,子表里面存放了这个元表的“基类”所对应的c++类型名字,每一个类型存有const和非const两种,这样可以方便c++接口中进行使用。
有了这几张表,就可以实现对userdata类型的判定,判定函数是lua_isusertype。
tolua_isusertype函数用来判定lua栈中指定位置是否是cocos绑定的类型所创建的userdata。
int lua_isusertype (lua_State* L, int lo, const char* type)
{
int r;
const char *tn;
//获取元表并入栈
if (lua_getmetatable(L,lo)) /* if metatable? */
{
//在注册表中获取以元表为key获取元表绑定的名字
lua_rawget(L,LUA_REGISTRYINDEX); /* get registry[mt] */
tn = lua_tostring(L,-1);
r = tn && (strcmp(tn,type) == 0);
lua_pop(L, 1);
if (r)
return 1;
else
{
/*如果绑定的名字和请求的参数不一至的情况下,查看请求类型名是否是绑定类型的基类*/
lua_pushstring(L,"tolua_super");
lua_rawget(L,LUA_REGISTRYINDEX); /* get super */
lua_getmetatable(L,lo);
lua_rawget(L,-2); /* get super[mt] */
if (lua_istable(L,-1))
{
int b;
lua_pushstring(L,type);
lua_rawget(L,-2); /* get super[mt][type] */
b = lua_toboolean(L,-1);
lua_pop(L,3);
if (b)
return 1;
}
}
}
return 0;
}