Xlua热更流程

发布时间 2023-04-24 16:22:45作者: mc宇少

转载自:深入理解xLua基于IL代码注入的热更新原理 - iwiniwin - 博客园 (cnblogs.com)

例子:

第一步:GenerateCode:为打了Hotfix标签的方法生成对应的匹配函数

[Hotfix]
public class TestXLua
{
    public int Add(int a, int b)
    {
        return a - b;  // 这里的Add方法故意写成减法,后面通过热更新修复
    }
}

会在配置的Gen目录下生成DelegatesGensBridge.cs文件,其中有为TestXLua.Add生成的对应的匹配函数__Gen_Delegate_Imp1

// DelegatesGensBridge.cs
public partial class DelegateBridge : DelegateBridgeBase
{
    // ...
    public int __Gen_Delegate_Imp1(object p0, int p1, int p2)
    {
#if THREAD_SAFE || HOTFIX_ENABLE
        lock (luaEnv.luaEnvLock)
        {
#endif
            RealStatePtr L = luaEnv.rawL;
            int errFunc = LuaAPI.pcall_prepare(L, errorFuncRef, luaReference);
            ObjectTranslator translator = luaEnv.translator;
            translator.PushAny(L, p0);
            LuaAPI.xlua_pushinteger(L, p1);
            LuaAPI.xlua_pushinteger(L, p2);
            
            PCall(L, 3, 1, errFunc);
            
            
            int __gen_ret = LuaAPI.xlua_tointeger(L, errFunc + 1);
            LuaAPI.lua_settop(L, errFunc - 1);
            return  __gen_ret;
#if THREAD_SAFE || HOTFIX_ENABLE
        }
#endif
    }
    // ...
}

这样的话,调用传递给C#的lua函数就相当于调用以"__Gen_Delegate_Imp"开头的生成函数,这个生成函数负责参数压栈,并通过保存的索引获取到真正的Lua function,然后使用lua_pcall完成Lua function的调用。

第二步:IL注入

为TestXlua添加一个名为"__Hotfix0_Add"的DelegateBridge类型的静态变量。并在原来的Add方法中注入判断静态变量是否不为空,如果不为空就调用静态变量所对应的Lua方法的逻辑。反编译已注入IL代码的Assembly-CSharp.dll,查看其中的TestXLua如下所示:

using System;
using XLua;

// Token: 0x02000016 RID: 22
[Hotfix(HotfixFlag.Stateless)]
public class TestXLua
{
    // Token: 0x06000051 RID: 81 RVA: 0x00002CE0 File Offset: 0x00000EE0
    public int Add(int a, int b)
    {
        DelegateBridge _Hotfix0_Add = TestXLua.__Hotfix0_Add;
        if (_Hotfix0_Add != null)
        {
            return _Hotfix0_Add.__Gen_Delegate_Imp1(this, a, b);
        }
        return a - b;
    }

    // Token: 0x06000052 RID: 82 RVA: 0x00002D14 File Offset: 0x00000F14
    public TestXLua()
    {
        DelegateBridge c__Hotfix0_ctor = TestXLua._c__Hotfix0_ctor;
        if (c__Hotfix0_ctor != null)
        {
            c__Hotfix0_ctor.__Gen_Delegate_Imp2(this);
        }
    }

    // Token: 0x04000022 RID: 34
    private static DelegateBridge __Hotfix0_Add;

    // Token: 0x04000023 RID: 35
    private static DelegateBridge _c__Hotfix0_ctor;
}

第三步:绑定Lua函数

在打补丁时通过xlua.hotfix为静态变量"__Hotfix0_Add"设置一个Lua函数。这样下次调用TestXLua.Add时,"__Hotfix0_Add"将不为空,此时将执行_Hotfix0_Add.__Gen_Delegate_Imp1,即调用设置的Lua函数,而不再执行原有逻辑。从而实现了C#热修复。