ET 7.2框架学习(3)

编程入门 行业动态 更新时间:2024-10-25 00:35:43

ET 7.2<a href=https://www.elefans.com/category/jswz/34/1770644.html style=框架学习(3)"/>

ET 7.2框架学习(3)

上次我们说到了第五个单例,这次继续阅读源码。

第六个单例是EventSystem,事件系统,这个单例在ET系统中非常重要。

先来看看作者怎么讲的,打开et目录下的Book目录,找到3.4事件机制EventSystem.md这篇文章。

其大意就是一个系统需要关注事件A,那么先向系统申明说我关注了事件A,当事件A发生时告诉我,然后我来自己做关于事件A的处理。那么这个机制是如何实现的呢,作者利用了C#的反射机制。

在EventSystem.cs这个代码文件中,“先向系统申明说我关注了事件A”,这个的实现在以下函数中

public void Add(Dictionary<string, Type> addTypes)

我们先来看看是哪里调用了这个函数,通过打断点运行的方式,可以看到在CodeLoader这个单例中的Start()方法调用了这个函数(代码模式和非代码模式都会调用到,这里看一个就行了,意思是一样的)

// 获取所有程序集中的所有类型
Dictionary<string, Type> types = AssemblyHelper.GetAssemblyTypes(assemblies);// 将类型添加到事件系统中
EventSystem.Instance.Add(types);

可以看到他把程序中所有定义的类型都取出来了,然后传入了Add()函数。

Add()函数中一共做了以下几件事:

1、把程序中的所有类型都保存到了allTypes中。

2、建立了BaseAttribute特性子类的类型到非特性类型的关系表types。

这点看起来有点绕,举个例子吧,我们可以在ET中找到以下类:

namespace ET.Client
{[Event(SceneType.Client)]public class AfterCreateClientScene_AddComponent: AEvent<EventType.AfterCreateClientScene>{protected override async ETTask Run(Scene scene, EventType.AfterCreateClientScene args){scene.AddComponent<UIEventComponent>();scene.AddComponent<UIComponent>();scene.AddComponent<ResourcesLoaderComponent>();await ETTask.CompletedTask;}}
}

这里面的[Event(SceneType.Client)],表明这个类具有EventAttribute特性,而EventAttribute特性又继承于BaseAttribute

using System;namespace ET
{[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]public class EventAttribute: BaseAttribute{public SceneType SceneType { get; }public EventAttribute(SceneType sceneType){this.SceneType = sceneType;}}
}

所有上面的types关系表中会有一条EventAttribute到AfterCreateClientScene_AddComponent的映射关系。

3、创建所有同时具有ObjectSystemAttribute特性和继承自ISystemType接口的类,并且建立映射关系到typeSystems中。

我们先来看一下继承自ISystemType接口的有哪些:

可以看到只要我们的类继承自上图中的任意接口且具有ObjectSystemAttribute特性就要加入这个映射关系中。

再举个实例:

在SessionAcceptTimeoutComponentSystem.cs这个文件中,有SessionAcceptTimeoutComponentAwakeSystem和SessionAcceptTimeoutComponentDestroySystem这两个类,他们都用[ObjectSystem]标记为具有ObjectSystemAttribute特性,且一个继承于AwakeSystem,一个继承于DestroySystem,这个两个System分别继承于IAwakeSystem接口和IDestroySystem接口,满足上述条件,加入映射容器typeSystems中。

using System;namespace ET
{[Invoke(TimerInvokeType.SessionAcceptTimeout)]public class SessionAcceptTimeout: ATimer<SessionAcceptTimeoutComponent>{protected override void Run(SessionAcceptTimeoutComponent self){try{self.Parent.Dispose();}catch (Exception e){Log.Error($"move timer error: {self.Id}\n{e}");}}}[ObjectSystem]public class SessionAcceptTimeoutComponentAwakeSystem: AwakeSystem<SessionAcceptTimeoutComponent>{protected override void Awake(SessionAcceptTimeoutComponent self){self.Timer = TimerComponent.Instance.NewOnceTimer(TimeHelper.ServerNow() + 5000, TimerInvokeType.SessionAcceptTimeout, self);}}[ObjectSystem]public class SessionAcceptTimeoutComponentDestroySystem: DestroySystem<SessionAcceptTimeoutComponent>{protected override void Destroy(SessionAcceptTimeoutComponent self){TimerComponent.Instance.Remove(ref self.Timer);}}
}

我们可以看到上面的写法是对SessionAcceptTimeoutComponent类的一种成员函数扩充方式,同时AwakeSystem和DestroySystem是一个模板类,这里都传入了SessionAcceptTimeoutComponent类型,这个类型会在ISystemType的成员函数Type()返回

namespace ET
{public interface ISystemType{Type Type();Type SystemType();InstanceQueueIndex GetInstanceQueueIndex();}
}

这个的用处是在建立typeSystems容器的映射关系时使用的,其作为了其键值,然后索引了一个系统类型和对象的键值对,图示如下:

4、创建所有具有EventAttribute特性的类,并且建立事件类型到事件类对象的映射关系到allEvents中。

举个实例:

有一个事件类型为ChangePosition:

using Unity.Mathematics;namespace ET
{namespace EventType{public struct ChangePosition{public Unit Unit;public float3 OldPos;}public struct ChangeRotation{public Unit Unit;}}
}

有两个类使用到了这个事件类型

using Unity.Mathematics;namespace ET.Server
{[Event(SceneType.Map)]public class ChangePosition_NotifyAOI: AEvent<ET.EventType.ChangePosition>{protected override async ETTask Run(Scene scene, ET.EventType.ChangePosition args){Unit unit = args.Unit;float3 oldPos = args.OldPos;int oldCellX = (int) (oldPos.x * 1000) / AOIManagerComponent.CellSize;int oldCellY = (int) (oldPos.z * 1000) / AOIManagerComponent.CellSize;int newCellX = (int) (unit.Position.x * 1000) / AOIManagerComponent.CellSize;int newCellY = (int) (unit.Position.z * 1000) / AOIManagerComponent.CellSize;if (oldCellX == newCellX && oldCellY == newCellY){return;}AOIEntity aoiEntity = unit.GetComponent<AOIEntity>();if (aoiEntity == null){return;}unit.DomainScene().GetComponent<AOIManagerComponent>().Move(aoiEntity, newCellX, newCellY);await ETTask.CompletedTask;}}
}
using UnityEngine;namespace ET.Client
{[Event(SceneType.Current)]public class ChangePosition_SyncGameObjectPos: AEvent<EventType.ChangePosition>{protected override async ETTask Run(Scene scene, EventType.ChangePosition args){Unit unit = args.Unit;GameObjectComponent gameObjectComponent = unit.GetComponent<GameObjectComponent>();if (gameObjectComponent == null){return;}Transform transform = gameObjectComponent.GameObject.transform;transform.position = unit.Position;await ETTask.CompletedTask;}}
}

这两个事件类都具有EventAttribute特性,所以最终allEvents中会有一条ChangePosition到这两个类对象的映射关系。

5、创建所有具有InvokeAttribute特性的类,并且建立回调类型到回调类对象的映射关系到allEvents中。

举个例子:

namespace ET
{[FriendOf(typeof(MoveComponent))]public static class MoveComponentSystem{[Invoke(TimerInvokeType.MoveTimer)]public class MoveTimer: ATimer<MoveComponent>{protected override void Run(MoveComponent self){try{self.MoveForward(true);}catch (Exception e){Log.Error($"move timer error: {self.Id}\n{e}");}}}...}
}

上面有个MoveTimer类,其拥有InvokeAttribute特性,其继承于ATimer抽象类

namespace ET
{public abstract class ATimer<T>: AInvokeHandler<TimerCallback> where T: class{public override void Handle(TimerCallback a){this.Run(a.Args as T);}protected abstract void Run(T t);}
}

而ATimer又继承于AInvokeHandler抽象类,AInvokeHandler又继承于IInvoke接口

using System;namespace ET
{public interface IInvoke{Type Type { get; }}public abstract class AInvokeHandler<A>: IInvoke where A: struct{public Type Type{get{return typeof (A);}}public abstract void Handle(A a);}public abstract class AInvokeHandler<A, T>: IInvoke where A: struct{public Type Type{get{return typeof (A);}}public abstract T Handle(A a);}
}

我们看到有个

        public Type Type{get{return typeof (A);}}

的方法,这就是返回类型的,而这个A就是TimerCallback类型,故建立了一个从TimerCallback到MoveTimer的映射关系。这样我们就可以向系统发出一个事件,然后所有关注这个事件的处理函数进行响应处理,看触发TimerCallback事件的函数

        private void Run(TimerAction timerAction){switch (timerAction.TimerClass){case TimerClass.OnceTimer:{EventSystem.Instance.Invoke(timerAction.Type, new TimerCallback() { Args = timerAction.Object });timerAction.Recycle();break;}case TimerClass.OnceWaitTimer:{ETTask tcs = timerAction.Object as ETTask;tcs.SetResult();timerAction.Recycle();break;}case TimerClass.RepeatedTimer:{                    long timeNow = GetNow();timerAction.StartTime = timeNow;this.AddTimer(timerAction);EventSystem.Instance.Invoke(timerAction.Type, new TimerCallback() { Args = timerAction.Object });break;}}}

回顾上面的内容,我们发现这个函数主要就是创建了一批对象,做了一些特性和类(对象)的映射工作。

我们接着看一些比较重要的成员函数。

        // 注册系统public void RegisterSystem(Entity component){Type type = component.GetType();OneTypeSystems oneTypeSystems = this.typeSystems.GetOneTypeSystems(type);if (oneTypeSystems == null){return;}for (int i = 0; i < oneTypeSystems.QueueFlag.Length; ++i){if (!oneTypeSystems.QueueFlag[i]){continue;}this.queues[i].Enqueue(component.InstanceId);}}

这个会在Entity.cs进行注册时调用,当注册一个实体(组件也是实体)时,会将这个实体的InstanceId放到queues队列数组中,queues队列数组的长度为InstanceQueueIndex.Max

    public enum InstanceQueueIndex{None = -1,Update,LateUpdate,Load,Max,}

这样如果我的实体的System类有UpdateSystem、LateUpdateSystem、LoadSystem等,同时有ObjectSystem特性,就会加入到上述的队列中,然后EventSystem本身就是继承于ISingletonUpdate和ISingletonLateUpdate的,这样可以在Update()函数和LateUpdate()中遍历上述的队列,调用实体的Update()和LateUpdate()方法了,达到驱动实体生命周期函数的目的。

更多推荐

ET 7.2框架学习(3)

本文发布于:2024-02-26 15:18:26,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1702977.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:框架

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!