using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using Syntriax.Engine.Core.Abstract; namespace Syntriax.Engine.Core; [System.Diagnostics.DebuggerDisplay("Behaviour Count: {behaviours.Count}")] public class BehaviourController : IBehaviourController { public event IBehaviourController.OnPreUpdateDelegate? OnPreUpdate = null; public event IBehaviourController.OnUpdateDelegate? OnUpdate = null; public event IBehaviourController.OnPreDrawDelegate? OnPreDraw = null; public event IBehaviourController.OnBehaviourAddedDelegate? OnBehaviourAdded = null; public event IBehaviourController.OnBehaviourRemovedDelegate? OnBehaviourRemoved = null; public event IAssignable.OnUnassignedDelegate? OnUnassigned; public event IAssignableGameObject.OnGameObjectAssignedDelegate? OnGameObjectAssigned = null; private readonly IList behaviours = new List(Constants.BEHAVIOURS_SIZE_INITIAL); private IGameObject _gameObject = null!; public IGameObject GameObject => _gameObject; public T AddBehaviour(T behaviour) where T : class, IBehaviour { InsertBehaviourByPriority(behaviour); behaviour.Assign(this); behaviour.Assign(GameObject.StateEnable); behaviour.Initialize(); behaviour.OnPriorityChanged += OnPriorityChange; OnBehaviourAdded?.Invoke(this, behaviour); return behaviour; } public T AddBehaviour(params object?[]? args) where T : class, IBehaviour => AddBehaviour(new Factory.BehaviourFactory().Instantiate(_gameObject, args)); public T? GetBehaviour() { foreach (var behaviourItem in behaviours) if (behaviourItem is T result) return result; return default; } public bool TryGetBehaviour([NotNullWhen(returnValue: true)] out T? behaviour) { behaviour = GetBehaviour(); return behaviour is not null; } public IList GetBehaviours() { List? behaviours = null; foreach (var behaviourItem in this.behaviours) { if (behaviourItem is not T behaviour) continue; behaviours ??= []; behaviours.Add(behaviour); } return behaviours ?? Enumerable.Empty().ToList(); } public void GetBehaviours(List behaviors) { behaviors.Clear(); foreach (var behaviourItem in behaviours) { if (behaviourItem is not T _) continue; behaviours.Add(behaviourItem); } } 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 {GameObject.Name}'s {nameof(IBehaviourController)}."); behaviour.OnPriorityChanged -= OnPriorityChange; behaviour.Finalize(); behaviours.Remove(behaviour); OnBehaviourRemoved?.Invoke(this, behaviour); } public bool Assign(IGameObject gameObject) { if (GameObject is not null && GameObject.IsInitialized) return false; _gameObject = gameObject; OnGameObjectAssigned?.Invoke(this); return true; } public bool Unassign() { if (GameObject is not null && GameObject.IsInitialized) return false; _gameObject = null!; OnUnassigned?.Invoke(this); return true; } public void Update() { if (!GameObject.StateEnable.Enabled) return; OnPreUpdate?.Invoke(this); OnUpdate?.Invoke(this); } public void UpdatePreDraw() { if (!GameObject.StateEnable.Enabled) return; OnPreDraw?.Invoke(this); } public BehaviourController() { } public BehaviourController(IGameObject gameObject) => Assign(gameObject); 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(); }