主頁 >  其他 > 【游戲開發高階】從零到一教你Unity使用ToLua實作熱更新(含Demo工程 | LuaFramework | 增量 | HotUpdate)

【游戲開發高階】從零到一教你Unity使用ToLua實作熱更新(含Demo工程 | LuaFramework | 增量 | HotUpdate)

2021-08-11 08:32:09 其他

文章目錄

      • 零、前言
      • 一、我做的熱更新Demo
        • 1、效果演示
        • 2、流程圖
        • 3、工程原始碼
      • 二、為什么要有熱更新
      • 三、Unity如何支持熱更新
        • 1、熱更C#代碼
        • 2、熱更lua代碼與資源
      • 四、Unity中集成tolua框架: LuaFramewrk
        • 1、下載tolua框架: LuaFramewrk
        • 2、打開tolua框架專案:LuaFramework_UGUI
        • 3、生成注冊檔案:生成Wrap類
        • 4、Generate All選單
        • 5、解決報錯問題
          • 5.1、GetElementType()為空報錯
          • 5.2、UnityEngine_ParticleSystemWrap報錯
          • 5.3、特定的Wrap移動到BaseType中
          • 5.4、LightWrap和MeshRendererWrap報錯
      • 五、tolua框架的作業流程
        • 1、Main.cs:入口腳本
        • 2、StartUp:啟動游戲框架
        • 3、LuaManager:Lua管理器
          • 3.1、LuaState:lua虛擬機
          • 3.2、LuaLoader:lua檔案加載器
          • 3.3、LuaLooper:lua生命周期控制
        • 4、GameManager:游戲管理器
          • 4.1、釋放資源
          • 4.2、更新資源
          • 4.3、執行lua代碼
          • 4.4、lua業務代碼的結構
      • 六、我的熱更Demo的一些介紹說明
        • 1、Web服務器
        • 2、代碼結構:Scripts目錄
        • 3、資源目錄結構:RawAssets目錄、GameRes目錄
        • 4、資源配置:resources.bytes、ResourcesCfg.cs
        • 5、資源管理器:ResourceMgr.cs
        • 6、界面管理器:PanelMgr.cs、BasePanel.cs
        • 7、熱更新邏輯:HotUpdater.cs
        • 8、下載器:Downloader.cs
        • 9、檔案解壓和壓縮
        • 10、AES對稱加密解密
        • 11、打整包
        • 12、打熱更包
      • 七、完畢

零、前言

嗨,大家好,我是新發,
有同學私信我,問我能不能寫一篇關于ToLua熱更新的教程,
在這里插入圖片描述
今天,我就來好好講講,內容會比較長,建議大家收藏后慢慢看,

一、我做的熱更新Demo

我花了一些時間做了一個Demo,采用的是Unity + tolua,實作完整的熱更流程,包括版本管理、資源打包、資源加載、lua代碼加密解密、熱更包下載、斷點續傳等功能,

1、效果演示

效果如下,下載多個增量包:
請添加圖片描述
跳過大版本更新:
請添加圖片描述
斷點續傳:
請添加圖片描述

2、流程圖

對應的流程圖如下(圖片可放大):
請添加圖片描述
首先是版本管理器,記錄當前的最新版本;
啟動時顯示更新界面,這里就涉及到界面資源的加載,我封裝了資源管理器和界面管理器,資源管理器優先從熱更目錄(persistentDataPathupdate)中查找資源,如果找不到才去包內的StreamingAssets目錄找資源;
接著執行熱更邏輯,先去Web服務器請求更新串列,判斷版本號,是整包更新還是增量更新,是否是強制更新;
根據更新串列執行下載,這里我使用獨立執行緒下載,這樣不會卡住UI主執行緒的進度更新顯示;
下載程序支持斷點續傳,這樣可以避免下載程序中網路斷開或強殺行程后需要從頭開始下載;
下載完增量包后校驗MD5是否正確,如果MD5不正確則重新下載;
校驗MD5正確后解壓到persistentDataPathupdate目錄中;
啟動lua框架前,先預加載luabundlelua.bundlelua_update.bundle
最后啟動lua框架,顯示登錄界面,

另外,我單獨寫一套簡單的打包工具,方便打AssetBundleAPP整包和增量包,
APP整包之前會先生成一份原始的lua檔案的MD5串列,打lua、配置、資源等的AssetBundle,最終才生成APP整包;
另外,打包lua時我先對lua做了加密,這樣可以防止被別人直接拿到lua明文檔案,
在這里插入圖片描述

3、工程原始碼

我的熱更新Demo工程以上傳到CODE CHINA,地址:https://codechina.csdn.net/linxinfa/UnityHotUpdateFramework
感興趣的同學可自行下載下來學習,另外,我使用的Unity版本為2021.1.7f1c1,如果你使用的版本與我的不同,可能打開工程會報錯,
在這里插入圖片描述

關于我這個Demo的一些介紹說明,可以跳到文章第六節,接下來,我先花一點篇幅講講熱更新和tolua框架,

二、為什么要有熱更新

關于為什么要有熱更新,我簡單啰嗦幾句,
假設你開發了一個游戲,上架到應用市場,之后用戶反饋了一個嚴重BUG,你緊急修復后,需要重新打包APP,重新提審應用市場,經過焦急地等待,終于過審了,接著玩家需要重新下載APP,重新安裝,整個流程可想而知,無法做到快速高效,而且一旦需要重新下載和安裝,用戶很可能就流失了,
所以我們需要有一種可以不重新安裝APP就可以修復BUG的方式,那就是熱更新,我們一般也叫增量更新
事實上,熱更新不僅僅應用于修復BUG,也經常用于線上的小版本迭代,實際的游戲專案開發節奏是很快的,一般分為大版本迭代小版本迭代,大版本會設計比較多的開發內容,周期長,一般在兩周到一個月左右;然而在同類游戲競品的激烈競爭下,你不得不小步快跑地迭代新內容,持續給玩家新的游戲內容,拉高留存,提升活躍度,所以在大版本周期中,就會設計一些小版本迭代,以熱更的方式把內容更新到線上版本,這樣既不需要重新提審APP到應用商店,又不需要玩家重新下載APP和安裝,一舉多得,

三、Unity如何支持熱更新

熱更新的內容包括代碼和資源,代碼有C#代碼、lua代碼,資源包括配置表、預設、音樂音效、影片、字體、圖片、材質等等,
在這里插入圖片描述

1、熱更C#代碼

Unity默認的開發語言是C#,我們寫的C#代碼最侄訓被編譯成dllUnity引擎來加載,所以可以把部分C#代碼編譯成一個獨立的dll,上傳到Web服務器,啟動游戲時從服務器下載dll檔案,在運行時重新加載dll,通過這種方式來達到熱更新的目的,不過這種方式被視為是危險操作,因為鬼知道你重新加載的dll的代碼里是不是病毒,如果你的專案上架了應用市場,使用這種dll的熱更操作,大概率會被應用市場視為違規操作而下架,
在這里插入圖片描述

注:順便說一下,如果你使用IL2CPP方式打包,則你的C#代碼會被轉成C++代碼,

2、熱更lua代碼與資源

說到游戲的熱更新,就不得不提lualua這門語言是運行時動態解釋的,它沒運行時就是一個普通的文本檔案,我們可以把它看成是資源檔案,所以lua代碼熱更和資源熱更本質是一樣的,一般都是打成AssetBundle放在Web服務器,客戶端從Web服務器下載最新的AssetBundle到本地,

市面上的lua框架有很多,比如toluaxluauluaslua等等,本質都是在Unity環境里內嵌一個lua虛擬機(使用c語言實作的虛擬機),游戲運行時動態決議lua腳本并執行,所以我們就可以把一些邏輯用lua來實作,然后再通過Web服務器下載lua腳本(一般是lua原始碼做加密后再打成AssetBundle檔案,或者是使用luaclua原始碼編譯成位元組碼然后再打成AssetBundle檔案),從而實作熱更的目的,

在這里插入圖片描述

四、Unity中集成tolua框架: LuaFramewrk

1、下載tolua框架: LuaFramewrk

toluaGitHub地址:https://github.com/topameng/tolua
如果有同學無法訪問GitHub,也可以通過Code China的鏡像源來下載,
地址:https://codechina.csdn.net/mirrors/topameng/tolua
我們可以看到它提供了兩個版本的框架:LuaFramework_NGUILuaFramework_UGUI
我們下載UGUI版本的:https://codechina.csdn.net/mirrors/jarjin/LuaFramework_UGUI

在這里插入圖片描述

2、打開tolua框架專案:LuaFramework_UGUI

下載下來后,我們在Unity Hub中添加它,可以看到它是使用Unity5版本做的,我使用Unity2021.1.7f1c1版本打開它,
在這里插入圖片描述
可想而知,肯定會有一些兼容問題的報錯,不要怕,我都幫你一一解決了,Unity2021.1.7f1c1版本的LuaFramework_UGUI我已上傳到CODE CHINA,如果你也是使用2021版本的Unity,可以直接使用我的版本,地址:https://codechina.csdn.net/linxinfa/LuaFramework_UGUI_2021

在這里插入圖片描述
不過,為了然你了解一些細節,我還是把我的解決程序寫出來吧,
我建議大家往下看我是如何解決這些報錯問題的,這對于你理解LuaFramework的作業原理是有幫助的,授人以魚不如授人以漁,你是要魚還是漁呢?

瀟灑地點擊確定按鈕,
在這里插入圖片描述

3、生成注冊檔案:生成Wrap類

經過幾分鐘的載入等待,彈出了下面這個框,點擊確定,它會將Unity常用的C#類生成Wrap類并注冊到lua虛擬機中,這樣我們就可以在lua中使用這些c#類了,
在這里插入圖片描述
上面點擊確定按鈕,等效于點擊選單Lua / Gen Lua Wrap Files,所以如果你不小心點擊了取消按鈕,可以在選單這里執行,
在這里插入圖片描述
生成Wrap成功后,我們可以在Assets/LuaFramework/ToLua/Source/Generate目錄中看到很多Wrap類,
在這里插入圖片描述
自問:它是怎么知道要生成哪些類的Wrap類的呢?
答案就在CustomSettings.cs腳本中,如果你打開CustomSettings.cs腳本,你可以看到很多_GT(typeof(XXXXX)),如下:
在這里插入圖片描述
它就是根據這里來生成對應的Wrap類的,如果你想在lua中使用你自己寫的類,則需要在這里加上_GT的呼叫,例:

_GT(typeof(MyClass)),

注:GT就是Genrate Table的意思,在lua中,類其實就是table

4、Generate All選單

上面我們只是生成了Wrap類,事實上,還要生成Lua DelegatesLuaBinder,你可以在選單中看到,
在這里插入圖片描述
生成的Wrap類需要在LuaBinder中注冊到lua虛擬機中,生成的lua委托需要在DelegateFactory中注冊到lua虛擬機中,當然,這些都是自動生成的,我們只需執行選單即可,
一般我們都是直接點擊選單Lua / Generate All
在這里插入圖片描述
它會做三件事情:
1 根據CustomSettings中的customDelegateList,生成lua委托并在DelegateFactory中注冊到lua虛擬機中;
2 根據CustomSettings中的customTypeList,生成Wrap類;
3 在LuaBinder中生成Wrap類的注冊邏輯,
在這里插入圖片描述

5、解決報錯問題

5.1、GetElementType()為空報錯

我們點擊Generate All選單后,報了如下錯:
在這里插入圖片描述
定位到代碼處:ToLuaExport.cs295行,GetElementType()可能回傳空,
在這里插入圖片描述
我們加上判空,這是ToLuaExport.cs工具的問題,
在這里插入圖片描述

5.2、UnityEngine_ParticleSystemWrap報錯

重新點擊Generate All選單,報了新的錯,
在這里插入圖片描述
定位到代碼處:UnityEngine_ParticleSystemWrap.cs腳本,可以看到是生成的Wrap類的ParticleSystemSetParticles的異參多載函式的生成有問題,
在這里插入圖片描述
事實上,這個SetParticles這個方法我們基本不用在lua代碼中使用到,所以簡單粗暴把它注釋掉就可以了,
在這里插入圖片描述
同理,解決掉UnityEngine_ParticleSystemWrap類的同類報錯,

5.3、特定的Wrap移動到BaseType中

問題來了,因為Wrap是工具生成的,上面我們這樣修改Wrap類,下次重新生成的時候會被覆寫回去,就又會報錯了,
解決辦法是把它移到Assets / LuaFramework / ToLua / BaseType目錄中,如下
在這里插入圖片描述
記得在CustomSettings.cs中把對應的類的_GT呼叫注釋掉,
在這里插入圖片描述
我們重新點擊Generate All選單,可以看到不會幫我們重新生成UnityEngine_ParticleSystemWrap類了,不過新的問題來了,在LuaBinder中會自動幫我們注冊生成的Wrap類,現在我們沒有指定生成UnityEngine_ParticleSystemWrap,自然在LuaBinder中就不會幫我們生成注冊的邏輯了,
在這里插入圖片描述
沒關系,BaseType中的也有一些Wrap類,它們肯定也是要注冊到lua虛擬機中的,我們只需要隨便找一個看看它是在哪里參考的就可以啦,
在這里插入圖片描述
通過參考查找,我們跳到了LuaState.cs腳本中,可以看到那些BasetType中的Wrap類是在LuaStateOpenBaseLibs函式中執行注冊的,
在這里插入圖片描述
我們只需要在這里添加上Register呼叫就可以了,不過需要注意命名空間,它是以BeginModuleEndModule來包裹的,多層命名空間可以嵌套,例:

BeginModule("System");
BeginModule("Generic");
System_Collections_Generic_ListWrap.Register(this);
System_Collections_Generic_DictionaryWrap.Register(this);
System_Collections_Generic_KeyValuePairWrap.Register(this);
EndModule();//Generic
EndModule();//end System

我們的ParticleSystem是在UnityEngine命名空間下的,所以放在BeginModule("UnityEngine");EndModule();之間,如下:
在這里插入圖片描述

5.4、LightWrap和MeshRendererWrap報錯

我們看到它沒有報錯了,打開main場景,
在這里插入圖片描述
運行,閃一下,報了一個Error,如下:
在這里插入圖片描述
我是Windows平臺,所以我點擊 Build Windows Resource選單,
在這里插入圖片描述
報了下面新的錯誤:
在這里插入圖片描述
一個是UnityEngine_LightWrap類,一個是UnityEngine_MeshRendererWrap類,我們使用上面類似UnityEngine_ParticleSystemWrap的方法來處理即可,
我們重新執行選單Generate AllBuild Windows Resource
可以在Assets / StreamingAssets目錄中生成了很多AssetBundle檔案,說明資源打包成功了,
在這里插入圖片描述
此時我們重新運行,即可看到可以正常運行了,
在這里插入圖片描述

五、tolua框架的作業流程

上面我們看到運行后出現了一個UI界面,這個UI界面是在lua代碼中創建的,那么,Unity是如何加載并執行lua代碼的呢?下面我來一步步講,希望你耐心看完,

1、Main.cs:入口腳本

我們看回main場景的Hierarchy視圖,有個GameManager
在這里插入圖片描述
它身上掛著一個Main腳本,明顯,這就是入口腳本,
在這里插入圖片描述

2、StartUp:啟動游戲框架

我們打開Main.cs腳本,如下,那句StartUp就是最關鍵的呼叫,
在這里插入圖片描述
里面會發送一個START_UP訊息,
在這里插入圖片描述
觸發StartUpCommand類執行Execute,我們可以看到在這里添加了很多管理器,
在這里插入圖片描述
這些管理器會掛到GameManager物體上,
在這里插入圖片描述
當然,我們可以根據自己的需求添加新的管理器,也可以把不需要的管理器刪掉,特別是你是專案中途繼承tolua框架的話,很多管理器可能你本身專案中就已經有了,比如界面管理器、資源管理器、聲音管理器、網路管理器、執行緒管理器等等,如果你想成為一位架構師,我建議你自己嘗試去寫這些管理器,
上面那些管理器中,最核心最關鍵的就是LuaManager,我這里要重點講一下LuaManager

3、LuaManager:Lua管理器

LuaManager是整個tolua框架的核心,它的三個核心成員如下:
在這里插入圖片描述

// lua虛擬機
private LuaState lua;
// lua檔案加載器
private LuaLoader loader;
// lua生命周期控制
private LuaLooper loop;

下面我挨個講解他們各自做的事情,

3.1、LuaState:lua虛擬機

我們的lua代碼需要經過lua解釋器進行解釋才能執行,lua解釋器是使用c語言寫的,它在各個平臺下有對應的庫檔案,我之前寫過一篇文章:《【游戲開發進階篇】教你在Windows平臺編譯tolua runtime的各個平臺庫(Unity | 熱更新 | tolua | 交叉編譯)》,里面我詳細講解了各個平臺的tolua庫檔案的編譯,感興趣的同學可以去看看,
庫函式的宣告在LuaDLL.cs中,
在這里插入圖片描述
LuaState中封裝了很多對LuaDLL的調度,比如呼叫某個lua的方法,
在這里插入圖片描述
LuaState又是由LuaManager來調度的,所以調度關系為LuaManager -> LuaState -> LuaDLL
啟動框架時,主要是調度LuaState做了下面這些事情:
在這里插入圖片描述

3.2、LuaLoader:lua檔案加載器

LuaLoader是檔案加載器,它繼承LuaFileUtils,主要提供lua檔案的讀取、查找功能,
核心成員變數:

 public bool beZip = false;
protected List<string> searchPaths = new List<string>();
protected Dictionary<string, AssetBundle> zipMap = new Dictionary<string, AssetBundle>();

beZipfalse時,在searchPaths中查找讀取lua文件;否則從外部設定過來bundel檔案中讀取lua檔案,我們可以重寫ReadFile方法,根據自己的設計去加載lua檔案,比如你對lua檔案做了加密,則需要在加載這里先做解密,
在這里插入圖片描述

3.3、LuaLooper:lua生命周期控制

Unity中,MonoBehaviour是有生命周期的,
可以參見Unity官方檔案的說明:https://docs.unity3d.com/Manual/ExecutionOrder.html

在這里插入圖片描述
我們的tolua為了實作類似的生命周期的功能,封裝了一些API

// LuaDLL.cs

[DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)]
public static extern int tolua_update(IntPtr L, float deltaTime, float unscaledDelta);

[DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)]
public static extern int tolua_lateupdate(IntPtr L);

[DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)]
public static extern int tolua_fixedupdate(IntPtr L, float fixedTime);

這些API就是由LuaLooper來調度的,
在這里插入圖片描述

注:如果沒有LuaLooper,則lua的協程會無法正常執行,

4、GameManager:游戲管理器

框架中幫我們提供了GameManager:游戲管理器,這個我們可以自己寫一個,不是用框架中的GameManager,不過我這里講一下框架中的GameManager做了什么事情,

4.1、釋放資源

在這里插入圖片描述

GameManager啟動時,會先檢測資源路徑(Util.DataPath)中是否有lua檔案,如果沒有,則將StreamingAssets目錄中的files.txt檔案拷貝到資源路徑(Util.DataPath)中,其中files.txt記錄了StreamingAssets目錄中所有lua檔案和資源檔案的md5
遍歷files.txt檔案,把StreamingAssets目錄中的lua檔案和資源檔案拷貝到資源路徑(Util.DataPath)中,這個程序叫做釋放資源

4.2、更新資源

在這里插入圖片描述

根據AppConst.UpdateMode決定要不要執行更新資源,
如果需要更新,則訪問Web服務器地址AppConst.WebUrl,下載最新的files.txt
然后遍歷最新的files.txt,檢查本地檔案是否缺少或者MD5是否不相等,然后去Web服務器下載lua代碼或資源,下載使用了執行緒管理器啟動獨立執行緒進行下載,

4.3、執行lua代碼

更新完lua代碼和資源后會呼叫GameManagerOnInitialize,到這里就可以啟動lua虛擬機執行lua代碼了,
啟動lua虛擬機:

LuaManager.InitStart();

執行lua代碼:

-- 加載Game.lua腳本
LuaManager.DoFile("Logic/Game");  
-- 執行lua的Game.OnInitOK方法
Util.CallMethod("Game", "OnInitOK"); 

我們在場景中看到的界面,
在這里插入圖片描述
就是在Game.OnInitOK里面創建出來的,
在這里插入圖片描述

4.4、lua業務代碼的結構

在這里插入圖片描述

lua業務代碼的結構是這樣的,以Demo中的界面為了例,Prompt是提示界面,
在這里插入圖片描述
對應一個PromptCtrl.lua腳本(界面互動邏輯,類似AndroidActivity腳本)和PromptPanel.lua腳本(界面UI物件系結,類似于Androidlayout布局檔案),CtrlManager.lua就是管理和調度Ctrl腳本的,
在這里插入圖片描述
先在define.lua中定義CtrlPanel的名字,

-- define.lua

CtrlNames = {
	Prompt = "PromptCtrl",
	Message = "MessageCtrl"
}

PanelNames = {
	"PromptPanel",	
	"MessagePanel",
}

然后所有的CtrlCtrlManager中注冊,

-- CtrlManager.lua

function CtrlManager.Init()
	logWarn("CtrlManager.Init----->>>");
	ctrlList[CtrlNames.Prompt] = PromptCtrl.New();
	ctrlList[CtrlNames.Message] = MessageCtrl.New();
	return this;
end

通過CtrlManager獲取對應的Ctrl物件,呼叫Awake()方法,

-- CtrlManager.lua
local ctrl = CtrlManager.GetCtrl(CtrlNames.Prompt);
if ctrl ~= nil then
    ctrl:Awake();
end

Ctrl中,Awake()方法中呼叫C#PanelManagerCreatePanel方法,

-- PromptCtrl.lua
function PromptCtrl.Awake()
	logWarn("PromptCtrl.Awake--->>");
	panelMgr:CreatePanel('Prompt', this.OnCreate);
end

C#PanelManagerCreatePanel方法去加載界面預設,并掛上LuaBehaviour腳本,
在這里插入圖片描述
這個LuaBehaviour腳本,主要是管理Panel的生命周期,呼叫luaPanelAwake,獲取UI元素物件,

-- PromptPanel.lua

local transform;
local gameObject;

PromptPanel = {};
local this = PromptPanel;

--啟動事件--
function PromptPanel.Awake(obj)
	gameObject = obj;
	transform = obj.transform;

	this.InitPanel();
	logWarn("Awake lua--->>"..gameObject.name);
end

--初始化面板--
function PromptPanel.InitPanel()
	this.btnOpen = transform:Find("Open").gameObject;
	this.gridParent = transform:Find('ScrollView/Grid');
end

--單擊事件--
function PromptPanel.OnDestroy()
	logWarn("OnDestroy---->>>");
end

界面創建后會回呼CtrlOnCreate(),在Ctrl中對UI元素物件添加一些事件和控制,

-- PromptCtrl.lua
--啟動事件--
function PromptCtrl.OnCreate(obj)
	gameObject = obj;
	transform = obj.transform;

	panel = transform:GetComponent('UIPanel');
	prompt = transform:GetComponent('LuaBehaviour');
	logWarn("Start lua--->>"..gameObject.name);

	prompt:AddClick(PromptPanel.btnOpen, this.OnClick);
	resMgr:LoadPrefab('prompt', { 'PromptItem' }, this.InitPanel);
end

六、我的熱更Demo的一些介紹說明

1、Web服務器

Web服務器我是使用小皮客戶端,直接啟動一個ApacheWeb服務器,
在這里插入圖片描述
實際專案會使用阿里云、騰訊云這些云服作為Web服務器,
增量包放在Web服務器跟目錄中,在這里插入圖片描述
update_list.json是更新串列檔案,里面記錄每個增量包的版本號、md5、大小和url,例:

[
    {
        "appVersion": "1.0.0.0",
        "appUrl": "https://blog.csdn.net/linxinfa",
        "updateList":
        [
			{
                "resVersion": "1.0.0.2",
                "md5": "206933991b0fd0275695e302b9fa0839",
                "size": 916897,
                "url": "http://localhost:7890/res_1.0.0.2.zip"
            },
            {
                "resVersion": "1.0.0.1",
                "md5": "6d71d1648247546b43197d1ddd832ad6",
                "size": 4737,
                "url": "http://localhost:7890/script_1.0.0.1.zip"
            }
        ]
    }
]

2、代碼結構:Scripts目錄

我的代碼結構如下:
在這里插入圖片描述

3、資源目錄結構:RawAssets目錄、GameRes目錄

生肉資源放在RawAssets目錄中,比如影片、字體、圖片等,這些資源會被預設依賴,預設是熟肉資源,相對的,這些就是生肉資源,
在這里插入圖片描述
熟肉資源放在GameRes目錄中,其中BaseRes放熱更之前就要使用的資源,其他目錄的資源都是熱更后才加載的,
在這里插入圖片描述

4、資源配置:resources.bytes、ResourcesCfg.cs

我把資源路徑配置在resources.bytes中,如下:

[
    { "id":1, "editor_path":"UIPrefabs/LoginPanel.prefab", "desc":"登錄界面" },
    { "id":2, "editor_path":"UIPrefabs/PlazaPanel.prefab", "desc":"大廳界面" },
    { "id":3, "editor_path":"UIPrefabs/TipsFly.prefab", "desc":"提示語" }
]

editor_path是相對GameRes的路徑,它的第一級目錄將會作為AssetBundle的名字,比如上面三個資源的一級目錄都是UIPrefab,所以他們會一起打在一個叫uiprefab.bundleAssetBundle檔案中,
我封裝了ResourcesCfg腳本來讀取resources.bytes,你可以通過GetResCfg方法來獲取配置,

// ResourcesCfg.cs

public ResourcesCfgItem GetResCfg(int resId)

例:

var resCfg = ResourcesCfg.instance.GetResCfg(1);

5、資源管理器:ResourceMgr.cs

配置了資源后,可以通過資源管理器來加載資源,我封裝了兩個介面:

// ResourceMgr.cs

public T LoadAsset<T>(int resId) where T : UObject
public T LoadAsset<T>(string resPath) where T : UObject

你可以通過資源id來加載資源,
例:

var loginPanelObj = ResourceMgr.instance.LoadAsset<GameObject>(1);

也可以通過相對路徑來加載資源,
例:

var loginPanelObj = ResourceMgr.instance.LoadAsset<GameObject>("UIPrefabs/LoginPanel.prefab");

不過如果要顯示界面,建議使用PanelMgr來調度和統一管理,

6、界面管理器:PanelMgr.cs、BasePanel.cs

為了方便管理界面,我封裝了界面基類BasePanel,由它來調度界面的生命周期,它有一個panelName成員,初始化時會去查找與panelName同名的lua腳本,調度生命周期相關的函式,界面的創建和銷毀由PanelMgr來統一呼叫,
畫個圖:
在這里插入圖片描述

7、熱更新邏輯:HotUpdater.cs

熱更新路基我封裝在HotUpdater中,它做的事情如下:
1 請求更新串列;
2 根據版本號計算真正需要下載的檔案,最終決定是否需要更新,是強制更新還是可選更新;
3 執行下載,調度Downloader類完成下載任務;
4 在Update中監聽下載事件,并根據事件呼叫界面更新的委托函式,實作界面狀態更新;
5 下載完成后執行MD5校驗,如果校驗不通過,重新執行下載;
6 MD5校驗通過后,執行檔案解壓,解壓到persistentDataPath/update目錄中;
7 解壓完畢后洗掉zip檔案;
8 下載下一個增量包,知道全部下載完畢;
9 下載完畢后,回呼actionAllDownloadDone委托函式,

8、下載器:Downloader.cs

Downloader主要就是執行下載任務,使用的是HttpWebRequest來請求Web服務器,

var httpReq = HttpWebRequest.Create(url) as HttpWebRequest;

要支持斷點續傳,需要判斷HttpWebResponseStatusCode是否為HttpStatusCode.PartialContent,如果是才支持斷點續傳,否則要重新從頭下載,

var response = (HttpWebResponse)httpReq.GetResponse();
if (response.StatusCode != HttpStatusCode.PartialContent)
{
	// 不能斷點續傳,要重新下載
}

斷點續傳的核心就是本地檔案Seek到檔案末尾,HttpWebRequest.AddRange到要續傳的位置,如下:

m_fs = new FileStream(savePath, FileMode.OpenOrCreate, FileAccess.Write);
var lastDownloadSize = fs.Length;

m_fs.Seek(lastDownloadSize, SeekOrigin.Current);
httpReq.AddRange(lastDownloadSize);

下載檔案的寫檔案比較耗時,使用獨立的執行緒來執寫檔案,

// 開啟一個獨立的寫檔案執行緒
if (null == m_thread)
{
	m_stopThread = false;
	m_thread = new Thread(WriteThread);
	m_thread.Start();
}

寫檔案的邏輯就是從HttpWebResponseStream流中讀取資料然后寫到本地的檔案中,

var readSize = m_ns.Read(m_buff, 0, m_buff.Length);
if (readSize > 0)
{
    m_fs.Write(m_buff, 0, readSize);
    curDownloadSize += readSize;
    Thread.Sleep(0);
}
else
{
    // 完畢
    m_stopThread = true;
    state = DownloadState.End;
    Dispose();
}

9、檔案解壓和壓縮

增量包我是在打包工具中執行了壓縮,壓成.zip檔案,客戶端熱更新時下載后會執行解壓,
壓縮和解壓我使用的庫是Ionic.Zip.Unity.dll
在這里插入圖片描述
壓縮檔案:

// using Ionic.Zip;

using (ZipFile zip = new ZipFile())
{
	// 設定壓縮密碼
	// zip.Password = "123456";
    zip.AddDirectory(Application.dataPath + "/TestDir", "./TestDir");
    zip.AddFile(Application.dataPath + "/Test1.txt", "./");
    zip.Save(Application.dataPath + "/result.zip");
}

解壓檔案:

using (ZipFile zip = new ZipFile(Application.dataPath + "/result.zip"))
{
	// 設定解壓密碼
	// zip.Password = "123456";
	// 直接解壓所有檔案
    // zip.ExtractAll(Application.dataPath + "/UnZip");
    foreach (var entity in zip)
    {	
    	// 挨個檔案解壓
		entity.Extract(Application.dataPath + "/UnZip");
	}
}

10、AES對稱加密解密

lua代碼打包成AssetBundle時,我先把lua代碼拷貝到一個臨時目錄中并做加密,然后才執行AssetBundle打包,
我使用的加密演算法是AES,對應的腳本是AESEncrypt.cs
在這里插入圖片描述
解密介面:

public static byte[] Encrypt(byte[] toEncryptArray)

解密介面:

public static byte[] Decrypt(byte[] toDecryptArray)

我們可以使用AssetStudio對打出來的luaAssetBundle進行逆向,可以看到逆向出來的是亂碼,說明我們的加密生效了,
在這里插入圖片描述

注:AssetStudio下載地址:https://codechina.csdn.net/mirrors/perfare/assetstudio

11、打整包

點擊選單Build / 打包APP
在這里插入圖片描述
設定你要打的整包的版本號,點擊Save,然后點擊Build APP即可,生成的APP會放在Assets同級目錄的Bin目錄中,
在這里插入圖片描述
Windows平臺為例,如下
在這里插入圖片描述
會自動生成一個LuaFrameworkFiles_版本號.json檔案,里面記錄了打包時的LuaFramework的檔案的md5,方便后續打增量包是進行MD5對比,

12、打熱更包

點擊選單Build / 打熱更包
在這里插入圖片描述
設定增量包的版本號,設定要讀取的LuaFrameworkFiles_xxxx.json檔案的版本號,根據需要添加要打進增量包的資源檔案,最后點擊打熱更包按鈕即可,
在這里插入圖片描述
生成的熱更包會存放在Bin目錄中,
在這里插入圖片描述
我們只需將其拷貝到Web服務器,
在這里插入圖片描述
并配置到update_list.json即可,如下:

[
    {
        "appVersion": "1.0.0.0",
        "appUrl": "https://blog.csdn.net/linxinfa",
        "updateList":
        [
            {
                "resVersion": "1.0.0.1",
                "md5": "50d550486de1a72bd0caaa560128a9ad",
                "size": 908405,
                "url": "http://localhost:7890/res_1.0.0.1.zip"
            }
        ]
    }
]

七、完畢

好了,就先寫這么多吧~
希望可以幫助到對熱更新有困惑的同學,
我是林新發:https://blog.csdn.net/linxinfa
原創不易,若轉載請注明出處,感謝大家~
喜歡我的可以點贊、關注、收藏,如果有什么技術上的疑問,歡迎留言或私信~

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/293056.html

標籤:其他

上一篇:基于概率分析的智能AI掃雷程式秒破雷界世界紀錄

下一篇:《Learning Spatio-Temporal Representation with Pseudo-3D Residual Networks》演算法詳解

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more