目录
前言
在Unity游戏开发中,热补丁(Hotfix)技术扮演着至关重要的角色。随着游戏版本的迭代和更新,开发者们常常会遇到一些在发布后才发现的bug或需要紧急修复的问题。传统的修复方式往往需要重新发布游戏版本,这不仅耗时长,还可能对用户体验造成不良影响。而热补丁技术的出现,为这些问题提供了一种快速、灵活的解决方案。
热补丁,通俗理解就是将C#中的方法替换成Lua等脚本语言中的函数来执行。在Unity中,通过XLua等插件,开发者可以轻松地实现这一功能。XLua不仅支持函数替换,还支持构造函数、析构函数、属性、事件以及泛型类的替换,为开发者提供了极大的便利。
本文将深入探讨Unity Hotfix技术在替换类中的函数方面的应用。
使用Hotfix
C#
using UnityEngine;
public class HotfixMain : MonoBehaviour
{
void Start()
{
LuaMgr.GetInstance().Init();
LuaMgr.GetInstance().DoLuaFile("Main");
Debug.Log(Add1(110,4));
Add2("长风破浪会有时,直挂云帆济沧海。");
}
void Update()
{
}
public int Add1(int a,int b)
{
return 0;
}
public static void Add2(string str)
{
Debug.Log("烫烫烫烫烫烫烫烫烫烫烫烫烫烫");
}
}
Lua
Mian.lua
print('Lua脚本准备就绪')
--Unity中写lua执行
--xlua帮我们处理
--只要是执行1ua脚本 都会自动的进入我们的重定向函数中找文件
require("test")
test.lua
--Lua当中 热补丁代码固定写法
--xlua.hotfix(类,"函数名",lua函数)
xlua.hotfix(CS.HotfixMain,"Add1",function (self,a,b)
return a+b;
end)
xlua.hotfix(CS.HotfixMain,"Add2",function (a)
print(a)
end)
使用hotfix,必须做4个非常重要的操作
1.加特性
using UnityEngine;
using XLua;
[Hotfix]
public class HotfixMain : MonoBehaviour
{
void Start()
{
LuaMgr.GetInstance().Init();
LuaMgr.GetInstance().DoLuaFile("Main");
Debug.Log(Add1(110,4));
Add2("长风破浪会有时,直挂云帆济沧海。");
}
void Update()
{
}
public int Add1(int a,int b)
{
return 0;
}
public static void Add2(string str)
{
Debug.Log("烫烫烫烫烫烫烫烫烫烫烫烫烫烫");
}
}
2.加宏
Build Profiles/Project Settings/Scripting Define Symbol中添加HOTFIX_ENABLE

3.生成代码
XLua/Generate Code

4.hotfix注入
需要有和Assets同级别的Tools文件,XLua文件中复制过来
XLua/Hotfix Inject In Editor
提示成功
只要修改了热补丁类的代码,我们就要重新注入hotfix
实现效果
最后执行的是经过Lua热更新之后的代码逻辑
多函数替换
Lua
--Lua当中 热补丁代码固定写法
--xlua.hotfix(类,"函数名",lua函数)
xlua.hotfix(CS.HotfixMain,{
Update = function (self)--使用成员函数需要传入自己为第一个参数
print(os.time())--lua中的时间
end,
Add1 = function (self,a,b)
return a+b;
end,
Add2 = function (a)--在C#中为静态函数,不需要传自己为第一个参数
print(a)
end
})
替换构造和析构函数
C#
[Hotfix]
public class HotfixTest
{
public HotfixTest()
{
Debug.Log("构造函数");
}
public void Speak(string str)
{
Debug.Log(str);
}
~HotfixTest()
{
}
}
Lua
与其他替换函数逻辑不同,Lua中构造和析构是先执行原逻辑,在执行Lua逻辑
xlua.hotfix(CS.HotfixTest,{
--构造函数 热补丁 固定写法
[".ctor"] = function ()
print("Lua热补丁构造函数")
end,
Speak = function (self,a)
print("这是计划的一部分"..a)
end,
--析构函数固定写法
Finalize = function ()
end
})
协程函数替换
整体规则和普通函数替换是一样的
区别在函数内部 是需要返回一个 xlua.util.cs_generator(函数)的返回值
C#
using System.Collections;
using UnityEngine;
using XLua;
[Hotfix]
public class HotfixMain : MonoBehaviour
{
HotfixTest hotTest;
void Start()
{
LuaMgr.GetInstance().Init();
LuaMgr.GetInstance().DoLuaFile("Main");
StartCoroutine(TestCoroutine());
}
void Update()
{
}
IEnumerator TestCoroutine()
{
while(true)
{
yield return new WaitForSeconds(1);
Debug.Log("C#协程打印一次");
}
}
public int Add1(int a,int b)
{
return 0;
}
public static void Add2(string str)
{
Debug.Log("烫烫烫烫烫烫烫烫烫烫烫烫烫烫");
}
}
util.lua位置
将文件复制一份改名xlua.util.lua到与自己写的lua文件同一级别的文件夹中
编写Lua脚本
--要在lua中配合C#协程函数,那么必须要使用它
util = require("xlua.util")
xlua.hotfix(CS.HotfixMain,{
TestCoroutine =function (self)
return util.cs_generator(function ()
while true do
coroutine.yield(CS.UnityEngine.WaitForSeconds(1))
print("Lua打补丁后的协程函数")
end
end)
end
})
索引器替换
C#
using System;
using System.Collections;
using UnityEngine;
using XLua;
[Hotfix]
public class HotfixMain : MonoBehaviour
{
HotfixTest hotTest;
public int[] array =new int[] {1,2,3};
//属性
public int Age
{
get
{
return 0;
}
set
{
Debug.Log(value);
}
}
public int this[int index]
{
get
{
if(index>=array.Length || index < 0)
{
Debug.Log("索引不正确");
return 0;
}
return array[index];
}
set
{
array[index] =value;
}
}
void Start()
{
LuaMgr.GetInstance().Init();
LuaMgr.GetInstance().DoLuaFile("Main");
this[99] = 100;
Debug.Log(this[999]);
}
void Update()
{
}
}
Lua
xlua.hotfix(CS.HotfixMain,{
--如果是属性进行热补丁重定向
--set 属性名 是设置属性 的方法
--get_属性名 是得到属性 的方法
set_Age=function(self, v)
print("Lua重定向的属性"..v)
end,
get_Age = function(self)
return 10;
end,
--索引器固定写法
--set_Item 设置索引器
--get_Item 获取索引器
set_Item = function (self,index,v)
print("Lua重定向索引器,索引"..index.."值"..v)
end,
get_Item = function (self,index)
print("Lua重定向")
return 12
end
})
事件替换
C#
using UnityEngine;
using UnityEngine.Events;
using XLua;
[Hotfix]
public class HotfixMain : MonoBehaviour
{
event UnityAction myEvent;
void Start()
{
LuaMgr.GetInstance().Init();
LuaMgr.GetInstance().DoLuaFile("Main");
myEvent +=TestTest;
myEvent -=TestTest;
}
private void TestTest()
{
}
}
Lua
xlua.hotfix(CS.HotfixMain,{
--add_事件名 代表事件加操作
--remove_事件名 减操作
add_myEvent = function (self,del)
print(del)
print("添加事件函数")
--会去尝试使用1ua使用C#事件的方法去添加
--在事件加减的重定向1ua函数中
--千万不要把传入的委托往事件里存
--否则会死循环
--会把传入的 函数 存在1ua中
--self:myEvent("+",de1)
end,
remove_myEvent = function (self,del)
print(del)
print("移除事件函数")
end
})
注意:
如果要重定向事件加减到Lua中来
一定不要使用C#的事件加减了
self:myEvent("+/-",传入函数)
因为会造成死循环
如果想重定向,肯定是希望把逻辑让lua处理
所以一定是把传入的函数,存到lua里的容器中
泛型替换
替换规则和之前一样
区别是:类名后括号加泛型的类型,因为泛型时可变的,所以我们要指定某一个类型来进行替换
想替换几个类型,就写几个补丁
C#
[Hotfix]
public class HotfixTest2<T>
{
public void Test(T str)
{
Debug.Log(str);
}
}
using UnityEngine;
using XLua;
[Hotfix]
public class HotfixMain : MonoBehaviour
{
void Start()
{
LuaMgr.GetInstance().Init();
LuaMgr.GetInstance().DoLuaFile("Main");
HotfixTest2<string> t1 =new HotfixTest2<string>();
t1.Test("123");
HotfixTest2<int> t2 =new HotfixTest2<int>();
t2.Test(456);
}
}
Lua
--泛型类 T是可以变化 那lua中应该如何替换呢 ?
--1ua中的替换 要一个类型一个类型的来
xlua.hotfix(CS.HotfixTest2(CS.System.String),{
Test = function (self,str)
print("lua中打的补丁"..str)
end
})
xlua.hotfix(CS.HotfixTest2(CS.System.int32),{
Test = function (self,str)
print("lua中打的补丁"..str)
end
})