日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Unity 游戏用XLua的HotFix实现热更原理揭秘

發布時間:2023/12/4 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Unity 游戏用XLua的HotFix实现热更原理揭秘 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文通過對XLua的HoxFix使用原理的研究揭示出來這樣的一套方法。這個方法的第一步:通過對C#的類與函數設置Hotfix標簽。來標識需要支持熱更的類和函數。第二步:生成函數連接器來連接LUA腳本與C#函數。第三步:在C#腳本編譯結束后,使用Mono提供的一套C#的API函數,對已經編譯過的.Net體系生成的DLL文件進行修改。第四步,通過LUA腳本修改C#帶有標簽的類中靜態變量,把代碼的執行路徑修改到LUA腳本中。通過這套方案可以實現對已經標識的C#代碼進行動態更新。


基礎準備

知識準備

CIL: 通用中間語言(Common Intermediate Language,簡稱CIL), 是一種屬于通用語言架構和 .NET 框架的低階(lowest-level)的人類可讀的編程語言。目標為 .NET 框架的語言被編譯成CIL(基于.NET框架下的偽匯編語言,原:MSIL),這是一組可以有效地轉換為本機代碼且獨立于 CPU 的指令。CIL類似一個面向對象的匯編語言,并且它是完全基于堆棧的。它運行在CLR上(類似于JVM),其主要支持的語言有C#、VisualBasic .NET、C++/CLI以及 J#(集成這些語言向CIL的編譯功能)。

在編譯.NET編程語言時,源代碼被翻譯成CIL碼,而不是基于特定平臺或處理器的目標代碼。CIL是一種獨立于具體CPU和平臺的指令集,它可以在任何支持.NET framework的環境下運行。CIL碼在運行時被檢查并提供比二進制代碼更好的安全性和可靠性。在Unity3D中,是用過Mono虛擬機來實現運行這些中間語言指令的。

之前寫一篇介紹過一篇使用微軟的API函數,利用中間語言生成或注入.NET支持下的DLL。這里就不在贅述,需要了解的請參考《使用MSIL采用Emit方式實現C#的代碼生成與注入

?

IL2CPP: 直接理解把IL中間語言轉換成CPP文件根據官方的實驗數據,換成IL2CPP以后,程序的運行效率有了1.5-2.0倍的提升。引用地址:http://blog.csdn.net/gz_huangzl/article/details/52486255

使用Mono的時候,腳本的編譯運行如下圖所示:

簡單的來說,3大腳本被編譯成IL,在游戲運行的時候,IL和項目里其他第三方兼容的DLL一起,放入Mono VM虛擬機,由虛擬機解析成機器碼,并且執行

IL2CPP做的改變由下圖紅色部分標明:

在得到中間語言IL后,使用IL2CPP將他們重新變回C++代碼,然后再由各個平臺的C++編譯器直接編譯成能執行的原生匯編代碼。

?

開啟IL2CPP的Unity構建流程:unity構建流程分步:

第一步:平臺資源處理,主要生成Library\metadata下面的文件。

第二步:腳本編譯(主要是C#腳本),Library\ScriptAssemblies下的Dll,主要是Assembly-CSharp.dll 和Assembly-CSharp-Editor.dll這兩個Dll。

第三步:把這個Assembly-CSharp.dll編譯成C++代碼。在IOS中,這里是導出Xcode的工程。Andriod中直接生成APK。

第四步:在IOS中,編譯Xcode,生成IPA。Andriod沒有這一步。


代碼注入方式

函數與屬性

?????? 首先需要加入Mono.Cecil庫 在Unity安裝目錄下 Editor\Data\Managed可以找到。

?????? 建立一個可以編輯AssemblyDefinition類。

AssemblyDefinitionassembiy = AssemblyDefinition.ReadAssembly(FileName);

獲取中間語言的類型

??? foreach (Mono.Cecil.TypeDefinitioniteminassembiy.MainModule.Types)

????? Console.Write("\nMainModule.Types" +? item.Name);

獲取指定類型的元素

item.Methods

獲取屬性的方法

item.Properties

注入代碼

????? 注入代碼的函數需要的參數:

AssemblyDefinitionassembiy? 可以編輯的IL語言的定義集合。

MethodDefinitionmethod? 需要修改的函數方法

TypeDefinitionitem?? 需要修改的函數所屬于的類

Instructionins = method.Body.Instructions[0];?// 獲取指定函數的指令集合

ILProcessorkWorker = method.Body.GetILProcessor();?//獲取修改指令集

kWorker.InsertBefore(ins, kWorker.Create(OpCodes.Nop)); // 在固定指令之前加入代碼

?

ILProcessor函數介紹

Replace(Instructiontarget, Instructioninstruction); 指令替換

Append(Instructioninstruction);? 增加指令

InsertAfter(Instructiontarget, Instructioninstruction);在指令指令之前插入新指令

InsertAfter(Instructiontarget, Instructioninstruction);在指令指令之后插入新指令

?

Create(OpCodeopcode); //創建新指令

Emit(OpCodeopcode); // 默認注入在當前函數最后插入對象指令。

關于IL指令,請參考《使用MSIL采用Emit方式實現C#的代碼生成與注入


工具準備

ILSpyversion:ILSpy是一個開源Net的瀏覽器和反編譯器。下載地址:http://ilspy.net/

使用指南:能把C#生成二進制文件轉換為MSIL 或者C# 任選一種,當想用Emit實現某一功能但是不知道怎么寫時,可以先把該功能的C#代碼寫出來,再用ILSpy將其轉換成MSIL,然后轉化為C#先查看是否能夠顯示出來。


測試環境準備

本節主要介紹如何能夠構成一個可以測試代碼注入的環境。

第一步:建立C#代碼代碼如下:

[Hotfix]

publicclassHotfixTest : MonoBehaviour {

??? LuaEnvluaenv = newLuaEnv();

??? publicinttick = 0; //如果是private的,在lua設置xlua.private_accessible(CS.HotfixTest)后即可訪問

??? //Update is called once per frame

??? voidUpdate () {

??? ??? if (++tick % 50 == 0){

??????????? Debug.Log(">>>>>>>>Updatein C#, tick = " + tick);

???????}

??? }

?

??? voidOnGUI() {

??????? if (GUI.Button(newRect(10, 100,300, 150), "Hotfix")){

??????????? luaenv.DoString(@"

???????????????xlua.hotfix(CS.HotfixTest, 'Update', function(self)

???????????????????self.tick = self.tick + 1

???????????????????if (self.tick % 50) == 0 then

???????????????????????print('<<<<<<<

???????self.tick = self.tick + 1

???????if (self.tick % 50) == 0 then

????????????print('<<<<<<<

??? for k, v in pairs(tbl) do

??????? local cflag = ''

??????? if k == '.ctor' then

???????????cflag = '_c'

???????????k = 'ctor'

??????? end

??????? local f = type(v) =='function' and v or nil

??????? xlua.access(cs, cflag.. '__Hitfix0_'..k, f) -- at least one

??????? pcall(function()

???????????for i = 1, 99 do

???????????????xlua.access(cs, '__Hitfix'..i..'_'..k, f)

???????????end

????? ??end)

??? end

end


通過Access修改

在Access對應的C#代碼是XLuaAccess代碼處理。下面主要處理函數修改的功能如下:

ObjectTranslatortranslator = ObjectTranslatorPool.Instance.Find(L);

object obj = translator.SafeGetCSObj(L, 1);

stringfieldName = LuaAPI.lua_tostring(L, 2);

varfield = type.GetField(fieldName, bindingFlags); //獲取函數名稱

field.SetValue(obj, translator.GetObject(L, 3, field.FieldType)); //修改當前函數名稱

修改創建函數對象

獲取函數功能:ObjectTranslator.CreateDelegateBridge

DelegateBridgeBaseexist_bridge = delegate_bridges[referenced].TargetasDelegateBridgeBase;

exist_delegate = exist_bridge.GetDelegateByType(delegateType);

?

通過類型來獲取函數的對象,如圖所示:

publicoverrideDelegateGetDelegateByType(Typetype){

??? if (type == typeof(__Gen_Hotfix_Delegate0)){

??????? returnnew__Gen_Hotfix_Delegate0(__Gen_Delegate_Imp1);

??? }

}


總結

?????? 本文主要揭示了Hoxfix的運行機制,便于能夠更好的使用Xlua的熱更機制。進一步了解C#的標簽、代碼生成、以及代碼注入的機制。這種機制能夠運行與Andriod和IOS平臺。同時也能對是否使用IL2CPP沒有影響。

原文地址:http://gad.qq.com/article/detail/7201590


.NET社區新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關注

總結

以上是生活随笔為你收集整理的Unity 游戏用XLua的HotFix实现热更原理揭秘的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。