using System.Collections.Generic; namespace Engine.Core; public class UniverseEntranceManager : Internal.BehaviourIndependent { // We use Ascending order because we are using reverse for loop to call them private static Comparer SortByAscendingPriority() => Comparer.Create((x, y) => x.CompareTo(y)); private static System.Func GetPriority() => (b) => b.Priority; private readonly ActiveBehaviourCollectorOrdered enterUniverses = new(GetPriority(), SortByAscendingPriority()); private readonly ActiveBehaviourCollectorOrdered exitUniverses = new(GetPriority(), SortByAscendingPriority()); private readonly List toCallEnterUniverses = new(32); private readonly List toCallExitUniverses = new(32); protected override void OnEnteredUniverse(IUniverse universe) { // FIXME: This causes an issue when the UniverseEntranceManager is already attached to a UniverseObject then registered into a Universe, // the enter/exit universe collectors call OnUniverseObjectRegistered internally on Assign, but since the Universe calls the OnUniverseObjectRegistered // event it tries to call OnUniverseObjectRegistered again on the same object, causing a duplicate entry error. Debug.Assert.AssertTrue(BehaviourController.Count == 1, $"{nameof(UniverseEntranceManager)} must be in it's own {nameof(IUniverseObject)} with no other {nameof(IBehaviour)}s attached at the moment. Failing to do so might cause instantiation or serialization issues."); enterUniverses.Assign(universe); exitUniverses.Assign(universe); foreach (IUniverseObject universeObject in universe.UniverseObjects) OnUniverseObjectRegistered(universe, new(universeObject)); universe.OnUniverseObjectRegistered.AddListener(OnUniverseObjectRegistered); universe.OnUniverseObjectUnRegistered.AddListener(OnUniverseObjectUnRegistered); } protected override void OnExitedUniverse(IUniverse universe) { enterUniverses.Unassign(); exitUniverses.Unassign(); foreach (IUniverseObject universeObject in universe.UniverseObjects) OnUniverseObjectUnRegistered(universe, new(universeObject)); universe.OnUniverseObjectRegistered.RemoveListener(OnUniverseObjectRegistered); universe.OnUniverseObjectUnRegistered.RemoveListener(OnUniverseObjectUnRegistered); } private void OnUniverseObjectUnRegistered(IUniverse sender, IUniverse.UniverseObjectUnRegisteredArguments args) { for (int i = toCallExitUniverses.Count - 1; i >= 0; i--) { IExitUniverse exitUniverse = toCallExitUniverses[i]; toCallExitUniverses.RemoveAt(i); exitUniverse.ExitUniverse(Universe); } } private void OnUniverseObjectRegistered(IUniverse sender, IUniverse.UniverseObjectRegisteredArguments args) { for (int i = toCallEnterUniverses.Count - 1; i >= 0; i--) { IEnterUniverse enterUniverse = toCallEnterUniverses[i]; toCallEnterUniverses.RemoveAt(i); enterUniverse.EnterUniverse(Universe); } } private void OnEnterUniverseCollected(IBehaviourCollector sender, IBehaviourCollector.BehaviourCollectedArguments args) { toCallEnterUniverses.Add(args.BehaviourCollected); } private void OnExitUniverseCollected(IBehaviourCollector sender, IBehaviourCollector.BehaviourCollectedArguments args) { toCallExitUniverses.Add(args.BehaviourCollected); } public UniverseEntranceManager() { enterUniverses.OnCollected.AddListener(OnEnterUniverseCollected); exitUniverses.OnCollected.AddListener(OnExitUniverseCollected); } }