原文 轉載請注明保留原文鏈接:http://www.jianshu.com/p/dc4de5612d9e
作者:Jumbo
在Unity3D項目中,邏輯代碼熱更新這一塊,現在有很多實現解決方案,基本都是借助Lua來實現的,在這眾多之中,最后還是選擇xLua,最早了解xLua是在騰訊的手游項目中,騰訊Apollo通用組件中,只是涉及的項目中,並沒有xLua的源碼及文檔相關的說明。可能當時xLua還在改進當中。直到2017年1月3日,騰訊Github開源項目中,出現xLua的身影。xLua優勢:1、集成快 (幾乎不用改變原本項目的代碼) 2、專職人員負責維護(企鵝還是有這個實力·~~·),說再多也不如自己切身體驗一番。下面就幫大家,快速入門下。
一、xLua源碼: https://github.com/Tencent/xLua/ 沒有帳號或者下載不了的同學,可以郵箱留言,發一份給大伙;
二、獲取到源碼后,首先認真閱讀README.md內容,可以更好的幫大家了解xLua,是否項目中遇到的問題,可以通過xLua來幫忙處理?;
三、根據提供的示例:
01_Helloworld: 快速入門的例子。
02_U3DScripting: 展示怎么用lua來寫MonoBehaviour。
03_UIEvent: 展示怎么用lua來寫UI邏輯。
04_LuaObjectOrented: 展示lua面向對象和C#的配合。
05_NoGc: 展示怎么去避免值類型的GC。
06_Coroutine: 展示lua協程怎么和Unity協程相配合。
07_AsyncTest: 展示怎么用lua協程來把異步邏輯同步化。
08_Hotfix: 熱補丁的示例(需要開啟熱補丁特性,如何開啟請看指南)。
配合文檔:
XLua教程.doc:教程,其配套代碼這里。
XLua的配置.doc:介紹如何配置xLua。
XLua增加刪除第三方lua庫.doc:如何增刪第三方lua擴展庫。
XLua API.doc:API文檔。
可以更好的了解xLua具備那些特性,如何便捷使用。
四、最重要的功能:熱補丁
xLua支持熱補丁,這意味着你可以:
1、開發只用C#;
2、運行也是C#,性能可以秒殺lua;
3、出問題了才用Lua來改掉C#出問題的部位,下次整體更新時換回正確的C#;能做到用戶不重啟程序fix bug;
如果你僅僅希望用熱更新來fix bug,這是強烈建議的做法。這里是使用指南。
這個文檔說明一定要仔細閱讀https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/hotfix.md
很多剛開始接觸的同學,因為沒有認真看文檔說明,容易出現一些問題,這邊列舉下:
注意:a、HOTFIX_ENABLE宏是否在Unity3D的File->Build Setting->Scripting Define Symbols下添加
b、Mono.Cecil.是否拷貝:OSX命令行 cp /Applications/Unity/Unity.app/Contents/Managed/Mono.Cecil. Project/Assets/XLua/Src/Editor/
Win命令行 copy UnityPath\Editor\Data\Managed\Mono.Cecil.* Project\Assets\XLua\Src\Editor\
c、菜單欄中,執行xLua/Generat Code, 會在新建Gen文件夾,下面生成一些wrap文件

具體生成那些類型對應的wrap文件,需要自己配置,詳見: https://github.com/Tencent/xLua/blob/master/Assets/XLua/Examples/ExampleGenConfig.cs
在項目中集成,最好自己寫一份配置,替換ExampleGenConfig,比如取名CustomGenConfig.cs,加入了[Hotfix]標簽
//需要熱更新的類型 [Hotfix] public static List<Type> by_field = new List<Type>() { };
d、要等打印了hotfix inject finish!后才運行例子,否則會類似xlua.access, no field __Hitfix0_Update的錯誤
五、整合xLua進項目
1、

2、

3、

先貼上代碼(myHotfix.lua 編寫fixbug邏輯):
using UnityEngine; using System.Collections; using XLua; /// <summary> /// 先判斷更新熱補丁文件,然后再執行Fixing /// </summary> public class xLuaInstance : MonoSingleton<xLuaInstance>{ LuaEnv luaenv; const string fixFile = "myHotfix.lua"; public string FixFilePath { get { return FileUtils.GetFullPath(null, fixFile, FileUtils.StorageType.Persistent); } } /// <summary> /// 熱補丁修復中。。。 /// </summary> public void Fixing() { byte[] bytes = System.IO.File.ReadAllBytes(FixFilePath); if (bytes != null) { luaenv = new LuaEnv(); luaenv.AddLoader((ref string filename) => { if (filename == "myHotfix") { filename = FixFilePath; return bytes; } return null; }); luaenv.DoString(@"require 'myHotfix'"); } } void Update() { if (luaenv != null) luaenv.Tick(); } void OnDestroy() { if (luaenv != null) luaenv.Dispose(); } }
4、大致流程
i、游戲一開始啟動時,檢查遠程服務器上是否有新的myHotfix.lua文件(例如:md5比對,自己加解密),有的話,下載下來,放在指定目錄,沒有的話,讀取本地已有的myHotfix.lua文件,若文件不存在,則說明不需要熱修復,一般這種情況是在項目剛發布的早起,沒有進行打補丁;
ii、項目發布版本前,需要在CustomGenConfig.cs中 加入需要添加[Hotfix]標簽的類型,想要更靈活使用的話,可以自己寫個配置表,讀取配置中的類型,自動添加,***只有加入[Hotfix]標簽的類型,才可以調用xlua.hotfix()

,不然會報錯,切記!!!
iii、如果你的項目是自動化發布版本,需要在調用打包之前,生成wrap, 調用這個CSObjectWrapEditor.Generator.GenAll();
MonoSingleton.cs
//非線程安全 using UnityEngine; /// <summary> /// 基類繼承樹中有MonoBehavrour類的單件實現,這種單件實現有利於減少對場景樹的查詢操作 /// </summary> /// <typeparam name="T"></typeparam> public class MonoSingleton<T> : MonoBehaviour where T : Component { // 單件子類實例 private static T _instance; // 在單件中,每個物件的destroyed標志設計上應該分割在不同的存儲個空間中,因此,忽略R#的這個提示 // ReSharper disable once StaticFieldInGenericType private static bool _destroyed; /// <summary> /// 獲得單件實例,查詢場景中是否有該種類型,如果有存儲靜態變量,如果沒有,構建一個帶有這個component的gameobject /// 這種單件實例的GameObject直接掛接在bootroot節點下,在場景中的生命周期和游戲生命周期相同,創建這個單件實例的模塊 /// 必須通過DestroyInstance自行管理單件的生命周期 /// </summary> /// <returns>返回單件實例</returns> public static T Instance { get{ if (_instance == null && !_destroyed) { _instance = (T) FindObjectOfType(typeof (T)); if (_instance == null) { GameObject go = new GameObject(typeof (T).Name); _instance = go.AddComponent<T>(); DontDestroyOnLoad(_instance); var singletonRootGo = GameObject.Find("MonoSingletonRoot"); if (singletonRootGo != null) { go.transform.parent = singletonRootGo.transform; } } } return _instance; } } /// <summary> /// 刪除單件實例,這種繼承關系的單件生命周期應該由模塊顯示管理 /// </summary> public static void DestroyInstance() { if (_instance != null) Destroy(_instance.gameObject); _destroyed = true; _instance = null; } /// <summary> /// Awake消息,確保單件實例的唯一性 /// </summary> protected virtual void Awake() { if (_instance != null && _instance.gameObject != gameObject) Destroy(gameObject); else if(_instance == null) _instance = GetComponent<T>(); DontDestroyOnLoad(_instance); } /// <summary> /// OnDestroy消息,確保單件的靜態實例會隨着GameObject銷毀 /// </summary> protected virtual void OnDestroy() { if (_instance != null && _instance.gameObject == gameObject) { _instance = null; } } /// <summary> /// Have Instance /// </summary> /// <returns></returns> public static bool HaveInstance() { return _instance != null; } }
如何調試Lua腳步,接下來,我會寫一篇關於ZeroBrane這個工具。
在此感謝xLua作者:車雄生 chexiongsheng!!!
期待大家的支持!!!
祝大家在17年萬事如意,身體健康!!!
作者:JumboWu
鏈接:https://www.jianshu.com/p/dc4de5612d9e
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。