Unity進階之ET網路遊戲開發框架 03-Hotfix層啟動
阿新 • • 發佈:2019-08-19
版權申明:
- 本文原創首發於以下網站:
- 部落格園『優夢創客』的空間:https://www.cnblogs.com/raymondking123
- 優夢創客的官方部落格:https://91make.top
- 優夢創客的遊戲講堂:https://91make.ke.qq.com
- 『優夢創客』的微信公眾號:umaketop
- 您可以自由轉載,但必須加入完整的版權宣告!
概要
- 在init.cs中:
- 首先,await到DownloadBundle完畢(即使是非同步的)
- 然後,Game.Hotfix.GotoHotfix()負責啟動Hotfix層,進而啟動UILogin畫面
- 本節就主要分析UILogin的啟動流程,以及其事件處理
先上Hotfix入口程式碼:
public void LoadHotfixAssembly() { Game.Scene.GetComponent<ResourcesComponent>().LoadBundle($"code.unity3d"); GameObject code = (GameObject)Game.Scene.GetComponent<ResourcesComponent>().GetAsset("code.unity3d", "Code"); byte[] assBytes = code.Get<TextAsset>("Hotfix.dll").bytes; byte[] pdbBytes = code.Get<TextAsset>("Hotfix.pdb").bytes; #if ILRuntime Log.Debug($"當前使用的是ILRuntime模式"); // ... #else Log.Debug($"當前使用的是Mono模式"); this.assembly = Assembly.Load(assBytes, pdbBytes); Type hotfixInit = this.assembly.GetType("ETHotfix.Init"); this.start = new MonoStaticMethod(hotfixInit, "Start"); this.hotfixTypes = this.assembly.GetTypes().ToList(); #endif Game.Scene.GetComponent<ResourcesComponent>().UnloadBundle($"code.unity3d"); } public void GotoHotfix() { #if ILRuntime ILHelper.InitILRuntime(this.appDomain); #endif this.start.Run(); }
- 由於ILRT模式無法除錯,所以開發階段選擇Mono模式,下面的分析也是以Mono方式為例的,這也是ET作者建議的工作流程(開發用Mono,釋出用ILRT)
- LoadHotfixAssembly:得到start方法
- start方法實際就是ETHotfix名稱空間下的Init類的Start方法
- GotoHotfix:執行start方法
ETHotfix.Init.Start():
namespace ETHotfix { public static class Init { public static void Start() { #if ILRuntime if (!Define.IsILRuntime) { Log.Error("Model層是mono模式, 但是Hotfix層是ILRuntime模式"); } #else if (Define.IsILRuntime) { Log.Error("Model層是ILRuntime模式, Hotfix層是mono模式"); } #endif try { // 註冊熱更層回撥 ETModel.Game.Hotfix.Update = () => { Update(); }; ETModel.Game.Hotfix.LateUpdate = () => { LateUpdate(); }; ETModel.Game.Hotfix.OnApplicationQuit = () => { OnApplicationQuit(); }; Game.Scene.AddComponent<UIComponent>(); Game.Scene.AddComponent<OpcodeTypeComponent>(); Game.Scene.AddComponent<MessageDispatcherComponent>(); // 載入熱更配置 ETModel.Game.Scene.GetComponent<ResourcesComponent>().LoadBundle("config.unity3d"); Game.Scene.AddComponent<ConfigComponent>(); ETModel.Game.Scene.GetComponent<ResourcesComponent>().UnloadBundle("config.unity3d"); UnitConfig unitConfig = (UnitConfig)Game.Scene.GetComponent<ConfigComponent>().Get(typeof(UnitConfig), 1001); Log.Debug($"config {JsonHelper.ToJson(unitConfig)}"); Game.EventSystem.Run(EventIdType.InitSceneStart); } catch (Exception e) { Log.Error(e); } } } }
- 注意:第86行,和上一課的分析類似,也是在初始化階段通過引發事件來建立UI介面,只不過這次的事件是InitSceneStart
InitSceneStart_CreateLoginUI.Run():
namespace ETHotfix
{
[Event(EventIdType.InitSceneStart)]
public class InitSceneStart_CreateLoginUI: AEvent
{
public override void Run()
{
UI ui = UILoginFactory.Create(); // 注意:這次是呼叫Hotfix層的UILoginFactory的Create工廠方法來建立UI實體,下面會重點分析
Game.Scene.GetComponent<UIComponent>().Add(ui); // 注意:這次是新增Hotfix層的UIComponent元件,其程式碼與模型層類似,不再贅述
}
}
}
UILoginFactory.Create():
```csharp
namespace ETHotfix
{
public static class UILoginFactory
{
public static UI Create()
{
try
{
ResourcesComponent resourcesComponent = ETModel.Game.Scene.GetComponent
resourcesComponent.LoadBundle(UIType.UILogin.StringToAB());
GameObject bundleGameObject = (GameObject)resourcesComponent.GetAsset(UIType.UILogin.StringToAB(), UIType.UILogin);
GameObject gameObject = UnityEngine.Object.Instantiate(bundleGameObject);
UI ui = ComponentFactory.Create<UI, string, GameObject>(UIType.UILogin, gameObject, false);
ui.AddComponent<UILoginComponent>();
return ui;
}
catch (Exception e)
{
Log.Error(e);
return null;
}
}
}
}```
- 注意:
- 這次載入的是從AB包載入UILogin預製體資源,而上節課是從Resources資料夾載入UILoading資源,不一樣!
- 雖然通過ComponentFactory.Create建立的Entity還是UI Entity,但該Entity新增的元件和上節課不一樣,是“UILoginComponent”!
UILoginComponent事件處理:
namespace ETHotfix
{
[ObjectSystem]
public class UiLoginComponentSystem : AwakeSystem<UILoginComponent>
{
public override void Awake(UILoginComponent self)
{
self.Awake();
}
}
public class UILoginComponent: Component
{
private GameObject account;
private GameObject loginBtn;
public void Awake()
{
ReferenceCollector rc = this.GetParent<UI>().GameObject.GetComponent<ReferenceCollector>();
loginBtn = rc.Get<GameObject>("LoginBtn");
loginBtn.GetComponent<Button>().onClick.Add(OnLogin);
this.account = rc.Get<GameObject>("Account");
}
public void OnLogin()
{
LoginHelper.OnLoginAsync(this.account.GetComponent<InputField>().text).Coroutine();
}
}
}
- 事件處理在UILoginComponent.Awake方法中被註冊
- 在Entity.AddComponent時,AwakeSystem.Awake()->UILoginComponent.Awake方法鏈會被呼叫