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

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM