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里。


免責聲明!

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



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