資源描述:
《另類unity熱更新大法:代碼注入式補(bǔ)丁熱更新》由會員上傳分享,免費在線閱讀,更多相關(guān)內(nèi)容在應(yīng)用文檔-天天文庫。
1、另類Unity熱更新大法:代碼注入式補(bǔ)丁熱更新眼看Unity引擎熱火朝天,無數(shù)程序猿加入到了Unity開發(fā)的大本營。一些老項目,當(dāng)時ulua/slua還不如今天那樣的成熟,因此他們選擇了全c#開發(fā);也有一些出于性能考慮,全c#開發(fā);也有一些沒有太豐富運營經(jīng)驗的開發(fā)團(tuán)隊,沒有想太多,用全c#爽爽地開發(fā)。用C#開發(fā)爽爽的日子一天一天的過去了,直到突然有一天,策劃老大說:“我們得做個熱更新模塊!”;突然有一天,老板說:“別人游戲用Lua熱更新,為什么我們不行?”;突然有一天,運營說:“線上游戲出了個bug,重新編譯出
2、包審核得幾天??!”——嗯,這時候,受傷的總是程序猿。有沒有亡羊補(bǔ)牢,臨危受命的折衷方法?可以不用把C#改成Lua,可以不用區(qū)分平臺(AndroidDLL重載IOS卻不行),可以對任何代碼做修復(fù)的方法?有的,并且用很笨的一句代碼來概括:classFucker{voidFucking(){if(PatchScript.HasPatchScript("Fucker.Fucking")){//dopatchfuckPatchScript.CallPatchScript("Fucker.Fucking");return;
3、}//dooriginfuckLog.Info("Iamaoriginalfuck");}}往所有的函數(shù)注入代碼,當(dāng)存在補(bǔ)丁腳本時執(zhí)行補(bǔ)丁腳本,不存在時執(zhí)行原代碼。因此,本文的熱更新等同于打補(bǔ)丁。什么是熱更新?吐槽一點,雖然我們這個方法確實將熱更新做成模塊了,但這絕對是迫不得已的。熱更新絕對不是一個功能模塊能實現(xiàn),它是一個底層架構(gòu)所決定的。要說一個項目不好,無法實現(xiàn)熱更新,這歸根到底是架構(gòu)沒想好、策劃沒堅持、程序沒執(zhí)著、運營懶得管等等各種各樣復(fù)雜原因所導(dǎo)致的。我心目中理想熱更新是怎樣?要熱?。骸θ我獠课坏拇a
4、進(jìn)行修改;·運行時,自動下載更新代碼,爾后無需重啟;·運行時,立即重載代碼,并繼續(xù)運行;·兼顧開發(fā)環(huán)境與生產(chǎn)環(huán)境的簡便性;熱更新在Web開發(fā)領(lǐng)域非常普遍,畢竟HTTP是無狀態(tài)的;而游戲這種高實時性的開發(fā)相比,要想做好熱更新就確實需要架構(gòu)層的更多考慮了。怎么做好熱更新,我們還是回到主題,接下來介紹方法,可以達(dá)到什么目的:·對任意部位的方法體代碼進(jìn)行修改;·運行時,立即重載代碼,并繼續(xù)運行·語言無關(guān):同樣的思路可以應(yīng)用在Java、C#、Go、C++等等·使用起來不太方便·亡羊補(bǔ)牢專用代碼注入補(bǔ)丁熱更新大法流程上面說
5、了很多廢話。接下直奔主題,要怎樣做到:classFucker{voidFucking(){if(PatchScript.HasPatchScript("Fucker.Fucking")){//dopatchfuckPatchScript.CallPatchScript("Fucker.Fucking");return;}//dooriginfuckLog.Info("Iamaoriginalfuck");}}我們要針對Fucker類的Fucking方法進(jìn)行更新,則新建Lua腳本Fucker.Fucking.lu
6、a--文件名Fucker.Fucking.luafunctionFunc()print("Iamapatchfuck!")endreturnFunc一個補(bǔ)丁腳本就此完成,當(dāng)程序運行到Fucking函數(shù)時,實際上它執(zhí)行的是Lua腳本,變相的實現(xiàn)了熱更新的功能——改變代碼的執(zhí)行行為。STEP1:執(zhí)行環(huán)境本文針對Unity游戲開發(fā),那么原語言,當(dāng)然是C#了;而打補(bǔ)丁的語言,當(dāng)時Lua了;在這里我們使用SLua插件,它的高質(zhì)量代碼和強(qiáng)大的反射功能,非常適合代碼注入補(bǔ)丁熱更新。classPatchScript{publi
7、cboolHasPatchScript(stringpath){returnFile.Exists("Script/"+path+".lua");}publicvoidCallScript(stringpath){stringscriptCode=File.ReadAllString(path);varluaFunc=this.luaState.doScript(scriptCode)asLuaFunction;luaFunc.call();}}STEP2:代碼注入嗯,執(zhí)行環(huán)境,非常的簡單,不就是簡單的if判斷
8、嗎?估計最令人迷惑的部分就是,如何往所有的C#函數(shù)體前部分插入代碼了。我們要做的,遍歷所有的c#文件,取得class類名,然后再分析函數(shù)名,定位函數(shù)在代碼中的起始位置、獲取函數(shù)的參數(shù)列表、參數(shù)類型……等等??雌饋砗軓?fù)雜,是不是要對c#做語法分析、詞法分析了?感覺工作量很大啊。幸好,輪子已經(jīng)做好了。這里要用到一個重要的庫——NRefactory。包括IDEMonoDevelop中的語法智