• xLua热更新(二)实现热更新


    一、环境配置

    要实现热更新功能,我们首先需要开启热更新的宏。操作方法是在「File->Build Settings->Player Settings->Player->Other Settings->Scripting Define Symbols」选项中添加HOTFIX_ENABLE

    开启后,在xLua的菜单中就出现了「Hotfix Inject In Editor」选项。

    当我们在开发补丁版本需要进行热更新测试时,都需要点击一次上图中的「Generate Code」选项重新生成一次代码,然后再点击「Hotfix Inject In Editor」进行注入。
    如果注入时出现了如下错误信息,我们需要将xLua源码中的「Tools」文件夹复制到我们工程的根目录下。

    以上两步操作如果成功的话,在控制台都会有相应提示。环境配置完成后,可以运行xLua自带的热更新示例,测试一下是否能热更成功。

    二、热更新原理

    首先引用一段xLua作者的话,介绍一下xLua实现热更新的原理(原文出处


    热补丁的基本原理其实非常简单,了解后任何程序员都很容易分析出开销,比如对于这个类

    public class Calc
    {
        int Add(int a, int b)
       {
            return a + b
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    打了hotfix标签后,xLua会在il层面注入代码,注入之后这个类会类似这样:

    public class Calc
    {
        static Func<object, int, int, int> hotfix_Add = null;
        int Add(int a, int b)
       {
            if (hotfix_Add != null) return hotfix_Add(this, a, b);
            return a + b
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    如果lua中执行了hotfix调用,hotfix_Add会指向一个lua的适配函数。


    也就是说,在给类加上[Hotfix]特性后,我们就可以在Lua中指定需要“替换”的方法。然后xLua就会将委托指向Lua中对应的函数。

    明白了原理后,我们来尝试实现一个简单的案例

    比如原本有一个C#脚本如下所示

    [Hotfix]
    public class HotfixExample : MonoBehaviour
    {
    	private float _timer = 0f;
    	[LuaCallCSharp]
    	private void Update()
    	{
    		_timer += Time.deltaTime;
    		if (_timer > 2f)
    		{
    			_timer = 0;
    			Debug.Log("这是C#代码");
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    运行结果如下

    现在我们希望通过热更新的方式修改Update方法,那么只需要在Lua脚本中调用xlua.hotfix()方法即可。该方法的第一个参数传入需要热更的C#类,第二个参数传入需要覆盖的方法名,第三个参数传递一个function,作为覆盖后的新方法。

    -- HotfixExample.lua.txt
    local class = CS.XLuaExample.HotfixExample
    local engine = CS.UnityEngine
    -- 允许访问私有成员
    xlua.private_accessible(class)
    xlua.hotfix(class,"Update",function(self)
        self._timer=self._timer + engine.Time.deltaTime
        if self._timer>2 then
            self._timer = 0
            engine.Debug.Log("这是Lua代码")
        end
    end)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在运行结束前还需要将注入到C#方法的引用置空,所以再写一个置空的Lua脚本

    -- HotfixExampleDispose.lua.txt
    xlua.hotfix(CS.XLuaExample.HotfixExample,"Update",nil)
    
    • 1
    • 2

    然后再写个C#脚本模拟调用Lua脚本的入口

    public class StartLua:MonoBehaviour
    {
    	private LuaEnv _luaEnv;
    	private void Awake()
    	{
    		_luaEnv = new LuaEnv();
    		_luaEnv.DoString("require 'HotfixExample'");
    	}
    
    	private void OnDisable()
    	{
    		_luaEnv.DoString("require 'HotfixExampleDispose'");
    	}
    
    	private void OnDestroy()
    	{
    		_luaEnv.Dispose();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    重新生成并注入代码后,运行项目,就会发现热更的Lua代码已经生效了

    当然,在某些情况下我们只需要在原方法的基础上增加一点逻辑,而不是将方法完全覆盖。这时我们可以引入xLua中的util.lua脚本,并使用其提供的hotfix_ex()方法,实现增量热更

    local class = CS.XLuaExample.HotfixExample
    local engine = CS.UnityEngine
    xlua.private_accessible(class)
    
    local util = require 'util'
    util.hotfix_ex(class,"Update",function(self)
    	-- 调用原本的方法
        self.Update(self)
        if self._timer>1 then
            engine.Debug.Log("这是Lua代码")
        end
    end)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    效果如下

    下面来总结一下热更新的流程

    • 首先我们在开发时应该在所有可能需要热更的类前加上[Hotfix]特性,在所有可能需要调用Lua脚本的地方加上[CSharpCallLua],在所有可能被Lua调用的地方加上[LuaCallCSharp],也可以通过反射实现。
    • 如果真的需要热更新,那就通过编写Lua脚本覆盖所需的方法。Lua脚本应该有一个统一的入口集中加载。
    • 最后将热更新的脚本、资源上传到服务器。玩家的客户端检查到更新后将热更新内容下载到本地,完成热更新。
  • 相关阅读:
    python通过jieba和whoosh实现mysql添加全文索引
    python - lambda x用法
    理论与实践:如何写好一个方法
    YOLO系列的Backbone改进历史
    Websocket获取B站直播间弹幕教程——第二篇、解包/拆包
    基于SSM的旅游网站设计与实现
    【开发工具的那些故事】Git跨代码仓库合并代码
    【SpringBoot】Spring常用注解总结
    Linux下应用程序调试
    【OceanBase诊断调优 】—— 索引调优
  • 原文地址:https://blog.csdn.net/LWR_Shadow/article/details/127134638