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 bool isInitialCollectionDone = false; private readonly FastListOrdered toCallEnterUniverses = new(GetPriority(), SortByAscendingPriority()); protected override void OnEnteredUniverse(IUniverse universe) { exitUniverses.Assign(universe); // FIXME: the isInitialCollectionDone is for the sole reason of some behaviours // adding more behaviours during entrance calls and the internal workings of // behaviour collector not being able to tell which behaviour was already called // (because it just runs a for loop with the behaviour count, and priority ordering doesn't help as well) // so it sometimes double processes or misses behaviours. A more elegant way of // handling this would be nice but for now it works good enough. // // SIDE NOTE: This same issue has the potential to occur on exitUniverses as well, but I've yet to run // into an instance of it actually happening so... I'm not gonna touch it until the edge case happens. isInitialCollectionDone = false; enterUniverses.Assign(universe); isInitialCollectionDone = true; for (int i = toCallEnterUniverses.Count - 1; i >= 0; i--) toCallEnterUniverses[i].EnterUniverse(universe); toCallEnterUniverses.Clear(); } protected override void OnExitedUniverse(IUniverse universe) { enterUniverses.Unassign(); exitUniverses.Unassign(); } private void OnEnterUniverseCollected(IBehaviourCollector sender, IBehaviourCollector.BehaviourCollectedArguments args) { if (!isInitialCollectionDone) { toCallEnterUniverses.Add(args.BehaviourCollected); return; } args.BehaviourCollected.EnterUniverse(Universe); } private void OnExitUniverseRemoved(IBehaviourCollector sender, IBehaviourCollector.BehaviourRemovedArguments args) => args.BehaviourRemoved.ExitUniverse(Universe); public UniverseEntranceManager() { enterUniverses.OnCollected.AddListener(OnEnterUniverseCollected); exitUniverses.OnRemoved.AddListener(OnExitUniverseRemoved); } }