zoukankan      html  css  js  c++  java
  • xlua 原理

    基于版本 104

    可以直接在lua访问c#函数原理:

    CS 是一个table,设置了一个__index函数,如果访问不存在的成员的时候,会走__index函数,调用import_type从C#中找到具体函数设置到CS中。以便下一次访问的时候直接使用

    xlua在生产wrap时,会生成一个partial ObjectTranslator类,对该类添加了成员变量XLua_Gen_Initer_Register__ s_gen_reg_dumb_obj,在类的构造函数中会提交一个函数(AddIniter),执行该函数时会注册已经生成了wrap的wrap类和__Register方法到ObjectTranslator.delayWrap中。

    没有生产类的wrap时,就不会有上面的过程,delayWrap就为空

    在lua访问cs中不存在的类的时候,会触发ImportType,ImportType走方法TryDelayWrapLoader注册该类的wrap类和方法。

            public bool TryDelayWrapLoader(RealStatePtr L, Type type)
            {
    .....
                if (delayWrap.TryGetValue(type, out loader))
                {
                    delayWrap.Remove(type);
                    loader(L);
                }
                else
                {
    .....
                    if (!DelegateBridge.Gen_Flag && !type.IsEnum() && !typeof(Delegate).IsAssignableFrom(type) && Utils.IsPublic(type))
                    {
                        Type wrap = ce.EmitTypeWrap(type);
                        MethodInfo method = wrap.GetMethod("__Register", BindingFlags.Static | BindingFlags.Public);
                        method.Invoke(null, new object[] { L });
                    }
                    else
                    {
                        Utils.ReflectionWrap(L, type, privateAccessibleFlags.Contains(type));
                    }
    .....
    
                return true;
            }

    从方法中可以看到,如果delayWrap存在对于的wrap和Register函数,那么就走生成好的wrap代码;如果没有,非生成wrap模式就会走EmitTypeWrap方法,动态生成该类的wrap代码和Rigister函数。调用Register函数注册该wrap。如果采用生成wrap模式,DelegateBridge.Gen_Flag就会被生成的代码设置为true,那么凡是没有生成wrap的类代码,都会走Utils.ReflectionWrap

    在ReflectionWrap中,对于方法会调用PushFixCSFunction把方法放入fix_cs_functions中,把把函数名,对应的索引和FixCSFunctionWraper注册到lua

            internal void PushFixCSFunction(RealStatePtr L, LuaCSFunction func)
            {
    .....
                    LuaAPI.xlua_pushinteger(L, fix_cs_functions.Count);
                    fix_cs_functions.Add(func);
                    LuaAPI.lua_pushstdcallcfunction(L, metaFunctions.FixCSFunctionWraper, 1);
    .....
            }

    在lua中调用该函数时,会走FixCSFunction,根据索引定位到具体的函数执行

            static int FixCSFunction(RealStatePtr L)
            {
                try
                {
                    ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
                    int idx = LuaAPI.xlua_tointeger(L, LuaAPI.xlua_upvalueindex(1));
                    LuaCSFunction func = (LuaCSFunction)translator.GetFixCSFunction(idx);
                    return func(L);
                }
                catch (Exception e)
                {
                    return LuaAPI.luaL_error(L, "c# exception in FixCSFunction:" + e);
                }
            }

    Hotfix原理
    以08_Hotfix中HotfixTest为列
    修改HotfixTest的方法Update

    xlua.hotfix(CS.HotfixTest, 'Update', function(self)
                        self.tick = self.tick + 1
                        if (self.tick % 50) == 0 then
                            print('<<<<<<<<Update in lua, tick = ' .. self.tick)
                        end
                    end

    hotfix函数实现

    xlua.hotfix = function(cs, field, func)
        if func == nil then func = false end
        local tbl = (type(field) == 'table') and field or {[field] = func}
        for k, v in pairs(tbl) do
            local cflag = ''
            if k == '.ctor' then
                cflag = '_c'
                k = 'ctor'
            end
            local f = type(v) == 'function' and v or nil
            xlua.access(cs, cflag .. '__Hotfix0_'..k, f) -- at least one
            pcall(function()
                for i = 1, 99 do
                    xlua.access(cs, cflag .. '__Hotfix'..i..'_'..k, f)
                end
            end)
        end
        xlua.private_accessible(cs)
    end

    经过xlua注入生成的Update代码如下

      private static DelegateBridge __Hotfix0_Update;
      private void Update()
        {
            DelegateBridge _Hotfix0_Update = __Hotfix0_Update;
            if (_Hotfix0_Update != null)
            {
                _Hotfix0_Update.__Gen_Delegate_Imp18(this);
            }
            else if (++tick % 50 == 0)
            {
                Debug.Log((object)(">>>>>>>>Update in C#, tick = " + tick));
            }
        }

    xlua.access 对应方法 StaticLuaCallbacks.XLuaAccess

           public static int XLuaAccess(RealStatePtr L)
            {
    ......
              Type type = getType(L, translator, 1);//HotfixTest
    ......
                    string fieldName = LuaAPI.lua_tostring(L, 2);// _Hotfix0_Update
    ......
    
                    if (LuaAPI.lua_gettop(L) > 2) // set
                    {
                        var field = type.GetField(fieldName, bindingFlags);
                        if (field != null)
                        {
                            field.SetValue(obj, translator.GetObject(L, 3, field.FieldType));
                            return 0;
                        }
                        var prop = type.GetProperty(fieldName, bindingFlags);
                        if (prop != null)
                        {
                            prop.SetValue(obj, translator.GetObject(L, 3, prop.PropertyType), null);
                            return 0;
    .......
            }

    在该方法中,设置方法对应的hotfix属性为lua函数。该例子中设置_Hotfix0_Update

      

  • 相关阅读:
    二次剩余
    【2020.9.29 NOIP模拟赛 T3】寻梦(fantasy)
    Graph and Queries
    势函数和鞅的停时定理学习笔记
    毒瘤计数题汇总
    2-SAT
    CF559E Gerald and Path
    [SDOI2019]世界地图
    CF1349D Slime and Biscuits
    AT4928 [AGC033E] Go around a Circle
  • 原文地址:https://www.cnblogs.com/hygblog/p/9698982.html
Copyright © 2011-2022 走看看