Unity進階之ET網絡游戲開發框架 03-Hotfix層啟動


版權申明:

  • 本文原創首發於以下網站:
  1. 博客園『優夢創客』的空間:https://www.cnblogs.com/raymondking123
  2. 優夢創客的官方博客:https://91make.top
  3. 優夢創客的游戲講堂:https://91make.ke.qq.com
  4. 『優夢創客』的微信公眾號: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():

namespace ETHotfix
{
    public static class UILoginFactory
    {
        public static UI Create()
        {
	        try
	        {
				ResourcesComponent resourcesComponent = ETModel.Game.Scene.GetComponent<ResourcesComponent>();
				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事件處理:
```csharp
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方法鏈會被調用


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM