using System.Reflection; using Cysharp.Threading.Tasks; namespace KYFramework { public sealed class EventSystem { private readonly Dictionary allComponents = new Dictionary(); private readonly UnOrderMultiMap types = new UnOrderMultiMap(); private readonly Dictionary> allEvents = new Dictionary>(); private Dictionary> allInvokes = new(); private readonly UnOrderMultiMap awakeSystems = new UnOrderMultiMap(); private readonly UnOrderMultiMap startSystems = new UnOrderMultiMap(); private readonly UnOrderMultiMap destroySystems = new UnOrderMultiMap(); private readonly UnOrderMultiMap loadSystems = new UnOrderMultiMap(); private readonly UnOrderMultiMap updateSystems = new UnOrderMultiMap(); private readonly UnOrderMultiMap lateUpdateSystems = new UnOrderMultiMap(); private readonly UnOrderMultiMap changeSystems = new UnOrderMultiMap(); private readonly UnOrderMultiMap deserializeSystems = new UnOrderMultiMap(); private Queue updates = new Queue(); private Queue updates2 = new Queue(); private readonly Queue starts = new Queue(); private Queue loaders = new Queue(); private Queue loaders2 = new Queue(); private Queue lateUpdates = new Queue(); private Queue lateUpdates2 = new Queue(); public List assemblies = new List(); public void Add(Assembly assembly) { this.assemblies.Add(assembly); this.types.Clear(); foreach (Assembly assembly1 in assemblies) { foreach (Type type in assembly1.GetTypes()) { object[] objects = type.GetCustomAttributes(typeof(BaseAttribute), false); if (objects.Length == 0) continue; BaseAttribute baseAttribute = (BaseAttribute)objects[0]; this.types.Add(baseAttribute.AttributeType, type); } } this.awakeSystems.Clear(); this.lateUpdateSystems.Clear(); this.updateSystems.Clear(); this.startSystems.Clear(); this.loadSystems.Clear(); this.changeSystems.Clear(); this.destroySystems.Clear(); this.deserializeSystems.Clear(); if (types.ContainsKey(typeof(ObjectSystemAttribute))) { 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; } } } this.allEvents.Clear(); if (types.ContainsKey(typeof(EventAttribute))) { foreach (Type type in types[typeof(EventAttribute)]) { IEvent obj = Activator.CreateInstance(type) as IEvent; if (obj == null) { throw new Exception($"type not is AEvent: {type.Name}"); } object[] attrs = type.GetCustomAttributes(typeof(EventAttribute), false); foreach (object attr in attrs) { EventAttribute eventAttribute = attr as EventAttribute; Type eventType = obj.GetEventType(); EventInfo eventInfo = new(obj); if (!this.allEvents.ContainsKey(eventType)) { this.allEvents.Add(eventType, new List()); } this.allEvents[eventType].Add(eventInfo); } } } this.allInvokes = new Dictionary>(); if (types.ContainsKey(typeof(InvokeAttribute))) { foreach (Type type in types[typeof(InvokeAttribute)]) { object obj = Activator.CreateInstance(type); IInvoke iInvoke = obj as IInvoke; if (iInvoke == null) { throw new Exception($"type not is callback: {type.Name}"); } object[] attrs = type.GetCustomAttributes(typeof(InvokeAttribute), false); foreach (object attr in attrs) { if (!this.allInvokes.TryGetValue(iInvoke.Type, out var dict)) { dict = new Dictionary(); this.allInvokes.Add(iInvoke.Type, dict); } InvokeAttribute invokeAttribute = attr as InvokeAttribute; try { dict.Add(invokeAttribute.Type, obj); } catch (Exception e) { throw new Exception($"action type duplicate: {iInvoke.Type.Name} {invokeAttribute.Type}", e); } } } } this.Load(); } private class EventInfo { public IEvent IEvent { get; } public EventInfo(IEvent iEvent) { this.IEvent = iEvent; } } public List GetTypes(Type systemAttributeType) { if (!this.types.ContainsKey(systemAttributeType)) { return new List(); } return this.types[systemAttributeType]; } 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); } } public void Remove(long instanceId) { this.allComponents.Remove(instanceId); } public Component Get(long instanceId) { Component component = null; this.allComponents.TryGetValue(instanceId, out component); return component; } public void Deserialize(Component component) { List iDeserializeSystems = this.deserializeSystems[component.GetType()]; if (iDeserializeSystems == null) { return; } foreach (IDeserializeSystem deserializeSystem in iDeserializeSystems) { if (deserializeSystem == null) { continue; } try { deserializeSystem.Run(component); } catch (Exception e) { Log.Error(e); } } } public void Awake(Component component) { List iAwakeSystems = this.awakeSystems[component.GetType()]; if (iAwakeSystems == null) { return; } foreach (IAwakeSystem aAwakeSystem in iAwakeSystems) { if (aAwakeSystem == null) { continue; } IAwake iAwake = aAwakeSystem as IAwake; if (iAwake == null) { continue; } try { iAwake.Run(component); } catch (Exception e) { Log.Error(e); } } } public void Awake(Component component, P1 p1) { List iAwakeSystems = this.awakeSystems[component.GetType()]; if (iAwakeSystems == null) { return; } foreach (IAwakeSystem aAwakeSystem in iAwakeSystems) { if (aAwakeSystem == null) { continue; } IAwake iAwake = aAwakeSystem as IAwake; if (iAwake == null) { continue; } try { iAwake.Run(component, p1); } catch (Exception e) { Log.Error(e); } } } public void Awake(Component component, P1 p1, P2 p2) { List iAwakeSystems = this.awakeSystems[component.GetType()]; if (iAwakeSystems == null) { return; } foreach (IAwakeSystem aAwakeSystem in iAwakeSystems) { if (aAwakeSystem == null) { continue; } IAwake iAwake = aAwakeSystem as IAwake; if (iAwake == null) { continue; } try { iAwake.Run(component, p1, p2); } catch (Exception e) { Log.Error(e); } } } public void Awake(Component component, P1 p1, P2 p2, P3 p3) { List iAwakeSystems = this.awakeSystems[component.GetType()]; if (iAwakeSystems == null) { return; } foreach (IAwakeSystem aAwakeSystem in iAwakeSystems) { if (aAwakeSystem == null) { continue; } IAwake iAwake = aAwakeSystem as IAwake; if (iAwake == null) { continue; } try { iAwake.Run(component, p1, p2, p3); } catch (Exception e) { Log.Error(e); } } } public void Change(Component component) { List iChangeSystems = this.changeSystems[component.GetType()]; if (iChangeSystems == null) { return; } foreach (IChangeSystem iChangeSystem in iChangeSystems) { if (iChangeSystem == null) { continue; } try { iChangeSystem.Run(component); } catch (Exception e) { Log.Error(e); } } } public void Load() { while (this.loaders.Count > 0) { long instanceId = this.loaders.Dequeue(); Component component; if (!this.allComponents.TryGetValue(instanceId, out component)) { continue; } if (component.IsDisposed) { continue; } List iLoadSystems = this.loadSystems[component.GetType()]; if (iLoadSystems == null) { continue; } this.loaders2.Enqueue(instanceId); foreach (ILoadSystem iLoadSystem in iLoadSystems) { try { iLoadSystem.Run(component); } catch (Exception e) { Log.Error(e); } } } ObjectHelper.Swap(ref this.loaders, ref this.loaders2); } private void Start() { while (this.starts.Count > 0) { long instanceId = this.starts.Dequeue(); Component component; if (!this.allComponents.TryGetValue(instanceId, out component)) { continue; } List iStartSystems = this.startSystems[component.GetType()]; if (iStartSystems == null) { continue; } foreach (IStartSystem iStartSystem in iStartSystems) { try { iStartSystem.Run(component); } catch (Exception e) { Log.Error(e); } } } } public void Destroy(Component component) { List iDestroySystems = this.destroySystems[component.GetType()]; if (iDestroySystems == null) { return; } foreach (IDestroySystem iDestroySystem in iDestroySystems) { if (iDestroySystem == null) { continue; } try { iDestroySystem.Run(component); } catch (Exception e) { Log.Error(e); } } } public void Update() { this.Start(); while (this.updates.Count > 0) { long instanceId = this.updates.Dequeue(); Component component; if (!this.allComponents.TryGetValue(instanceId, out component)) { continue; } if (component.IsDisposed) { continue; } List iUpdateSystems = this.updateSystems[component.GetType()]; if (iUpdateSystems == null) { continue; } this.updates2.Enqueue(instanceId); foreach (IUpdateSystem iUpdateSystem in iUpdateSystems) { try { iUpdateSystem.Run(component); } catch (Exception e) { Log.Error(e); } } } ObjectHelper.Swap(ref this.updates, ref this.updates2); } public void LateUpdate() { while (this.lateUpdates.Count > 0) { long instanceId = this.lateUpdates.Dequeue(); Component component; if (!this.allComponents.TryGetValue(instanceId, out component)) { continue; } if (component.IsDisposed) { continue; } List iLateUpdateSystems = this.lateUpdateSystems[component.GetType()]; if (iLateUpdateSystems == null) { continue; } this.lateUpdates2.Enqueue(instanceId); foreach (ILateUpdateSystem iLateUpdateSystem in iLateUpdateSystems) { try { iLateUpdateSystem.Run(component); } catch (Exception e) { Log.Error(e); } } } ObjectHelper.Swap(ref this.lateUpdates, ref this.lateUpdates2); } public void Publish(T a) where T : struct { List iEvents; if (!this.allEvents.TryGetValue(typeof(T), out iEvents)) { return; } foreach (EventInfo eventInfo in iEvents) { if (!(eventInfo.IEvent is AEvent aEvent)) { Log.Error($"event error: {eventInfo.IEvent.GetType().Name}"); continue; } aEvent.Handle(a).Forget(); } } // Invoke跟Publish的区别(特别注意) // Invoke类似函数,必须有被调用方,否则异常,调用者跟被调用者属于同一模块,比如MoveComponent中的Timer计时器,调用跟被调用的代码均属于移动模块 // 既然Invoke跟函数一样,那么为什么不使用函数呢? 因为有时候不方便直接调用,比如Config加载,在客户端跟服务端加载方式不一样。比如TimerComponent需要根据Id分发 // 注意,不要把Invoke当函数使用,这样会造成代码可读性降低,能用函数不要用Invoke // publish是事件,抛出去可以没人订阅,调用者跟被调用者属于两个模块,比如任务系统需要知道道具使用的信息,则订阅道具使用事件 public void Invoke(int type, A args) where A : struct { if (!this.allInvokes.TryGetValue(typeof(A), out var invokeHandlers)) { throw new Exception($"Invoke error: {typeof(A).Name}"); } if (!invokeHandlers.TryGetValue(type, out var invokeHandler)) { throw new Exception($"Invoke error: {typeof(A).Name} {type}"); } var aInvokeHandler = invokeHandler as AInvokeHandler; if (aInvokeHandler == null) { throw new Exception($"Invoke error, not AInvokeHandler: {typeof(A).Name} {type}"); } aInvokeHandler.Handle(args); } public T Invoke(int type, A args) where A : struct { if (!this.allInvokes.TryGetValue(typeof(A), out var invokeHandlers)) { throw new Exception($"Invoke error: {typeof(A).Name}"); } if (!invokeHandlers.TryGetValue(type, out var invokeHandler)) { throw new Exception($"Invoke error: {typeof(A).Name} {type}"); } var aInvokeHandler = invokeHandler as AInvokeHandler; if (aInvokeHandler == null) { throw new Exception($"Invoke error, not AInvokeHandler: {typeof(T).Name} {type}"); } return aInvokeHandler.Handle(args); } public void Invoke(A args) where A : struct { Invoke(0, args); } public T Invoke(A args) where A : struct { return Invoke(0, args); } } }