上篇记录了对基础类的理解,这片回到program.cs文件
program主要用于初始化game.scene里面的内容,首先最重要的就是事件系统。
EventSystem用于事件通知,事件回调,走的消息监听,消息派发,消息回调的方式,是一种有效解耦各种业务逻辑代码的编程方式。
要想完全理解EventSystem,先要弄清楚ET里面的UnOrderMultiMap,这是个数据结构辅助类。专门用于管理某个类型对应的List。当然这个类,还带有重用功能,用于提升性能。
事件相关接口,用于定义事件处理,一个事件监听一个IEvent,AEvent,class AEvent。具体需要具体实现
public interface IEvent
{
void Handle();
void Handle(object a);
void Handle(object a, object b);
void Handle(object a, object b, object c);
}
了解类上面的基础数据结构之后回到EventSystem.
定义几个DLLType枚举类型。
this.awakeSystems.Clear();
this.lateUpdateSystems.Clear();
this.updateSystems.Clear();
this.startSystems.Clear();
this.loadSystems.Clear();
this.changeSystems.Clear();
this.destroySystems.Clear();
this.deserializeSystems.Clear();
foreach (Type type in types[typeof(ObjectSystemAttribute)])
{
object[] attrs = type.GetCustomAttributes(typeof(ObjectSystemAttribute), false);
if (attrs.Length == 0)
{
continue;
}
object obj = Activator.CreateInstance(type);
switch (obj)
{
case IAwakeSystem objectSystem:
this.awakeSystems.Add(objectSystem.Type(), objectSystem);
break;
case IUpdateSystem updateSystem:
this.updateSystems.Add(updateSystem.Type(), updateSystem);
break;
case ILateUpdateSystem lateUpdateSystem:
this.lateUpdateSystems.Add(lateUpdateSystem.Type(), lateUpdateSystem);
break;
case IStartSystem startSystem:
this.startSystems.Add(startSystem.Type(), startSystem);
break;
case IDestroySystem destroySystem:
this.destroySystems.Add(destroySystem.Type(), destroySystem);
break;
case ILoadSystem loadSystem:
this.loadSystems.Add(loadSystem.Type(), loadSystem);
break;
case IChangeSystem changeSystem:
this.changeSystems.Add(changeSystem.Type(), changeSystem);
break;
case IDeserializeSystem deserializeSystem:
this.deserializeSystems.Add(deserializeSystem.Type(), deserializeSystem);
break;
}
}
11.然后同样的,筛选出所有EventAttribute特性标记的类,实例化出来,这些类都继承或者实现类IEvent等,然后将特性打进去的事件字符串当做key,添加到对应到事件列表中
// 分发数值监听
[Event(EventIdType.NumbericChange)]
public class NumericChangeEvent_NotifyWatcher: AEvent<long, NumericType, int>
{
public override void Run(long id, NumericType numericType, int value)
{
Game.Scene.GetComponent<NumericWatcherComponent>().Run(numericType, id, value);
}
}
上面的事件实例添加到了allEvents[EventIdType.NumbericChange]对应的List中,这样一旦派发EventIdType.NumbericChange事件,就会调用对应类型实例的Run方法里面去
Game.EventSystem.Add(DLLType.Model, typeof(Game).Assembly);
通过将当前Game所在的程序集(ETModel),添加到事件系统中
Game.EventSystem.Add(DLLType.Hotfix, DllHelper.GetHotfixAssembly());
GetHotfixAssembly()方法内部通过Assembly.Load(dllBytes, pdbBytes);方式加载热更程序集,获取到程序集,并添加到事件系统中
通过上面两句调用,将下面两个程序集内的所有相关事件system进行实例化,并放入到各个事件UnOrderMultiMap中
监听当component通过public void Add(Component component)方法加入到事件系统中时,添加到各个队列中,然后在合适时机(比如update,在每个update中调用),调用与componnet对应的system中的对应方法
public void Add(Component component)
{
this.allComponents.Add(component.InstanceId, component);
Type type = component.GetType();
if (this.loadSystems.ContainsKey(type))
{
this.loaders.Enqueue(component.InstanceId);
}
if (this.updateSystems.ContainsKey(type))
{
this.updates.Enqueue(component.InstanceId);
}
if (this.startSystems.ContainsKey(type))
{
this.starts.Enqueue(component.InstanceId);
}
if (this.lateUpdateSystems.ContainsKey(type))
{
this.lateUpdates.Enqueue(component.InstanceId);
}
}
这里先记录到这,下篇继续。回顾一下,通过遍历程序集类,获取特性标记与类型的类型信息,存到types里面,然后再遍历这个typs通过特性,以及类型信息,反射实例化,放到不同的map或者字典里面处理。
总体梳理一下现在碰到的几个特性对应的意义:
[ObjectSystem]
public class ActorMessageDispatcherComponentStartSystem: AwakeSystem<ActorMessageDispatcherComponent>
{
public override void Awake(ActorMessageDispatcherComponent self)
{
self.Awake();
}
}
这个system就是继承AwakeSystem,并且关联ActorMessageDispatcherComponent组件,现在注册好这个system后,当ActorMessageDispatcherComponent添加到EventSystem后,会调用到public override void Awake(ActorMessageDispatcherComponent self)这个函数,进一步调用到ActorMessageDispatcherComponent本身的Awake函数,其他system类似如此。
// 分发数值监听
[Event(EventIdType.NumbericChange)]
public class NumericChangeEvent_NotifyWatcher: AEvent<long, NumericType, int>
{
public override void Run(long id, NumericType numericType, int value)
{
Game.Scene.GetComponent<NumericWatcherComponent>().Run(numericType, id, value);
}
}
}
当有调用时,会调用到这个类的处理上
Game.EventSystem.Run(EventIdType.NumbericChange, this.Entity.Id, (NumericType) final, result);
public void Run<A, B, C>(string type, A a, B b, C c)
{
List<IEvent> iEvents;
if (!this.allEvents.TryGetValue(type, out iEvents))
{
return;
}
foreach (IEvent iEvent in iEvents)
{
try
{
iEvent?.Handle(a, b, c);
}
catch (Exception e)
{
Log.Error(e);
}
}
}