xlua通信

发布时间 2023-04-14 17:34:36作者: mc宇少

xlua的wrap文件:Xlua 生成wrap文件 - 柯腾_wjf - 博客园 (cnblogs.com)

脑图:xlua - 百度脑图 (baidu.com)

相关扩展:XLua标签(转) - mc宇少 - 博客园 (cnblogs.com)

参考资料:

干货:xlua 是怎么和C#通信的?(二) - 知乎 (zhihu.com)

深入理解xLua基于IL代码注入的热更新原理 - iwiniwin - 博客园 (cnblogs.com)

Lua调用c#发生了什么? - 柯腾_wjf - 博客园 (cnblogs.com)

 

 

1.生成函数填充元表

// TestXLua.cs
[LuaCallCSharp]
public class TestXLua
{
    public string Name;
    public void Test1(int a){
    }
    public static void Test2(int a, bool b, string c)
    {
    }
}

 


Generatecode后生成的XXXwrap文件:
public class TestXLuaWrap 
{
    public static void __Register(RealStatePtr L)
    {
        ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
        System.Type type = typeof(TestXLua);
        //准备注册类的非静态成员(成员变量,成员方法等),主要为元表添加_gc和_tostring,并准备好method表、getter表、setter表。
        Utils.BeginObjectRegister(type, L, translator, 0, 1, 1, 1);
         
        //将下面生成的非静态包裹方法注册进对应的表中
        Utils.RegisterFunc(L, Utils.METHOD_IDX, "Test1", _m_Test1);//成员方法放进method表中
        Utils.RegisterFunc(L, Utils.GETTER_IDX, "Name", _g_get_Name);//成员变量get放进getter表中
        Utils.RegisterFunc(L, Utils.SETTER_IDX, "Name", _s_set_Name);//成员变量get放进setter表中

        //完成类的非静态成员的注册,主要为元表生成_index和_newIndex元方法。
        //_index元方法:当访问userdata[key]时,先依次查询之前通过RegisterFunc填充的methods、getters等表中是否存有对应key的包裹方法,
        //如果有就直接使用,没有则递归在父类中查找。
        Utils.EndObjectRegister(type, L, translator, null, null,
            null, null, null);

        //对类的静态值(例如静态变量,静态方法等)进行注册前做一些准备工作。主要是为类生成对应的cls_table表,
        //以及提前创建好static_getter表与static_setter表,后续用来存放静态字段对应的get和set包裹方法。注意这里还会为cls_table设置元表meta_table
        //cls_table:存类数据的表,Lua注册表[xlua_csharp_namespace]实际上对应的就是CS全局表,所以要在xLua中访问C#类时才可以直接使用CS.A.B.C这样的形式
        //Lua注册表 = {
        //xlua_csharp_namespace = {  -- 就是CS全局表
        //A = {
        //    B = {
        //       C = cls_table
        //    }
        //},
        //},
        // }
        Utils.BeginClassRegister(type, L, __CreateInstance, 2, 0, 0);

        //跟前面一样,注册到对应的表中
        Utils.RegisterFunc(L, Utils.CLS_IDX, "Test2", _m_Test2_xlua_st_);

        //结束对类的静态值的注册,为cls_table的元表meta_table设置_index元方法和_newIndex元方法。
        Utils.EndClassRegister(type, L, translator);
    }
    
    [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
    static int __CreateInstance(RealStatePtr L)
    {
            ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
            TestXLua gen_ret = new TestXLua();
            translator.Push(L, gen_ret);
            return 1;
        
    }

    //类成员方法
    [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
    static int _m_Test1(RealStatePtr L)
    {
        try {
            ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
            TestXLua gen_to_be_invoked = (TestXLua)translator.FastGetCSObj(L, 1);
            int _a = LuaAPI.xlua_tointeger(L, 2);
            gen_to_be_invoked.Test1( _a );
            return 0;
            {
               
            }
    }

    //类静态方法
    [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
    static int _m_Test2_xlua_st_(RealStatePtr L)
    {
            int _a = LuaAPI.xlua_tointeger(L, 1);
            bool _b = LuaAPI.lua_toboolean(L, 2);
            string _c = LuaAPI.lua_tostring(L, 3);
            TestXLua.Test2( _a, _b, _c );
            return 0;
    }
    
    //字段生成的get方法
    [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
    static int _g_get_Name(RealStatePtr L)
    {
            ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
            TestXLua gen_to_be_invoked = (TestXLua)translator.FastGetCSObj(L, 1);
            LuaAPI.lua_pushstring(L, gen_to_be_invoked.Name);
        return 1;
    }
    
    //字段生成的set方法
    [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
    static int _s_set_Name(RealStatePtr L)
    {
            ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
            TestXLua gen_to_be_invoked = (TestXLua)translator.FastGetCSObj(L, 1);
            gen_to_be_invoked.Name = LuaAPI.lua_tostring(L, 2);
        return 0;
    }
}

总结:

生成代码会为类的非静态值都生成对应的包裹方法(字段改成get和set方法),并将包裹方法以key = func的形势注册到不同的表中。userdata元表的_index和_newindex负责从这些不同的表中找到对应key的方法,通过包裹方法实现对c#层对象的控制.

生成代码会为每个类以命名空间为层次结构生成cls_table表。与类的非静态值相同,生成代码也会为类的静态值都生成对应的包裹方法并注册到不同的表中(静态方法会直接注册到cls_table中而不是function表中)。而cls_table元表的_index和_newIndex负责从不同的表中找到对应key的包裹方法,最终通过调用包裹方法实现对c#类的控制。

local obj = CS.TestXLua()
obj.Name = "test"  -- 赋值操作将触发obj元表的__newindex,__newindex在setter表中找到Name对应的set包裹方法_s_set_Name,然后通过调用_s_set_Name方法设置了TestXLua对象的Name属性为"test"
CS.TestXLua.Test2()  -- CS.TestXLua获取到TestXLua类对应的cls_table,由于Test2是静态方法,在cls_table中可以直接拿到其对应的包裹方法_m_Test2_xlua_st_,然后通过调用_m_Test2_xlua_st_而间接调用了TestXLua类的Test2方法