XLua——热更新

article/2025/9/28 2:04:36

什么是热更新?

        游戏上线后,出现游戏Bug或者需要更新小版本内容,游戏如果没有做热更新支持的话,就需要重重新打包游戏,然后上传平台进行审核,审核通过后玩家才可以下载新版本。审核期间需要时间,而且频繁的重新去下载游戏新包,玩家可能会反感,造成玩家流失。

游戏有热更新技术的支持下,不用重新打包上传平台审核,然后发布游戏,让玩家去下载新版本。将资源放在服务器上,通过下载更新游戏内容或者修复游戏Bug。

https://github.com/Tencent/xLua

接入XLua框架我们可以很容易的实现代码的热补丁(热更新)

热补丁

  • 侵入性小,老项目原有代码不做任何调整就可使用。
  • 运行时影响小,不打补丁基本和原来程序一样。
  • 出问题了可以用Lua来打补丁,这是才走lua代码逻辑

XLua热补丁使用方式

1.打开该特性

添加HOTFIX_ENABLE宏,(在Unity3D的File->Build Setting->Scripting Define Symbols下添加)。编辑器、各手机平台这个宏要分别设置!如果是自动化打包,要注意在代码里头用API设置的宏是不生效的,需要在编辑器设置。

建议平时开发业务代码不打开HOTFIX_ENABLE,只在build手机版本或者要在编译器下开发补丁时打开HOTFIX_ENABLE)

2、执行XLua/Generate Code菜单。 

3、注入。

构建手机包这个步骤会在构建时自动进行,编辑器下开发补丁需要手动执行"XLua/Hotfix Inject In Editor"菜单。打印“hotfix inject finish!”或者“had injected!”才算成功,否则会打印错误信息。

如果已经打印了“hotfix inject finish!”或者“had injected!”,执行xlua.hotfix仍然报类似“xlua.access, no field __Hitfix0_Update”的错误,要么是该类没配置到Hotfix列表,要么是注入成功后,又触发了编译,覆盖了注入结果。

约束

  • 不支持静态构造函数。
  • 目前只支持Assets下代码的热补丁,不支持引擎,c#系统库的热补丁。

API

xlua.hotfix(class, [method_name], fix)

  • 描述:注入lua补丁
  • class : C#类,两种表示方法,CS.Namespace.TypeName或者字符串方式"Namespace.TypeName",字符串格式和C#的Type.GetType要求一致,如果是内嵌类型(Nested Type)是非Public类型的话,只能用字符串方式表示"Namespace.TypeName+NestedTypeName";
  • method_name : 方法名,可选;
  • fix:如果传了method_name,fix将会是一个function,否则通过table提供一组函数。table的组织按key是method_name,value是function的方式。

util.hotfix_ex(class, method_name, fix)

  • 描述 : xlua.hotfix的增强版本,可以在fix函数里头执行原来的函数,缺点是fix的执行会略慢。
  • method_name : 方法名;
  • fix : 用来替换C#方法的lua function。

打补丁

客户端测试过程中,只要修改了热补丁的代码,都需要重新进行hotfix注入

xlua可以用lua函数来替换C#的构造函数,函数,属性。事件的替换。lua实现都是函数,比如属性对于一个getter函数和一个setter函数,事件对应一个add函数和一个remove函数。

函数

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;[Hotfix]
public class HotfixCalc : MonoBehaviour
{LuaEnv luaenv = new LuaEnv();void Start(){luaenv.DoString(@"
xlua.hotfix(CS.HotfixCalc, 'Add', function(self, a, b)return a + b
end)xlua.hotfix(CS.HotfixCalc, 'staticAdd', function( a, b)return a + b
end)");Debug.Log( "Add "+ Add(1, 1));Debug.Log("Add " + Add( Vector3.one, Vector3.one));Debug.Log("staticAdd " + HotfixCalc.staticAdd(1,1));}public int Add(int a, int b){return a - b;}public Vector3 Add(Vector3 a, Vector3 b){return a - b;}public static int staticAdd(int a, int b){return a - b;}
}

输出

  • 静态函数和成员函数的区别是,成员函数会加一个self,参数,这个self在Stateless方式下是C#对象本身(对应C#的this)
  • 普通参数对于lua的参数,ref参数对应lua的一个参数和一个返回值,out参数对于lua的一个返回值。

构造函数

  • 构造函数对应的method_name是‘.ctor’。
  • 和普通函数不一样是,构造函数的热补丁并不是替换,而是执行原有逻辑后调用lua
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
[Hotfix]
public class Hotfix构造函数 : MonoBehaviour
{LuaEnv luaenv = new LuaEnv();void Start(){HotfixTestClass1 oldTest = new HotfixTestClass1();luaenv.DoString(@"
xlua.hotfix(CS.HotfixTestClass1, '.ctor', function()print('新构造函数')
end)");Debug.Log("------------------");HotfixTestClass1 newTest = new HotfixTestClass1();}
}
[Hotfix]
public class HotfixTestClass1
{public HotfixTestClass1(){Debug.Log("构造函数");}
}

析构函数

method_name是"Finalize",传一个self参数。

和普通函数不一样的是,析构函数的热补丁并不是替换,而是开头调用lua函数后继续原有逻辑。

属性

using UnityEngine;
using XLua;[Hotfix]
public class HotfixGetSet : MonoBehaviour
{public int age;public int Age{get { return age; }set { age = value; }}LuaEnv luaenv = new LuaEnv();void Start(){//get_属性名// set_属性名 luaenv.DoString(@"xlua.hotfix(CS.HotfixGetSet, 'get_Age', function()return 10end)xlua.hotfix(CS.HotfixGetSet, 'set_Age', function(self, value) -- value: 传入的值print('set 属性')end)");Debug.Log(Age);Age = 10;}
}

[]操作符 

赋值对应set_Item,取值对应get_Item。第一个参数是self,赋值后面跟key,value,取值只有key参数,返回值是取出的值。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
[Hotfix]
public class HotfixIndex : MonoBehaviour
{public int[] test = { 77, 88, 99, 100 };public int this[int index]{get { return test[index]; }set { test[index] = value; }}void Start(){LuaEnv luaenv = new LuaEnv();luaenv.DoString(@"-- 索引器--set_Item  get_Itemxlua.hotfix(CS.HotfixIndex, 'set_Item', function(self, index, v)print( tostring(index) .. '  ' .. tostring(v))self.test[index] = vend)xlua.hotfix(CS.HotfixIndex, 'get_Item', function(self, index)return self.test[index]end)");this[1] = 20000;Debug.Log(this[1]);}
}

其它操作符

C#的操作符都有一套内部表示,比如+号的操作符函数名是op_Addition(其它操作符的内部表示可以去请参照相关资料),覆盖这函数就覆盖了C#的+号操作符。

事件

 比如对于事件“AEvent”,+=操作符是add_AEvent,-=对应的是remove_AEvent。这两个函数均是第一个参数是self,第二个参数是操作符后面跟的delegate。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using XLua;[Hotfix]
[LuaCallCSharp]
public class HotfixAction : MonoBehaviour
{event UnityAction myEvent;void Start(){LuaEnv luaenv = new LuaEnv();luaenv.DoString(@"xlua.hotfix(CS.HotfixAction, 'add_myEvent', function(self, del)
--会去去尝试使用lua使用C#事件的方法去添加--在事件加减的重定向lua函数中
--千万不要把传入的委托往事件里存
--否则会死循环
-- self:myEvent('+', del)  !!!!!!
--如果想重定向,肯定是希望把逻辑让lua处理
--所以一定是把传入的函数,存在lua的容器中print('add_myEvent')               end)xlua.hotfix(CS.HotfixAction, 'remove_myEvent', function(self, del) print('remove_myEvent')end)");myEvent += Test;}private void Test(){Debug.Log("xxxxxxxxxxxxxxx");}
}

泛化类型

其它规则一致,需要说明的是,每个泛化类型实例化后都是一个独立的类型,只能针对实例化后的类型分别打补丁。比如

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
[Hotfix]
public class Hotfix泛型 : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaEnv luaenv = new LuaEnv();luaenv.DoString(@"xlua.hotfix(CS.HotfixTest(CS.System.Int32), 'Test', function(self, str)print(' lua 中打的补丁 ' .. str )end)xlua.hotfix(CS.HotfixTest(CS.System.String), 'Test', function(self, str)print(' lua 中打的补丁 ' .. str )end)
");HotfixTest<int> hotfixTest = new HotfixTest<int>();hotfixTest.Test(1);HotfixTest<string> hotfixTest1 = new HotfixTest<string>();hotfixTest1.Test("string");HotfixTest<float> hotfixTest2 = new HotfixTest<float>();hotfixTest2.Test(1.5f);}
}
[Hotfix]
public class HotfixTest<T>
{public void Test(T str){Debug.Log("该泛型未修改" + str);}
}

Unity协程

通过util.cs_generator 可以用一个function模拟一个Ienumerator,在里头用coroutine.yield,就类似C#里头yield return 。比如下面的C#代码和对应的hotfix代码是等同效果

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;[Hotfix]
public class HotFixSubClass : MonoBehaviour
{void Awake(){LuaEnv luaenv = new LuaEnv();luaenv.DoString(@"-- xlua.hotfix(类, { 函数名 = 函数, 函数名 = 函数.....})local util = require 'xlua.util'   -- 要在lua中配合C#协程函数 必须使用它xlua.hotfix(CS.HotFixSubClass ,{Start = function(self)return util.cs_generator(function()while true docoroutine.yield(CS.UnityEngine.WaitForSeconds(3))print('Wait for 3 seconds')endend)end;})");}IEnumerator Start(){while (true){yield return new WaitForSeconds(3);Debug.Log("Wait for 3 seconds");}}
}

整个类

 如果要替换整个类,或者一个类中的多个方法,不需要一次次的调用xlua.hotfix去替换,可以整个一次完成。只要给一个table,按method_name = function组织即可

-- xlua.hotfix(类, { 函数名 = 函数, 函数名 = 函数.....})


xlua.hotfix(CS.StatefullTest, {['.ctor'] = function(csobj)return util.state(csobj, {evt = {}, start = 0, prop = 0})end;set_AProp = function(self, v)print('set_AProp', v)self.prop = vend;get_AProp = function(self)return self.propend;get_Item = function(self, k)print('get_Item', k)return 1024end;set_Item = function(self, k, v)print('set_Item', k, v)end;add_AEvent = function(self, cb)print('add_AEvent', cb)table.insert(self.evt, cb)end;remove_AEvent = function(self, cb)print('remove_AEvent', cb)for i, v in ipairs(self.evt) doif v == cb thentable.remove(self.evt, i)breakendendend;Start = function(self)print('Start')for _, cb in ipairs(self.evt) docb(self.start, 2)endself.start = self.start + 1end;StaticFunc = function(a, b, c)print(a, b, c)end;GenericTest = function(self, a)print(self, a)end;Finalize = function(self)print('Finalize', self)end
})

手游为什么要热更新,C#为什么不能热更新,LUA为什么可以 - 时空观察者9号 - 博客园

xLua/hotfix.md at master · Tencent/xLua · GitHub


http://chatgpt.dhexx.cn/article/DIPUq0Xw.shtml

相关文章

通过Xlua插件运行lua程序

using System.Collections; using System.Collections.Generic; using UnityEngine; using XLua; //引入xlua命名空间 public class Creat : MonoBehaviour {private LuaEnv luaenv;void Start(){luaenv new LuaEnv(); //LuaEnv可以理解为lua的运行环境luaenv.DoString("…

xlua基础知识

1.1 xLua简介 xLua是由腾讯维护的一个开源项目&#xff0c;xLua为Unity、 .Net、 Mono等C#环境增加Lua脚本编程的能力&#xff0c;借助xLua&#xff0c;这些Lua代码可以方便的和C#相互调用。自2016年初推广以来&#xff0c;已经应用于十多款腾讯自研游戏&#xff0c;因其良好性…

[Unity XLua]热更新XLua入门(一)-基础篇

无意中发现了一个巨牛巨牛的人工智能教程&#xff0c;忍不住分享一下给大家。教程不仅是零基础&#xff0c;通俗易懂&#xff0c;小白也能学&#xff0c;而且非常风趣幽默&#xff0c;还时不时有内涵段子&#xff0c;像看小说一样&#xff0c;哈哈&#xff5e;我正在学习中&…

Xlua

有一个项目做完快上线了,不是lua写的,能热更新的东西就特别少,如果遇到bug也很难在第一时间热修复,所以我就接入了Xlua这个插件点击打开链接 原本只是想热修复一下的,后来领导要求把逻辑系统的C#代码全部换成了Lua,至于为什么,因为他们习惯了每天都更新和修改的开发模式...所以…

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

一、环境配置 要实现热更新功能&#xff0c;我们首先需要开启热更新的宏。操作方法是在「File->Build Settings->Player Settings->Player->Other Settings->Scripting Define Symbols」选项中添加HOTFIX_ENABLE 开启后&#xff0c;在xLua的菜单中就出现了「…

Unity 热更新技术 |(六)xLua框架学习最新系列完整教程

🎬 博客主页:https://xiaoy.blog.csdn.net 🎥 本文由 呆呆敲代码的小Y 原创,首发于 CSDN🙉 🎄 学习专栏推荐:Unity系统学习专栏 🌲 游戏制作专栏推荐:游戏制作 🌲Unity实战100例专栏推荐:Unity 实战100例 教程 🏅 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬…

xLua(九)——实战

一&#xff1a;使用xLua的步骤 ——导入xLua插件 其实xLua本质就是一个Unity工程&#xff0c;把Asset中的文件导入到Unity工程中就搞定了&#xff08;导入之后编辑器菜单栏会扩展出一个XLua选项&#xff09; ——添加宏File——Build Settings——Player Settings——Other Se…

【XLua】简单使用

文章目录 前言1 配置1.1 配置宏1.2 XLua配置 2 lua和C#相互调用2.1 XLua.CSharpCallLua2.2 XLua.LuaCallCSharp 3 加载器 前言 XLua本质上是为Unity提供了使用lua的能力&#xff0c;实际多用于热更新。 热更新&#xff0c;因为要给代码打标签才能生效&#xff0c;所以需要预测…

xLua介绍

xLua地址&#xff1a;传送门 Xlua是啥&#xff1f; 2016年 腾讯推出的 一种 unity下 lua 编成的解决方案 基本概念介绍&#xff1a; 1.模块 模块就是一个 程序库&#xff0c;可以通过 require 加载&#xff0c;得到了一个表示 table的全局变量 这个table 就像一个命名空间&am…

Lua快速入门篇(XLua教程)(Yanlz+热更新+xLua+配置+热补丁+第三方库+API+二次开发+常见问题+示例参考)

《Lua热更新》 ##《Lua热更新》发布说明&#xff1a; “Lua热更新”开始了&#xff0c;立钻哥哥终于开始此部分的探索了。 作为游戏发布迭代的重要技术&#xff1a;Lua热更新在网络游戏迭代更新中非常重要&#xff0c;特别是对于AppStore这样的平台&#xff0c;我们只需要定…

XLua加载

XLua加载lua文件的方式 LuaEnv.DoString(print("hello world")); //直接执行lua的语句&#xff0c;在函数体内的语句格式要符合lua的语法 LuaEnv.DoString("require byfile")//使用require lua文件名也可在unity中加载lua 但是在unity中需要把文件放置在…

XLua系列讲解_Helloworld

一、XLua简介 XLua是Unity3D下Lua编程解决方案&#xff0c;自2016年初推广以来&#xff0c;已经应用于十多款腾讯自研游戏&#xff0c;因其良好性能、易用性、扩展性而广受好评。现在&#xff0c;腾讯已经将xLua开源到GitHub。 二、Xlua的优点 简洁易用&#xff0c;容易上手可…

Unity XLua Hotfix热更新配置笔记

Unity XLUA Hotfix热更新配置笔记 目录 Unity XLUA Hotfix热更新配置笔记 配置热更新步骤&#xff1a; 下载XLUA下载压缩包解压 复制xlua 和plugins到assets开启热补丁特性 先添加宏 HOTFIX_ENABLE;INJECT_WITHOUT_TOOL报“This delegate/interface must add to CSharpCallLu…

xLua热更新(一)xLua基本使用

一、什么是xLua xLua为Unity、 .Net、 Mono等C#环境增加Lua脚本编程的能力&#xff0c;借助xLua&#xff0c;这些Lua代码可以方便的和C#相互调用。 xLua是用来实现Lua代码与C#代码相互调用的插件。我们可以借助这个插件来实现热更新方案。 那么为什么要选择Lua实现热更新呢&am…

Bug-CTF-秋名山老司机(正则匹配)

题目: 没有啥思路&#xff0c;意外地刷新了一下页面&#xff0c;发现数值变化了 再刷新一次试试&#xff0c;出来一个提示&#xff0c;大概意思是需要提交结果&#xff0c;这里也不知道该怎么传参&#xff0c;也不晓得怎么写这个脚本&#xff0c;只能参考其他大佬的思路了 解题…

BUGKU------秋名山老司机

看到这个就直接上python吧&#xff0c;用eval计算子式 import requests from bs4 import BeautifulSoup r requests.session() s r.get(http://123.206.87.240:8002/qiumingshan/) soup BeautifulSoup(s.text, "html.parser") a soup.find(div) d {"valu…

bugku秋名山车神

不断的刷新&#xff0c;发现表达式一直在变换&#xff0c;这种必须写脚本&#xff0c;才能跟上速度。直接上代码 import re import requests srequests.session() rs.get("http://123.206.87.240:8002/qiumingshan/") searchObj re.search(r^<div>(.*)\?;<…

【BugkuCTF】Web--秋名山老司机

Description: http://123.206.87.240:8002/qiumingshan/ 是不是老司机试试就知道。 Solution: 打开网页 2秒解决问题真是稳稳的写脚本……但是不知道提交啥&#xff0c;刷新网页看看提示让用POST方式传递一个value变量&#xff0c;构造脚本 import requests import re url htt…

CTF-web-秋名山老司机

前言&#xff1a;小编也是现学现卖&#xff0c;方便自己记忆&#xff0c;写的不好的地方还请包涵&#xff0c;也欢迎各位大佬多多批评指正。 网址&#xff1a;秋名山老司机 1.打开网址&#xff0c;提示需要两秒内计算出数值&#xff0c;手工几乎不可能实现。 2.思路:利用pyt…

秋名山车神

解题思路&#xff1a;看到这种题要在两秒类算出&#xff0c;人工肯定不可能&#xff0c;直接上脚本&#xff0c;由于我不会写python 脚本&#xff0c;直接在网上找了一篇大佬的脚本 import requests #安装requests库 import re url http://114.67.246.176:16847 #改为自己题…