tolua之C#与Lua的交互方式

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的客户端框架

你可能感兴趣的:(tolua之C#与Lua的交互方式)