CDN + xLua
CDN + xLua
xLua 在功能、性能、易用性都有不少突破,这几方面分别最具代表性的是:
- 可以运行时把 C# 实现(方法,操作符,属性,事件等等)替换成 lua 实现。
- 出色的 GC 优化,自定义 struct,枚举在 Lua 和 C# 间传递无 C# gc alloc。
- 编辑器下无需生成代码,开发更轻量。
UOS CDN + xLua 使用示例
核心思路是通过 UOS CDN 的 Release / Badge 功能,手动控制 Lua 脚本的版本更新。
样例为单个 Lua 脚本文件的更新流程,样例中每次均会下载远程的 Lua 脚本文件,可自行判断远程文件是否更新再下载。
1. 创建和上传资源
首先创建一个空的 Unity Project,在 Unity 项目的 Assets 目录新建 LuaScripts 目录,创建用于热更新的脚本文件(内容可参考下方 first.lua),上传到 UOS CDN 的 Bucket:
2. 创建新的发布版本
创建新的发布版本 "Release #1",创建并分配 Badge "v1.0.0",在 「RELEASES」 页面,复制以 Badge 为前缀的 URL,记为 UOS CDN URL
3. 配置
将UOS CDN URL填入样例代码(内容可参考 XLuaDemoController.cs),并根据 xLua的教程,配置好热更新环境。执行客户端,即可测试修改前的代码逻辑:
4. 更新流程
修改first.lua文件内容,重新上传,创建新的发布版本 "Release #2",将 Badge "v1.0.0" 指向 "Release #2"。
此时运行客户端,可以看见会执行修改后的代码逻辑(由于缓存,这里可能会有约一分钟的延迟才生效)。
至此,您已经完成了 UOS 与 xLua 的搭配操作,期待您在后续的探索中有更多的发现。
示例代码
1. first.lua
xlua.hotfix(CS.XLuaDemo.HotfixCalc, 'Add', function(self, a, b)
return a + b
end)2. XLuaDemoController.cs
namespace XLuaDemo
{
[Hotfix]
public class HotfixCalc
{
public int Add(int a, int b)
{
return a - b;
}
public Vector3 Add(Vector3 a, Vector3 b)
{
return a - b;
}
}
public class XLuaDemoController : MonoBehaviour
{
string uos_cdn_prefix = {UOS CDN URL};
private LuaEnv luaenv;
void Start()
{
luaenv = new LuaEnv();
StartCoroutine(HotfixLuaScript("first.lua"));
}
IEnumerator HotfixLuaScript(string name)
{
string filename = string.Format("{0}.lua", name);
UnityWebRequest req = UnityWebRequest.Get(uos_cdn_prefix + filename);
yield return req.SendWebRequest();
if (req.isDone)
{
if (req.responseCode == 200)
{
var data = req.downloadHandler.data;
string savePath = string.Format("{0}/{1}", Application.persistentDataPath, filename);
System.IO.File.WriteAllBytes(savePath, data);
HotfixCalc calc = new HotfixCalc();
Debug.Log("Before Fix: 2 + 1 = " + calc.Add(2, 1));
Debug.Log("Before Fix: Vector3(2, 3, 4) + Vector3(1, 2, 3) = " + calc.Add(new Vector3(2, 3, 4), new Vector3(1, 2, 3)));
luaenv.AddLoader(CustomLoader);
luaenv.DoString(string.Format("require '{0}'", name));
Debug.Log("After Fix: 2 + 1 = " + calc.Add(2, 1));
Debug.Log("After Fix: Vector3(2, 3, 4) + Vector3(1, 2, 3) = " + calc.Add(new Vector3(2, 3, 4), new Vector3(1, 2, 3)));
}
}
else
{
Debug.Log("Not Done");
}
}
private byte[] CustomLoader(ref string luaFileName)
{
string path = string.Format("{0}/{1}.lua", Application.persistentDataPath, luaFileName);
if (!File.Exists(path))
{
path = string.Format("{0}/LuaScripts/{1}.lua", Application.dataPath, luaFileName);
if (!File.Exists(path))
{
return new byte[] { };
}
}
byte[] data = Encoding.UTF8.GetBytes(File.ReadAllText(path));
return data;
}
// 上述流程每次均会下载lua文件
// 如果需要先通过hash值来判断lua文件是否更新,可以先使用Head请求来获取当前远程资源的hash值
IEnumerator HeadRequest()
{
UnityWebRequest req = UnityWebRequest.Head(uos_cdn_prefix + "first.lua");
yield return req.SendWebRequest();
if (req.isDone)
{
Debug.Log(req.GetResponseHeader("Upload-Hash"));
}
else
{
Debug.Log("Not Done");
}
}
}
}