using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Core.Exceptions; namespace Syntriax.Engine.Core; [System.Diagnostics.DebuggerDisplay("Behaviour Count: {behaviours.Count}")] public class BehaviourController : IBehaviourController { public event IBehaviourController.PreUpdateEventHandler? OnPreUpdate = null; public event IBehaviourController.UpdateEventHandler? OnUpdate = null; public event IBehaviourController.PreDrawEventHandler? OnPreDraw = null; public event IBehaviourController.BehaviourAddedEventHandler? OnBehaviourAdded = null; public event IBehaviourController.BehaviourRemovedEventHandler? OnBehaviourRemoved = null; public event IHasHierarchyObject.HierarchyObjectAssignedEventHandler? OnHierarchyObjectAssigned = null; public event IInitializable.InitializedEventHandler? OnInitialized = null; public event IInitializable.FinalizedEventHandler? OnFinalized = null; public event IAssignable.UnassignEventHandler? OnUnassigned = null; private readonly IList behaviours = new List(Constants.BEHAVIOURS_SIZE_INITIAL); private IHierarchyObject _hierarchyObject = null!; private bool _initialized = false; public IHierarchyObject HierarchyObject => _hierarchyObject; public bool IsInitialized { get => _initialized; private set { if (value == _initialized) return; _initialized = value; if (value) OnInitialized?.Invoke(this); else OnFinalized?.Invoke(this); } } public T AddBehaviour(T behaviour) where T : class, IBehaviour { InsertBehaviourByPriority(behaviour); behaviour.Assign(this); behaviour.Assign(Factory.StateEnableFactory.Instantiate(behaviour)); behaviour.Initialize(); behaviour.OnPriorityChanged += OnPriorityChange; OnBehaviourAdded?.Invoke(this, behaviour); return behaviour; } public T AddBehaviour(params object?[]? args) where T : class, IBehaviour => AddBehaviour(Factory.BehaviourFactory.Instantiate(_hierarchyObject, args)); public T? GetBehaviour() { foreach (IBehaviour behaviourItem in behaviours) if (behaviourItem is T result) return result; return default; } public IList GetBehaviours() { List? behaviours = null; foreach (IBehaviour behaviourItem in this.behaviours) { if (behaviourItem is not T behaviour) continue; behaviours ??= []; behaviours.Add(behaviour); } return behaviours ?? Enumerable.Empty().ToList(); } public void GetBehaviours(IList results) { results.Clear(); foreach (IBehaviour behaviourItem in behaviours) { if (behaviourItem is not T behaviour) continue; results.Add(behaviour); } } public void RemoveBehaviour(bool removeAll = false) where T : class, IBehaviour { for (int i = behaviours.Count; i >= 0; i--) { if (behaviours[i] is not T behaviour) continue; RemoveBehaviour(behaviour); if (!removeAll) return; } } public void RemoveBehaviour(T behaviour) where T : class, IBehaviour { if (!behaviours.Contains(behaviour)) throw new Exception($"{behaviour.GetType().Name} does not exist in {HierarchyObject.Name}'s {nameof(IBehaviourController)}."); behaviour.OnPriorityChanged -= OnPriorityChange; behaviour.Finalize(); behaviours.Remove(behaviour); OnBehaviourRemoved?.Invoke(this, behaviour); } public bool Assign(IHierarchyObject hierarchyObject) { if (HierarchyObject is not null && HierarchyObject.IsInitialized) return false; _hierarchyObject = hierarchyObject; OnHierarchyObjectAssigned?.Invoke(this); return true; } public bool Initialize() { if (IsInitialized) return false; NotAssignedException.Check(this, _hierarchyObject); foreach (IBehaviour behaviour in behaviours) behaviour.Initialize(); IsInitialized = true; return true; } public bool Finalize() { if (!IsInitialized) return false; foreach (IBehaviour behaviour in behaviours) behaviour.Finalize(); IsInitialized = false; return true; } public bool Unassign() { if (IsInitialized) return false; _hierarchyObject = null!; OnUnassigned?.Invoke(this); return true; } public void Update() { if (!HierarchyObject.StateEnable.Enabled) return; OnPreUpdate?.Invoke(this); OnUpdate?.Invoke(this); } public void UpdatePreDraw() { if (!HierarchyObject.StateEnable.Enabled) return; OnPreDraw?.Invoke(this); } public BehaviourController() { } public BehaviourController(IHierarchyObject hierarchyObject) => Assign(hierarchyObject); private void InsertBehaviourByPriority(T behaviour) where T : class, IBehaviour { int i; for (i = 0; i < behaviours.Count; i++) { if (behaviours[i].Priority > behaviour.Priority) continue; behaviours.Insert(i, behaviour); return; } if (i == 0 || i == behaviours.Count) behaviours.Add(behaviour); } private void OnPriorityChange(IBehaviour sender, int previousPriority) { behaviours.Remove(sender); InsertBehaviourByPriority(sender); } public IEnumerator GetEnumerator() => behaviours.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => behaviours.GetEnumerator(); }