了解熱更新之前,首先得知道為啥要用熱更新?
為了省去用戶自行更新客戶端的步驟,從而改善用戶體驗,
Unity熱更新方案
- 一、幾種常用熱更新解決方案的區別
- 二、Lua語法講解及編輯器下載
- 三、XLua熱更新實戰
- 1、xLua特性總結
- 2、xlua支持下載,以及Unity 中搭建 xlua 環境
- 3、C#與Lua互動原理
- 4、Xlua與C#的互相呼叫實戰
- 5、xLua熱更新框架使用
- 6、熱更新大致流程
一、幾種常用熱更新解決方案的區別
以下列舉的這些解決方案都是C#環境下的Lua代碼解釋器(Lua虛擬機),
1、uLua
Lua插件原生版本,不會產生靜態代碼,反射機制,效率低下,速度慢,gcalloc頻繁,已停止更新維護
2、xLua
視頻 xLua基本原理原則 https://www.zhihu.com/zvideo/1380896883473170433

3、ToLua
tolua(基于tolua開發了luaframework)
ToLua LuaFramework 使用實戰[1]-代碼熱更新
ToLua LuaFramework 使用實戰[2]-資源熱更新
4、slua
代碼質量好,性能比tolua低
5、其他
C#light、LSharp同一個作者(商用比較少)
參考此博客:https://blog.csdn.net/guofeng526/article/details/52662994
二、Lua語法講解及編輯器下載
lua語法是通用的,可以根據菜鳥課程學,
https://www.runoob.com/lua/lua-basic-syntax.html

方便學習和直接運行Lua代碼,先安裝Lua編輯器:Luaforwindows
https://github.com/rjpcomputing/luaforwindows/releases
第一個是命令列形式,
第二個是編輯器形式,推薦用第二個:


三、XLua熱更新實戰
1、xLua特性總結
xLua為Unity、 .Net、 Mono等C#環境增加Lua腳本編程的能力,借助xLua,這些Lua代碼可以方便的和C#相互呼叫,
目前Unity下的Lua熱更新方案大多都是要求要熱更新的部分一開始就要用Lua語言實作,不足之處在于:
1、接入成本高,有的專案已經用C#寫完了,這時要接入需要把需要熱更的地方用Lua重新實作;
2、即使一開始就接入了,也存在同時用兩種語言開發難度較大的問題;
3、Lua性能不如C#;
xLua熱補丁技術支持在運行時把一個C#實作(函式,運算子,屬性,事件,或者整個類)替換成Lua實作,意味著你可以:
1、平時用C#開發;
2、運行也是C#,性能秒殺Lua;
3、有bug的地方下發個Lua腳本fix了,下次整體更新時可以把Lua的實作換回正確的C#實作,更新時甚至可以做到不重啟游戲;
這個新特性iOS,Android,Window,Mac都測驗通過了,目前在做一些易用性優化,
2、xlua支持下載,以及Unity 中搭建 xlua 環境
xlua支持下載:
https://codeload.github.com/Tencent/xLua/zip/refs/heads/master
或
https://github.com/Tencent/xLua
參考此博客:https://blog.csdn.net/u014361280/article/details/104826274

3、C#與Lua互動原理
可參考此博客:https://zhuanlan.zhihu.com/p/38322991
C#呼叫Lua:C#先呼叫Lua的dll檔案(C語言寫的庫),dll檔案執行Lua代碼
2、Lua呼叫C#:Wrap方式:非反射機制,需要為源檔案生成相應的wrap檔案,當啟動Lua虛擬機時,Wrap檔案將會被自動注冊到Lua虛擬機中,之后,Lua檔案
將能夠識別和呼叫C#源檔案,
總結:Lua呼叫Wrap檔案, Wrap檔案呼叫C#源檔案
4、Xlua與C#的互相呼叫實戰
Xlua與C#的互相呼叫:
專案結構如下圖:

三個lua腳本和C#腳本如下:
下面展示一些 LuaTest.lua,
num = 10
name = "LuaTest"
boy = true
person = {name = "xiaoming",age = 20}
function add(a,b)
a = a+b
print(a)
end
--在Lua中new C#物件(創建游戲物體)
CS.UnityEngine.GameObject()
--Lua訪問C#靜態屬性和方法
print(CS.UnityEngine.Time.deltaTime)
CS.UnityEngine.Time.timeScale = 0.5
local gameObject = CS.UnityEngine.GameObject
local cube = gameObject.Find("Cube")
cube.name = "cubeLua"
local Collider = cube.GetComponent(cube,"BoxCollider")
gameObject.Destroy(Collider)
print("-----LuaTest-----")
下面展示一些 HellowWorld.lua,
num = 10
name = "LuaTest"
boy = true
print("HellowWorld")
下面展示一些 Lua_StreamingAssets.lua,
print('Load Lua by StreamingAssets')
下面展示一些 LuaStudy,
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using XLua;
public class LuaStudy : MonoBehaviour
{
private LuaEnv luaEnv;
private void Start()
{
//創建lua運行環境
luaEnv = new LuaEnv();
LuaLoaderFun();
VisitLua_Table();
VisitLua_Function();
}
private void OnDestroy()
{
//釋放lua環境
luaEnv.Dispose();
}
/// <summary>
/// 加載及呼叫lua腳本
/// </summary>
void LuaLoaderFun()
{
//執行lua的輸出陳述句
luaEnv.DoString("print('Hellow World 1')");
//在lua中呼叫C#方法
luaEnv.DoString("CS.UnityEngine.Debug.Log('Hellow World 2')");
//加載運行Resources檔案中的lua腳本
TextAsset ta = Resources.Load<TextAsset>("HellowWorld.lua");
luaEnv.DoString(ta.text);
//加載運行helloworld.lua.txt 默認從Resources檔案中進行加載
luaEnv.DoString("require 'HellowWorld'");
// 添加自定義的Loader方法
//添加了一個自定義的Loader回傳null并且DoString里面添加的是一個不存在的lua檔案,它會回傳錯誤,
//luaEnv.AddLoader(MyLoader_1);
//luaEnv.DoString("require 'xxx'");
// 添加自定義的Loader方法
//添加了一個自定義的Loader回傳lua陳述句的二進制并且DoString里面添加的是一個不存在的lua檔案,它會執行自定義的Loader的輸出,
//luaEnv.AddLoader(MyLoader_2);
//luaEnv.DoString("require 'xxx'");
//通過自定義Loader加載指定目錄的Lua腳本
luaEnv.AddLoader(MyLoader_3);
luaEnv.DoString("require 'Lua_StreamingAssets'");
}
/// <summary>
/// 訪問獲取lua屬性和表
/// </summary>
void VisitLua_Table() {
//呼叫lua腳本才能訪問屬性
luaEnv.DoString("require 'LuaTest'");
//獲取lua腳本中的全域變數
int num = luaEnv.Global.Get<int>("num");//獲取lua里面的全域變數num
string name = luaEnv.Global.Get<string>("name");//獲取lua里面的全域變數name
Debug.Log("num:" + num + " name:" + name);
//訪問lua中的table(映射到class)
Person personTemp = luaEnv.Global.Get<Person>("person");
Debug.Log(personTemp.name + " " + personTemp.age);
//這種方式的訪問,修改age的值不會影響到lua里面的表的屬性
personTemp.name = "wang";
personTemp.age = 50;
//修改后試一下
Person personTemp2 = luaEnv.Global.Get<Person>("person");
Debug.Log(personTemp2.name + " " + personTemp2.age);
//訪問lua中的table(映射到interface)
//映射到interface修改p中的屬性,lua中的原table也會發生變化
IPerson personTemp3 = luaEnv.Global.Get<IPerson>("person");
Debug.Log(personTemp2.name + " " + personTemp2.age);
//通過LuaTable訪問table
List<object> list = luaEnv.Global.Get<List<object>>("person");
foreach (object o in list)
{
print(o);
}
//通過LuaTable類 比較慢
LuaTable luaTable = luaEnv.Global.Get<LuaTable>("person");
print(luaTable.Get<string>("name"));
print(luaTable.Get<int>("age"));
}
/// <summary>
/// 訪問lua中的全域方法
/// </summary>
void VisitLua_Function()
{
//呼叫lua腳本才能訪問屬性
luaEnv.DoString("require 'LuaTest'");
//使用委托來獲取Lua中的全域函式
Add add = luaEnv.Global.Get<Add>("add");
add(2, 4);
//通過LuaFunction訪問Lua中的全域函式
LuaFunction luaFunction = luaEnv.Global.Get<LuaFunction>("add");
luaFunction.Call(2, 4);
}
private byte[] MyLoader_1(ref string filePath)
{
print(filePath);
return null;
}
private byte[] MyLoader_2(ref string filePath) {
string s = "print(123)";
return System.Text.Encoding.UTF8.GetBytes(s);
}
private byte[] MyLoader_3(ref string filePath) {
string path = Application.streamingAssetsPath + "/" + filePath + ".lua.txt";
return System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(path));
}
class Person
{
public string name;
public int age;
}
//打標簽
[CSharpCallLua]
public interface IPerson
{
string name { get; set; }
int age { get; set; }
}
//打標簽
[CSharpCallLua]
delegate void Add(int a, int b);
}
5、xLua熱更新框架使用
下載的xLua-master的 Assets\XLua\Doc 路徑下有熱更新相關教程檔案

這個檔案說明一定要仔細閱讀https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/hotfix.md
使用方式
1、添加HOTFIX_ENABLE宏打開該特性(在Unity3D的File->Build Setting->Scripting Define Symbols下添加),編輯器、各手機平臺這個宏要分別設定!如果是自動化打包,要注意在代碼里頭用API設定的宏是不生效的,需要在編輯器設定,
(建議平時開發業務代碼不打開HOTFIX_ENABLE,只在build手機版本或者要在編譯器下開發補丁時打開HOTFIX_ENABLE)
2、打開unity安裝路徑D:\Unity\2020.3.0f1c1\Editor\Data\MonoBleedingEdge\lib\mono\unity\Mono.Cecil.dll,把Mono.Cecil.dll拷貝到專案LuaTest\Assets\XLua\Editor路徑下

或者復制Tools檔案到專案中


3、選單欄中,執行xLua/Generat Code,會在新建Gen檔案夾,下面生成一些wrap檔案


4、把ExampleConfig腳本拖到XLua檔案夾下,自行修改配置資訊


5、構建手機包這個步驟會在構建時自動進行,編輯器下開發補丁需要手動執行"XLua/Hotfix Inject In Editor"選單,注入成功會列印“hotfix inject finish!”或者“had injected!”,
6、熱更新大致流程
1、游戲一開始啟動時,檢查遠程服務器上是否有新的myHotfix.lua檔案(例如:md5比對,自己加解密),有的話,下載下來,放在指定目錄,沒有的話,讀取本地已有的myHotfix.lua檔案,若檔案不存在,則說明不需要熱修復,一般這種情況是在專案剛發布的早期,沒有進行打補丁;
2、專案發布版本前,需要在CustomGenConfig.cs中 加入需要添加[Hotfix]標簽的型別,想要更靈活使用的話,可以自己寫個配置表,讀取配置中的型別,自動添加,***只有加入[Hotfix]標簽的型別,才可以呼叫xlua.hotfix()
,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/339282.html
標籤:其他
