1、tolua是Unity静态绑定lua的一个解决方案,它通过C#提供的反射信息分析代码并生成相应的Wrap类。
2、Wrap类自动生成用于在Lua中访问Unity的绑定代码,并把C#中的常量、变量、函数、属性、类等暴露给Lua。因此,Lua需要访问的C#类应用在CustomSettings类的customTypeList中注册,并重新生成Wrap文件。这些文件的注册方法会汇总在LuaBinder.cs的Bind方法中,虚拟器开启后应先调用此方法。
3、在Wrap.cs内有Register函数,它由四部分组成:
BeginClass部分,在下图可以看到,BeginClass主要功能是将注册类作为一个Lua表加入Loaded表内,并为这个Lua表设置名称、引用数、构造方法。如果注册类存在父类,将父类设为其元表。在C#内还设置了__gc元方法。
RegFunction部分,在tolua.c的1413行可以看到,依次压入了函数名和函数地址,并调用lua_rawset(lua_State* L,int index),表示t[k]=v,t为栈索引为index的值,v为栈顶值,k为栈顶下一个值。
RegVar部分,每一个变量或属性或被包装成get_xxx,set_xxx函数注册添加到类的元表的gettag,settag表中去,用于调用和获取。
EndClass部分,把该类加到所在模块代表的表中(如将GameObject加入到UnityEngine模块内)
tolua.c的1279行和1222行
LUALIB_API int tolua_beginclass(lua_State *L, const char *name, int baseType, int ref)
{
int reference = ref;
lua_pushstring(L, name);
lua_newtable(L);
_addtoloaded(L);
if (ref == LUA_REFNIL)
{
lua_newtable(L); //创建一个Lua表存放C#类映射
lua_pushvalue(L, -1);
reference = luaL_ref(L, LUA_REGISTRYINDEX);
}
else
{
lua_getref(L, reference);
}
if (baseType != 0) //存在父类,设置元表
{
lua_getref(L, baseType);
lua_setmetatable(L, -2);
}
lua_pushlightuserdata(L, &tag);
lua_pushnumber(L, 1);
lua_rawset(L, -3); //t[k] = v,这里t=stack[-3],v为栈顶值,k为栈顶下一个值
lua_pushstring(L, ".name");
_pushfullname(L, -4);
lua_rawset(L, -3);
lua_pushstring(L, ".ref");
lua_pushinteger(L, reference);
lua_rawset(L, -3);
lua_pushstring(L, "__call");
lua_pushcfunction(L, class_new_event); //压入构造方法,见下
lua_rawset(L, -3);
tolua_setindex(L);
tolua_setnewindex(L);
return reference;
}
static int class_new_event(lua_State *L)
{
if (!lua_istable(L, 1))
{
return luaL_typerror(L, 1, "table");
}
int count = lua_gettop(L);
lua_pushvalue(L,1); //复制index=1处的元素到栈顶
if (lua_getmetatable(L,-1))
{
lua_remove(L,-2);
lua_pushstring(L, "New"); //调用New方法实例化
lua_rawget(L,-2); //t[k]压入栈,t这里为stack[-2],k为栈顶值,弹出k
if (lua_isfunction(L,-1))
{
for (int i = 2; i <= count; i++)
{
lua_pushvalue(L, i);
}
lua_call(L, count - 1, 1);
return 1;
}
lua_settop(L,3);
}
return luaL_error(L,"attempt to perform ctor operation failed");
}
4、Lua与C#的通过弱引用维持,lua有__mode元方法,它有三种模式:k、v和kv,具体可参考Lua5.1文档
tolua提供的一些方法,在tolua.c的tolua_openlibs函数内注册
tolua.c的2175行和2562行
static const struct luaL_Reg tolua_funcs[] =
{
{ "gettime", tolua_gettime },
{ "typename", tolua_bnd_type },
{ "setpeer", tolua_bnd_setpeer},
{ "getpeer", tolua_bnd_getpeer},
{ "getfunction", tolua_bnd_getfunction},
{ "initset", tolua_initsettable},
{ "initget", tolua_initgettable},
{ "int64", tolua_newint64},
{ "uint64", tolua_newuint64},
{ "traceback", traceback},
{ NULL, NULL }
};
LUALIB_API void tolua_openlibs(lua_State *L)
{
initmodulebuffer();
luaL_openlibs(L);
int top = lua_gettop(L);
tolua_setluabaseridx(L);
tolua_opentraceback(L);
tolua_openpreload(L);
tolua_openubox(L);
tolua_openfixedmap(L);
tolua_openint64(L);
tolua_openuint64(L);
tolua_openvptr(L);
//tolua_openrequire(L);
luaL_register(L, "Mathf", tolua_mathf);
luaL_register(L, "tolua", tolua_funcs);
lua_getglobal(L, "tolua");
lua_pushstring(L, "gettag");
lua_pushlightuserdata(L, &gettag);
lua_rawset(L, -3);
lua_pushstring(L, "settag");
lua_pushlightuserdata(L, &settag);
lua_rawset(L, -3);
lua_pushstring(L, "version");
lua_pushstring(L, "1.0.7");
lua_rawset(L, -3);
lua_settop(L,top);
}
基于tolua的客户端框架