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里。
原文地址:https://www.cnblogs.com/wang-jin-fu/p/13508812.html