using System; using System.Collections; using System.Collections.Generic; using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Core.Exceptions; using Syntriax.Engine.Core.Factory; namespace Syntriax.Engine.Core; [System.Diagnostics.DebuggerDisplay("HierarchyObject Count: {_hierarchyObjects.Count}")] public class GameManager : BaseEntity, IGameManager { public event IGameManager.UpdateEventHandler? OnUpdate = null; public event IGameManager.PreDawEventHandler? OnPreDraw = null; public event IGameManager.HierarchyObjectRegisteredEventHandler? OnHierarchyObjectRegistered = null; public event IGameManager.HierarchyObjectUnRegisteredEventHandler? OnHierarchyObjectUnRegistered = null; private readonly List _hierarchyObjects = new(Constants.GAME_OBJECTS_SIZE_INITIAL); private HierarchyObjectFactory _hierarchyObjectFactory = null!; private HierarchyObjectFactory HierarchyObjectFactory { get { _hierarchyObjectFactory ??= new HierarchyObjectFactory(); return _hierarchyObjectFactory; } } public IReadOnlyList HierarchyObjects => _hierarchyObjects; public override IStateEnable StateEnable { get { if (base.StateEnable is null) { Assign(new StateEnableFactory().Instantiate(this)); if (base.StateEnable is null) throw NotAssignedException.From(this, base.StateEnable); } return base.StateEnable; } } public EngineTime Time { get; private set; } = new(); public void Register(IHierarchyObject hierarchyObject) { if (_hierarchyObjects.Contains(hierarchyObject)) throw new Exception($"{nameof(IHierarchyObject)} named {hierarchyObject.Name} is already registered to the {nameof(GameManager)}."); hierarchyObject.OnFinalized += OnHierarchyObjectFinalize; hierarchyObject.OnExitedHierarchy += OnHierarchyObjectExitedHierarchy; if (!hierarchyObject.Initialize()) throw new Exception($"{hierarchyObject.Name} can't be initialized"); foreach (IHierarchyObject child in hierarchyObject.Children) Register(child); _hierarchyObjects.Add(hierarchyObject); if (!hierarchyObject.EnterHierarchy(this)) throw new Exception($"{hierarchyObject.Name} can't enter the hierarchy"); OnHierarchyObjectRegistered?.Invoke(this, hierarchyObject); } public T InstantiateHierarchyObject(params object?[]? args) where T : class, IHierarchyObject { T hierarchyObject = HierarchyObjectFactory.Instantiate(args); Register(hierarchyObject); return hierarchyObject; } public void Remove(IHierarchyObject hierarchyObject) { if (!_hierarchyObjects.Contains(hierarchyObject)) throw new Exception($"{nameof(IHierarchyObject)} named {hierarchyObject.Name} is not registered to the {nameof(GameManager)}."); hierarchyObject.OnFinalized -= OnHierarchyObjectFinalize; hierarchyObject.OnExitedHierarchy -= OnHierarchyObjectExitedHierarchy; foreach (IHierarchyObject child in hierarchyObject.Children) Remove(child); _hierarchyObjects.Remove(hierarchyObject); if (!hierarchyObject.ExitHierarchy()) throw new Exception($"{hierarchyObject.Name} can't exit the hierarchy"); if (!hierarchyObject.Finalize()) throw new Exception($"{hierarchyObject.Name} can't be finalized"); OnHierarchyObjectUnRegistered?.Invoke(this, hierarchyObject); } protected override void InitializeInternal() { base.InitializeInternal(); NotAssignedException.Check(this, StateEnable); foreach (IHierarchyObject hierarchyObject in HierarchyObjects) hierarchyObject.Initialize(); } protected override void FinalizeInternal() { base.FinalizeInternal(); for (int i = HierarchyObjects.Count; i >= 0; i--) HierarchyObjects[i].Finalize(); } public void Update(EngineTime engineTime) { Time = engineTime; for (int i = 0; i < HierarchyObjects.Count; i++) HierarchyObjects[i].BehaviourController.Update(); OnUpdate?.Invoke(this, engineTime); } public void PreDraw() { for (int i = 0; i < HierarchyObjects.Count; i++) HierarchyObjects[i].BehaviourController.UpdatePreDraw(); OnPreDraw?.Invoke(this); } private void OnHierarchyObjectFinalize(IInitializable initializable) { if (initializable is IHierarchyObject hierarchyObject) Remove(hierarchyObject); } private void OnHierarchyObjectExitedHierarchy(IHierarchyObject sender, IGameManager gameManager) { if (sender is IHierarchyObject hierarchyObject) Remove(hierarchyObject); } public IEnumerator GetEnumerator() => _hierarchyObjects.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _hierarchyObjects.GetEnumerator(); }