[高度なゲーム開発] Unity が ToLua を使用してホット アップデートを実装することをゼロから教えます (デモ プロジェクト | LuaFramework | インクリメンタル | HotUpdate を含む)

記事ディレクトリ

ゼロ。

こんにちは、私は新しいです。
クラスメートが個人的な手紙を送ってくれて、ホット アップデートに関するチュートリアルを書いてもらえないかと尋ねてきましたToLua
ここに画像の説明を挿入
今日は詳しくお話ししますが、内容は比較的長くなりますので、ブックマークしてゆっくり読むことをお勧めします。

1.私が作ったホットアップデートのデモ

バージョン管理、リソースのパッケージ化、リソースのロード、コードの暗号化と復号化、ホット アップデート パッケージのダウンロード、ブレークポイント レジュームなどの機能を含むDemo、完全なホット アップデート プロセスを実現する方法を使用して、時間をかけて作成しました。Unity + tolualua

1.効果のデモンストレーション

その効果は次のとおりです。複数の増分パッケージをダウンロードします:
写真の説明を追加してください
メジャー バージョンの更新をスキップ:
写真の説明を追加してください
ブレークポイントの再開:
写真の説明を追加してください

2.フローチャート

対応するフローチャートは次のとおりです (画像は拡大できます):
写真の説明を追加してください
まず、最新の現在のバージョンを記録するバージョン マネージャー;
インターフェイス リソースの読み込みを伴う起動時に更新インターフェイスが表示されます. リソース マネージャーをカプセル化し、インターフェイス マネージャー、リソース マネージャーは最初にホット アップデート ディレクトリ ( persistentDataPathof update) からリソースを検索し、見つからない場合は、パッケージ内のディレクトリに移動してStreamingAssetsリソースを見つけます。
次に、ホット アップデート ロジックを実行し、最初にWebサーバーに移動します。更新リストを要求し、バージョン番号を決定します, それがパッケージ全体の更新であるか増分更新であるか. 定量的更新, 必須の更新であるかどうか; 更新リストに従ってダウンロード, ここでは独立したスレッドを使用してダウンロードします
,UIメインスレッドの進行状況更新表示がスタックしないように
、ダウンロードプロセスはアップロードの再開をサポートしているため、ダウンロードプロセス中のネットワーク切断を回避できますまたはプロセスを強制終了した後、最初からダウンロードする必要があります
;増分パッケージMD5が正しいかどうかを確認し、正しくない場合MD5再度ダウンロードします;
検証が正しい場合は、ディレクトリMD5に解凍します;フレームワークを起動する前に、プリロード: and ;最後にフレームワークを起動してログイン画面を表示します.persistentDataPathupdate
lualuabundlelua.bundlelua_update.bundle
lua

さらに、パッケージングAssetBundleAPP全体パッケージ、増分パッケージに便利な簡易パッケージ ツールのセットを個別に作成しました.パッケージ全体を
パッケージ化する前に、元のファイルのリストが最初に生成され、パッケージ全体が最後に生成されます。パッケージ化、構成、リソースなど;さらに、他の人が平文ファイルを直接取得できないように、パッケージ化するときに最初にファイルを暗号化しましたAPPluaMD5luaAssetBundleAPP
lualualua
ここに画像の説明を挿入

3. プロジェクトのソースコード

のホット アップデートDemoプロジェクトはここにアップロードされています,アドレスCODE CHINA: https://codechina.csdn.net/linxinfa/UnityHotUpdateFramework mine とは異なり、プロジェクトを開くとエラーが報告される場合があります。
Unity2021.1.7f1c1
ここに画像の説明を挿入

私のDemoいくつかの紹介については、この記事の 6 番目のセクションまで飛ばしてください. 次に、最新の更新プログラムとtoluaフレームワークについて少しスペースを割いて説明します.

2. ホット アップデートが必要な理由は何ですか?

ホットなアップデートがある理由について、簡単にいくつかの言葉を述べます。
ゲームを開発してアプリマーケットに出したところ、ユーザーから重大な問題が報告され、BUG緊急に修正した後、再パッケージ化してAPPアプリマーケットの再審査を行う必要があり、心配しながら待っていたところ、ようやく審査を通過したとします。 、その後、プレーヤーはそれをAPP再度ダウンロードする必要があります インストール. プロセス全体を想像することはできますが、高速で効率的とは言えず、ダウンロードして再度インストールする必要があると、ユーザーが失われる可能性があります. したがって、再インストールせずに修正する方法
が必要です。つまり、APPBUGホットアップデート、私たちは一般的にも呼びます増分更新.
実際、ホット アップデートは修理に使用されるだけでなくBUG、オンラインでの小さなバージョンの反復にもよく使用されます。実際のゲーム プロジェクトの開発ペースは非常に速く、一般的に次のように分けられます。大きなバージョンの繰り返し小さなバージョンの反復. 大型版は多くの開発コンテンツを設計し、サイクルは通常 2 週間から 1 か月程度と長いですが、類似ゲームの激しい競争下では、小さなステップで新しいコンテンツを繰り返し、プレーヤーに提供し続ける必要があります。新しいゲームのコンテンツ、定着率の向上、アクティビティの増加。したがって、メジャー バージョン サイクルでは、いくつかの小さなバージョンのイテレーションが設計され、コンテンツはホット アップデートの形でオンライン バージョンに更新されます。ダウンロードしてインストールするAPPと、APP複数の目的に役立ちます。

3. Unity はホット アップデートをどのようにサポートしていますか

ホット アップデートにはコードとリソースが含まれ、コードにはC#コード、luaコードが含まれ、リソースには構成テーブル、プリセット、音楽効果音、アニメーション、フォント、画像、素材などが含まれます。
ここに画像の説明を挿入

1. C# コードのホット アップデート

Unityデフォルトの開発言語では、C#作成したコードは最終的にエンジンによってC#コンパイルおよびロードされます。したがって、コードの一部を独立したファイルにコンパイルしてサーバーにアップロードし、ゲームの開始時にサーバーからファイルをダウンロードし、実行時に再ロードすることで、ホット アップデートの目的を達成できますが、あなたがリロードしたコードがウイルスかどうかは悪魔が知っているため、危険な操作と見なされます. あなたのプロジェクトがアプリ市場に出された場合、この種のホット アップデート操作を使用すると、危険な操作と見なされる可能性が高くなります.アプリ市場による違法な操作として、棚から取り除かれました。dllUnityC#dllWebdlldlldlldll
ここに画像の説明を挿入

注: ところで、IL2CPPメソッドのパッケージ化を使用すると、C#コードはコードに変換されますC++

2. lua コードとリソースのホット アップデート

ゲームのホット アップデートに関して言えば、luaこのlua言語は実行時に動的に解釈され、実行されていないときは通常のテキスト ファイルであり、リソース ファイルと見なすことができます。したがって、luaコードの更新とリソースの更新は本質的に同じであり、通常、パッケージ化されてサーバーAssetBundleに配置されWeb、クライアントはWebサーバーからAssetBundleローカルに最新の更新をダウンロードします。

、などの多くのフレームワークが市場にlua出回っています.本質は、仮想マシン (言語で実装された仮想マシン) を環境に埋め込むことです. ゲームが実行されているとき、スクリプトは動的に解析され実行されます.ロジックを実装するために使用され、サーバーを介してスクリプトをダウンロードします(通常、ソース コードは暗号化されてからファイルに入力されるか、ソース コードはバイトコードにコンパイルされてからファイルに入力されます)。 、ホットアップデートの目的を達成するため。toluaxluauluasluaUnityluaclualuaWeblualuaAssetBundleluacluaAssetBundle

ここに画像の説明を挿入

4. Unity に統合された tolua フレームワーク: LuaFramewrk

1. tolua フレームワークをダウンロードします: LuaFramewrk

toluaアドレスGitHub: https://github.com/topameng/tolua
にアクセスできない学生がいる場合は、ミラー ソースからダウンロードすることGitHubもできます。アドレス: https://codechina.csdn.net/mirrors/topameng/toluaには、 との 2 つのバージョンのフレームワークが用意されていますバージョンをダウンロードしました: https://codechina.csdn.net/mirrors/jarjin/LuaFramework_UGUICode China

LuaFramework_NGUILuaFramework_UGUI
UGUI

ここに画像の説明を挿入

2. tolua フレームワーク プロジェクトを開きます: LuaFramework_UGUI

ダウンロード後、 に追加します。バージョンで作成されているUnity Hubことがわかります。ご想像のとおり、バージョンを使用して開きます。Unity5Unity2021.1.7f1c1
ここに画像の説明を挿入
間違いなく互換性の問題がいくつかあります。, 心配しないでください, 私はあなたのためにそれらを一つずつ解決しました.私はウェブサイトにUnity2021.1.7f1c1バージョンをLuaFramework_UGUIアップロードしました.バージョンもCODE CHINA使用する場合, あなたは私のバージョンを直接使用することができます. アドレス: https://codechina.csdn.ネット/linxinfa/LuaFramework_UGUI_20212021Unity

ここに画像の説明を挿入
ただし、詳細を理解していただくために、私の解決プロセスを書きます。
これらのエラー報告の問題をどのように解決したかを読んでおくことをお勧めします。これは、LuaFramework がどのように機能するかを理解するのに役立ちます。、 男に魚を与えるよりも、魚を教える方が良いです. 魚が欲しいですか、それとも魚が欲しいですか?

确定ボタンをスマートにクリックし、
ここに画像の説明を挿入

3. 登録ファイルの生成: Wrap クラスの生成

ロードして数分待つと、次のボックスがポップアップ表示されます。クリックすると、确定一般Unity的に使用されるクラスのクラスC#が生成され、仮想マシンにWrap登録されます。これにより、これらのクラスを で使用できるようになります。上のボタンをクリックすると、 menu をクリックすると、誤ってボタンをクリックしても、メニュー内で実行できます.生成が成功すると、ディレクトリ内に多くのクラスが表示されます.自問してみてください: どのクラスを生成するかをどうやって知るのでしょうか? 答えはスクリプトにあります. スクリプトを開くと,次のようにたくさん見ることができます.これに基づいて対応するクラスを生成します. 自分で書いたクラスを使いたい場合は,ここに呼び出しを追加する必要があります.例:lualuac#
ここに画像の説明を挿入
确定Lua / Gen Lua Wrap Files取消
ここに画像の説明を挿入
WrapAssets/LuaFramework/ToLua/Source/GenerateWrap
ここに画像の説明を挿入
Wrap
CustomSettings.csCustomSettings.cs_GT(typeof(XXXXX))
ここに画像の説明を挿入
Wraplua_GT

_GT(typeof(MyClass)),

注:GTではGenrate Tableluaクラスは実際にはtable

4. すべて生成メニュー

上記のクラスを生成したばかりですWrapが、実際には と も生成する必要がありますLua DelegatesLuaBinderメニューに表示されているように、
ここに画像の説明を挿入
生成されたWrapクラスはで仮想マシンLuaBinderに登録する必要がありlua、生成されたデリゲートは で仮想マシンに登録するlua必要があります。もちろん、これらはすべて自動的に生成されるため、メニューを実行するだけで済みます。通常、メニューを直接クリックすると、次の 3 つのことが行われます: 1.に従ってデリゲートを生成し、仮想マシンに登録します; 2.に従ってクラスを生成します; 3.でクラスの登録ロジック生成します。DelegateFactorylua
Lua / Generate All
ここに画像の説明を挿入

CustomSettingscustomDelegateListluaDelegateFactorylua
CustomSettingscustomTypeListWrap
LuaBinderWrap
ここに画像の説明を挿入

5. エラー報告の問題を解決する

5.1、GetElementType() が空で、エラーが報告される

Generate Allメニューをクリックした後、次のエラーが報告されました:
ここに画像の説明を挿入
コードの検索:ToLuaExport.cs最初の295行、GetElementType()空を返す可能性があります。
ここに画像の説明を挿入
空判定を追加します。これはToLuaExport.csツールの問題です。
ここに画像の説明を挿入

5.2. UnityEngine_ParticleSystemWrap がエラーを報告する

Generate Allメニューをもう一度クリックし、新しいエラーを報告し、
ここに画像の説明を挿入
コードを見つけます:スクリプト、生成されたクラスの異なるパラメーターを持つオーバーロードされた関数の生成に問題があることがわかります。UnityEngine_ParticleSystemWrap.cs実際WrapParticleSystem基本的に使用する必要ありませんコード内のこのメソッド 到着したので、単純かつ無礼にコメントアウトするだけで十分であり、同様に、クラスの同様のエラー報告を解決します。SetParticles
ここに画像の説明を挿入
SetParticleslua
ここに画像の説明を挿入
UnityEngine_ParticleSystemWrap

5.3、特定の Wrap を BaseType に移動

ここで問題が発生します。Wrapこれはツールによって生成されるため、Wrap上記のクラスを変更すると、次回の再生成時に上書きされ、再度エラーが報告されます。解決策は、次のようにディレクトリ
に移動することです.の対応するクラスの呼び出しをコメントアウトすることを忘れないでください,メニューをもう一度クリックすると、クラスが生成されないことがわかります. .生成されたクラスを自動的に登録します. 世代を指定していないので, では当然登録ロジックは生成されません.関係ありません.にはクラスがいくつかあります. 1つ見つけてどこにあるかを確認してください.参照検索でスクリプトにジャンプすると、その中のクラスが関数に登録されていることがわかります.ここで呼び出しを追加するだけです.大丈夫ですが、名前空間に注意する必要があります. およびでラップされ、マルチレイヤーの名前空間はネストできます。次に例を示します。Assets / LuaFramework / ToLua / BaseType
ここに画像の説明を挿入
CustomSettings.cs_GT
ここに画像の説明を挿入
Generate AllUnityEngine_ParticleSystemWrapLuaBinderWrapUnityEngine_ParticleSystemWrapLuaBinder
ここに画像の説明を挿入
BaseTypeWraplua
ここに画像の説明を挿入
LuaState.csBasetTypeWrapLuaStateOpenBaseLibs
ここに画像の説明を挿入
RegisterBeginModuleEndModule

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ように one を報告しました:
ここに画像の説明を挿入
I am a Windowsplatform, so I click Build Windows Resourcethe menu , そして
ここに画像の説明を挿入
次の新しいエラーを報告しました:
ここに画像の説明を挿入
one is UnityEngine_LightWrapa class,もう 1 つはUnityEngine_MeshRendererWrapクラスです。上記と同様のUnityEngine_ParticleSystemWrapメソッドを使用して処理します。
メニューを再実行するGenerate Allと、多くのファイルがディレクトリに生成されリソースが正常にパッケージ化されたことを示します.この時点でBuild Windows Resourceもう一度実行して、正常に実行できることを確認できます.
Assets / StreamingAssetsAssetBundle
ここに画像の説明を挿入

ここに画像の説明を挿入

五、toluaフレームワークのワークフロー

上記では、を実行するとUIインターフェイスが表示されることがわかりました. このUIインターフェイスはluaコードで作成されました. では、コードをUnity読み込んで実行するにはどうすればよいでしょうか? lua順を追って説明しますので、気長に読んでいただければ幸いです。

1. Main.cs: エントリ スクリプト

mainシーンのビューを振り返るとスクリプトがぶら下がっていHierarchyます。明らかに、これはエントリ スクリプトです。GameManager
ここに画像の説明を挿入
Main
ここに画像の説明を挿入

2. StartUp: ゲーム フレームワークを開始します。

Main.cs次のようにスクリプトを開きます。その文StartUpは最も重要な呼び出しであり、メッセージを
ここに画像の説明を挿入
送信してクラスの実行をトリガーしますここに多くのマネージャーが追加されていることがわかります。これらのマネージャーはオブジェクトにハングアップします。もちろん、必要に応じて新しいマネージャーを追加することもできます。不要なマネージャーを削除することもできます。特に、プロジェクトの途中でフレームワークを継承している場合は、インターフェイスなど、独自のプロジェクトに多くのマネージャーが既に存在している可能性があります。マネージャーとリソース管理マネージャー、サウンド マネージャー、ネットワーク マネージャー、スレッド マネージャーなど、START_UP
ここに画像の説明を挿入
StartUpCommandExecute
ここに画像の説明を挿入
GameManager
ここに画像の説明を挿入
toluaアーキテクトになりたい場合は、これらのマネージャーを自分で書いてみることをお勧めします。
LuaManager上記のマネージャーの中で、ここで注目したいのは、コアで最も重要なマネージャーですLuaManager

3. LuaManager: Lua マネージャー

LuaManagerこれはフレームワーク全体のコアでありtolua、その 3 つのコア メンバーは次のとおりです。
ここに画像の説明を挿入

// lua虚拟机
private LuaState lua;
// lua文件加载器
private LuaLoader loader;
// lua生命周期控制
private LuaLooper loop;

彼らが何をしているのかを1つずつ説明しましょう。

3.1、LuaState: lua 仮想マシン

私たちのluaコードはlua、実行する前にインタープリターによって解釈される必要があります. インターluaプリターはc言語で記述されており、各プラットフォームに対応するライブラリ ファイルがあります. 以前に記事を書きました: 「[高度なゲーム開発] 使用方法を教えてください」 Windows プラットフォームで tolua ランタイムのさまざまなプラットフォーム ライブラリをコンパイルする (Unity | Hot Update | tolua | Cross Compilation)」では、toluaプラットフォームごとのライブラリ ファイルのコンパイルについて詳しく説明しました。
ライブラリ関数の宣言は にありLuaDLL.cs、特定のメソッドの呼び出しなど、スケジューリング
ここに画像の説明を挿入
LuaStateの多くのペアをカプセル化します。これは、それ自体でスケジュールされます。したがって、スケジューリング関係は、フレームワークが開始されるとスケジューリングは主に次のことを行います。LuaDLLlua
ここに画像の説明を挿入
LuaStateLuaManagerLuaManager -> LuaState -> LuaDLL
LuaState
ここに画像の説明を挿入

3.2、LuaLoader: lua ファイルローダー

LuaLoaderLuaFileUtilsファイルの読み込みと検索の機能を継承し、主に提供するファイルローダですlua
コア メンバー変数:

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

yesの場合は、読み込まれたファイルを で見つけます。そうでない場合は、独自の設計に従ってファイルを読み込む方法を書き換えることができます。たとえば、ファイルを暗号化する場合は、最初にここで読み込む必要があります。復号化を行います。beZipfalsesearchPathslua文bundelluaReadFilelualua
ここに画像の説明を挿入

3.3、LuaLooper: lua ライフサイクル制御

にはUnityMonoBehaviourライフサイクルがあります。
公式の 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
ここに画像の説明を挿入

注: そうでない場合LuaLooperluaコルーチンは正常に実行されません。

4. ゲームマネージャー: ゲームマネージャー

このフレームワークは次のものを提供しますGameManager: フレームワークを使用する代わりに自分で作成できるゲーム マネージャーですが、ここではフレームワークが何をするかGameManagerについて説明します。GameManager

4.1. リソースの解放

ここに画像の説明を挿入

GameManager起動時に、まずリソース パス ( ) にファイルがUtil.DataPathあるかどうかを確認し、ない場合は、ディレクトリ内のファイルをリソース パス ( ) にコピーします。これにより、ディレクトリ内のすべてのファイルとリソース ファイルが記録されますファイルをトラバースし、ディレクトリ内のファイルとリソース ファイルをリソース パス ( ) にコピーします。このプロセスは呼び出されます。luaStreamingAssetsfiles.txtUtil.DataPathfiles.txtStreamingAssetsluamd5
files.txtStreamingAssetsluaUtil.DataPathリソースを解放する

4.2. リソースの更新

ここに画像の説明を挿入

AppConst.UpdateMode更新リソースを実行するかどうかによって異なります。
更新が必要な場合は、WebサーバーのアドレスにアクセスしAppConst.WebUrlて最新のものをダウンロードしてくださいfiles.txt
Then iterate through the latest ones files.txt, check whether the local files are missing or MD5not equal, and then go to Webthe server to download luacode or resources. ダウンロードでは、スレッド マネージャーを使用して、ダウンロード用の独立したスレッドを開始します。

4.3、lua コードの実行

luaコードとリソースを更新した後にGameManager呼び出され、OnInitializeここで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.luaAndroidActivityPromptPanel.luaUIAndroidlayoutCtrlManager.luaCtrl
ここに画像の説明を挿入
define.luaCtrlPanel

-- define.lua

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

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

次に、すべてがCtrlに登録されCtrlManager

-- 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

CtrlAwake()メソッドでC#呼び出されるPanelManagerメソッドCreatePanel

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

C#インターフェイス プリセットをロードしてスクリプトをハングアップするメソッド。このスクリプトは主にライフ サイクルを管理しPanelManager呼び出し中に要素オブジェクトを取得しますCreatePanelLuaBehaviour
ここに画像の説明を挿入
LuaBehaviourPanelluaPanelAwakeUI

-- 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

After the interface is created, it will be called back Ctrl.いくつかのイベントとコントロールを要素オブジェクトに追加OnCreate()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

6. ホット アップデート デモの紹介

1. ウェブサーバー

Webサーバーについては、Xiaopi クライアントを使用してApacheサーバーを直接起動しますWeb
ここに画像の説明を挿入
実際のプロジェクトでは、Alibaba Cloud や Tencent Cloud などのクラウド サービスをサーバーとして使用します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ディレクトリに配置されます.これらのリソースはデフォルトで依存されます.デフォルトは調理済み肉リソースです.対照的に,これらは生肉リソースです. ディレクトリに
ここに画像の説明を挿入
焼き肉のリソースを配置し、ホットアップデート前に使用するリソースを配置し、ホットアップデート後に他のディレクトリのリソースを読み込みます。GameResBaseRes
ここに画像の説明を挿入

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パスであり、その第 1 レベルのディレクトリが名前として使用されますAssetBundle。たとえば、上記の 3 つのリソースの第 1 レベルのディレクトリはすべて であるため、これらはという名前のファイルUIPrefabにまとめて入力されます。read するスクリプトをカプセル化しましたメソッドを介して構成を取得できます。uiprefab.bundleAssetBundle
ResourcesCfgresources.bytesGetResCfg

// ResourcesCfg.cs

public ResourcesCfgItem GetResCfg(int resId)

例:

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

5. リソース マネージャー: ResourceMgr.cs

リソースが構成された後、リソースはリソース マネージャーを介して読み込まれます。2 つのインターフェイスをカプセル化しました。

// 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のスクリプトを検索し、ライフ サイクルに関連するスケジュール機能インターフェースの作成と破棄の起源 ユニファイドコール。絵を描く:panelNameluaPanelMgr

ここに画像の説明を挿入

7. ホット アップデート ロジック: HotUpdater.cs

ホット アップデート ロジックを にカプセル化しHotUpdater、それが行うことは次のとおりです:
1. リストの更新を要求する;
2. バージョン番号に従って実際にダウンロードする必要があるファイルを計算し、最終的に更新するかどうかを決定する必須の更新またはオプションの更新です;
3. ダウンロードを実行し、Downloaderクラスをスケジュールします ダウンロード タスクを完了します;
4.Updateでダウンロード イベントをリッスンし、イベントに従ってインターフェイス更新デリゲート関数を呼び出し、インターフェイス ステータスの更新を実現します;
5 . ダウンロード完了後に検証を行うMD5. 検証に失敗した場合は、ダウンロードを再実行する
6.検証に合格したら、ファイルの解凍を実行し、ディレクトリMD5に解凍する7 解凍が完了したら、ファイルを削除する; 8 すべてのダウンロードが完了するまで次の増分パッケージをダウンロードします; 9 ダウンロードが完了したら、デリゲート関数をコールバックします。persistentDataPath/update
zip

actionAllDownloadDone

8. ダウンローダー: Downloader.cs

Downloader主なことは、ダウンロード タスクを実行し、それを使用してサーバーHttpWebRequestを要求することです。Web

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

ブレークポイントからの再開可能なアップロードをサポートするには、それが であるHttpWebResponseかどうかを判断する必要があります。サポートしている場合はブレークポイントからの再開可能なアップロードをサポートしており、そうでない場合は最初から再度ダウンロードする必要があります。StatusCodeHttpStatusCode.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入力されたluaものを逆にすることができAssetBundle、逆にしたものが文字化けしていることがわかります。これは、暗号化が有効になったことを示しています。
ここに画像の説明を挿入

注:AssetStudioダウンロード アドレス: https://codechina.csdn.net/mirrors/perfare/assetstudio

11.パッケージ全体を梱包する

メニューをクリックしBuild / 打包APP
ここに画像の説明を挿入
印刷するパッケージ全体のバージョン番号を設定し、 をクリックしてSaveから をクリックするとBuild APP、生成されたものが同じレベルのディレクトリのディレクトリにAPP配置されます。プラットフォームを例にすると、ファイルは自動的に次のように生成され、パッケージ化の時刻が記録されます。後続の増分パッケージを比較するのに便利ですAssetsBin
ここに画像の説明を挿入
Windows
ここに画像の説明を挿入
LuaFrameworkFiles_版本号.jsonLuaFrameworkmd5MD5

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"
            }
        ]
    }
]

md5そして、あなたsizeはそれを使って見ることができますそれは非常Hash.exe小さいです.ファイルをウィンドウにドラッグして表示します. ファイルは大文字で生成されていることに注意してください. 設定すると,小文字に変換されます.これは無料です〜)28KB
ここに画像の説明を挿入
CODE CHINA

sizemd5md5md5ToLower

セブン、終了

では、まずはたくさん書きましょう~
最新情報に戸惑う学生さんの参考になれば幸いです。
私はLin Xinfaです: https: //blog.csdn.net/linxinfa
オリジナルであることは簡単ではありません。再投稿する場合は、ソースを示してください、ありがとうございます〜
私が好きなら、いいね、フォロー、ブックマークできます。技術的な質問がある場合は、メッセージまたはプライベートメッセージを残してください〜

おすすめ

転載: blog.csdn.net/linxinfa/article/details/119493890