zoukankan      html  css  js  c++  java
  • Xlua 热补丁技术

    一、xlua.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.access:
    public static int XLuaAccess(RealStatePtr L)
    {
        try
        {
            ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
            Type type = getType(L, translator, 1);//静态方法,通过cls_table["UnderlyingSystemType"]获取ud。
            object obj = null;
            if (type == null && LuaAPI.lua_type(L, 1) == LuaTypes.LUA_TUSERDATA)
            {
                obj = translator.SafeGetCSObj(L, 1);//对象方法,获取对象object
                type = obj.GetType();
            }
     
            string fieldName = LuaAPI.lua_tostring(L, 2);
            BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
     
            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);//lua_function转委托并进行赋值。
                    return 0;
                }
            }
            else //get
            {
                var field = type.GetField(fieldName, bindingFlags);
                if (field != null)
                {
                    translator.PushAny(L, field.GetValue(obj));
                    return 1;
                }
                var prop = type.GetProperty(fieldName, bindingFlags);
                if (prop != null)
                {
                    translator.PushAny(L, prop.GetValue(obj, null));
                    return 1;
                }
            }
            return LuaAPI.luaL_error(L, "xlua.access, no field " + fieldName);
        }
    }
    以下面为例子:
    xlua.hotfix(CS.Calc, 'add',function(a,b)
        print('Update in lua')
    end)
    1. xlua.access(CS.Calc, '__Hotfix0_add', func)。
    2. 由于CS.Calc = cls_table,类型是LUA_TTABLE,通过cls_table["UnderlyingSystemType"]获取到类的ud。
    3.通过ud获取到CS.Calc 的Type。translator.Get(L, -1, out value);
    4.translator.GetObject把lua_function转成对应的委托。也就是上面截图的else的逻辑。由于xlua生成的补丁代码是带参数类型的委托,那么这边走的是把lua_function转成委托(__Gen_Delegate_ImpX)的分支。
    5.委托赋值给CS.Calc. __Hotfix0_add。
    二、xlua IL层面是如何把代码注入到源码的?
    网上有个示例可以参考下:
    [hotfix]
    public class Calc
    {
        int Add(int a, int b) 
        {
            return a + b;
        }
    }
     
     
    public class Calc
    {
        static Func<object, int, int, int> __Hotfix0_Add = null; //xlua注入
        int Add(int a, int b) 
        {
            if (__Hotfix0_Add != null) return __Hotfix0_Add(this, a, b); //xlua注入
            return a + b;//原逻辑
        }
    }
    注入代码的逻辑在Hotfix.injectMethod里。
  • 相关阅读:
    关于Markdown
    20. 有效的括号(栈)
    数组队列
    MySql编码、卸载、启动问题
    循环队列
    链表实现与时间复杂度分析
    栈的应用和基本实现
    使用链表实现栈
    封装动态数组类Array
    Android平台的开发环境的发展演变
  • 原文地址:https://www.cnblogs.com/wang-jin-fu/p/13508812.html
Copyright © 2011-2022 走看看