using System; using System.Collections.Generic; namespace Syntriax.Engine.Core; public class ActiveBehaviourCollector : IBehaviourCollector where T : class, IBehaviour { public Event, IBehaviourCollector.BehaviourCollectedArguments> OnCollected { get; } = new(); public Event, IBehaviourCollector.BehaviourRemovedArguments> OnRemoved { get; } = new(); public Event OnUniverseAssigned { get; } = new(); public Event? OnUnassigned { get; } = new(); private readonly Event.EventHandler delegateOnBehaviourAdded = null!; private readonly Event.EventHandler delegateOnBehaviourRemoved = null!; private readonly Event.EventHandler delegateOnBehaviourStateChanged = null!; private readonly Event.EventHandler delegateOnUniverseObjectRegistered = null!; private readonly Event.EventHandler delegateOnUniverseObjectUnregistered = null!; private readonly List monitoringBehaviours = new(32); protected readonly List activeBehaviours = new(32); protected readonly Dictionary monitoringActiveToBehaviour = new(32); public IUniverse Universe { get; private set; } = null!; private void OnUniverseObjectRegistered(IUniverse manager, IUniverse.UniverseObjectRegisteredArguments args) { IUniverseObject universeObject = args.UniverseObjectRegistered; universeObject.BehaviourController.OnBehaviourAdded.AddListener(delegateOnBehaviourAdded); universeObject.BehaviourController.OnBehaviourRemoved.AddListener(delegateOnBehaviourRemoved); for (int i = 0; i < universeObject.BehaviourController.Count; i++) OnBehaviourAdded(universeObject.BehaviourController, new(universeObject.BehaviourController[i])); } private void OnUniverseObjectUnregistered(IUniverse manager, IUniverse.UniverseObjectUnRegisteredArguments args) { IUniverseObject universeObject = args.UniverseObjectUnregistered; universeObject.BehaviourController.OnBehaviourAdded.RemoveListener(delegateOnBehaviourAdded); universeObject.BehaviourController.OnBehaviourRemoved.RemoveListener(delegateOnBehaviourRemoved); for (int i = 0; i < universeObject.BehaviourController.Count; i++) OnBehaviourRemoved(universeObject.BehaviourController, new(universeObject.BehaviourController[i])); } protected virtual void OnBehaviourAdd(IBehaviour behaviour) { } private void OnBehaviourAdded(IBehaviourController controller, IBehaviourController.BehaviourAddedArguments args) { if (args.BehaviourAdded is not T tBehaviour) return; monitoringBehaviours.Add(tBehaviour); monitoringActiveToBehaviour.Add(tBehaviour, tBehaviour); tBehaviour.OnActiveChanged.AddListener(delegateOnBehaviourStateChanged); OnBehaviourStateChanged(tBehaviour, new(!tBehaviour.IsActive)); } protected virtual void AddBehaviour(T behaviour) => activeBehaviours.Add(behaviour); private void OnBehaviourStateChanged(IActive sender, IActive.ActiveChangedArguments args) { T behaviour = monitoringActiveToBehaviour[sender]; if (sender.IsActive) { AddBehaviour(behaviour); OnBehaviourAdd(behaviour); OnCollected?.Invoke(this, new(behaviour)); } else if (activeBehaviours.Remove(behaviour)) { OnBehaviourRemove(behaviour); OnRemoved?.Invoke(this, new(behaviour)); } } protected virtual void OnBehaviourRemove(IBehaviour behaviour) { } private void OnBehaviourRemoved(IBehaviourController controller, IBehaviourController.BehaviourRemovedArguments args) { if (args.BehaviourRemoved is not T tBehaviour) return; if (!monitoringBehaviours.Remove(tBehaviour) || !monitoringActiveToBehaviour.Remove(tBehaviour)) return; tBehaviour.OnActiveChanged.RemoveListener(delegateOnBehaviourStateChanged); if (activeBehaviours.Remove(tBehaviour)) { OnBehaviourRemove(tBehaviour); OnRemoved?.Invoke(this, new(tBehaviour)); } } public bool Assign(IUniverse universe) { if (Universe is not null) return false; foreach (IUniverseObject universeObject in universe.UniverseObjects) OnUniverseObjectRegistered(universe, new(universeObject)); universe.OnUniverseObjectRegistered.AddListener(delegateOnUniverseObjectRegistered); universe.OnUniverseObjectUnRegistered.AddListener(delegateOnUniverseObjectUnregistered); Universe = universe; OnUniverseAssigned?.Invoke(this); return true; } public bool Unassign() { if (Universe is null) return false; foreach (IUniverseObject universeObject in Universe.UniverseObjects) OnUniverseObjectUnregistered(Universe, new(universeObject)); Universe.OnUniverseObjectRegistered.RemoveListener(delegateOnUniverseObjectRegistered); Universe.OnUniverseObjectUnRegistered.RemoveListener(delegateOnUniverseObjectUnregistered); Universe = null!; OnUnassigned?.Invoke(this); return true; } public int Count => activeBehaviours.Count; public T this[Index index] => activeBehaviours[index]; public ActiveBehaviourCollector() { delegateOnBehaviourAdded = OnBehaviourAdded; delegateOnBehaviourRemoved = OnBehaviourRemoved; delegateOnBehaviourStateChanged = OnBehaviourStateChanged; delegateOnUniverseObjectRegistered = OnUniverseObjectRegistered; delegateOnUniverseObjectUnregistered = OnUniverseObjectUnregistered; } public ActiveBehaviourCollector(IUniverse universe) { delegateOnBehaviourAdded = OnBehaviourAdded; delegateOnBehaviourRemoved = OnBehaviourRemoved; delegateOnBehaviourStateChanged = OnBehaviourStateChanged; delegateOnUniverseObjectRegistered = OnUniverseObjectRegistered; delegateOnUniverseObjectUnregistered = OnUniverseObjectUnregistered; Assign(universe); } }