zoukankan      html  css  js  c++  java
  • 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方法链会被调用
  • 相关阅读:
    OpenCMS创建导航条
    C++笔记(2)面向对象编程
    C++笔记(3)模板与泛型编程
    多线程和信号量
    C++笔记(4)用于大型程序的工具
    C++笔记(5)特殊工具与技术
    C++笔记(1)类
    Effective C++ 笔记(1)
    C语言笔记整理(2)
    C语言笔记整理(3)
  • 原文地址:https://www.cnblogs.com/raymondking123/p/11369644.html
Copyright © 2011-2022 走看看