using System.Collections; using System.Collections.Generic; using Syntriax.Engine.Core.Abstract; namespace Syntriax.Engine.Core; [System.Diagnostics.DebuggerDisplay("Name: {Name}, Initialized: {Initialized}")] public class UniverseObject : BaseEntity, IUniverseObject { public event IUniverseObject.EnteredUniverseEventHandler? OnEnteredUniverse = null; public event IUniverseObject.ExitedUniverseEventHandler? OnExitedUniverse = null; public event IUniverseObject.ParentChangedEventHandler? OnParentChanged = null; public event IUniverseObject.ChildrenAddedEventHandler? OnChildrenAdded = null; public event IUniverseObject.ChildrenRemovedEventHandler? OnChildrenRemoved = null; public event IHasBehaviourController.BehaviourControllerAssignedEventHandler? OnBehaviourControllerAssigned = null; public event INameable.NameChangedEventHandler? OnNameChanged = null; public event IActive.ActiveChangedEventHandler? OnActiveChanged = null; private string _name = nameof(UniverseObject); private IUniverse _universe = null!; private IBehaviourController _behaviourController = null!; private bool _isActive = false; private readonly List _children = []; public IUniverseObject? Parent { get; private set; } = null; public IReadOnlyList Children => _children; public IBehaviourController BehaviourController => _behaviourController; public IUniverse Universe => _universe; public bool IsInUniverse => _universe is not null; public bool IsActive => _isActive; public string Name { get => _name; set { if (value == _name) return; string previousName = _name; _name = value; OnNameChanged?.InvokeSafe(this, previousName); } } protected virtual void OnEnteringUniverse(IUniverse universe) { } bool IUniverseObject.EnterUniverse(IUniverse universe) { if (IsInUniverse) return false; _universe = universe; UpdateActive(); OnEnteringUniverse(universe); OnEnteredUniverse?.InvokeSafe(this, universe); return true; } protected virtual void OnExitingUniverse(IUniverse universe) { } bool IUniverseObject.ExitUniverse() { if (!IsInUniverse || _universe is not IUniverse universe) return false; OnExitingUniverse(universe); _universe = null!; OnExitedUniverse?.InvokeSafe(this, universe); return true; } public void SetParent(IUniverseObject? parent) { if (parent == this) throw new Exceptions.AssignFailedException($"{Name} can not parent itself"); if (Parent == parent) return; IUniverseObject? previousParent = Parent; if (previousParent is not null) { previousParent.RemoveChild(this); previousParent.OnActiveChanged -= OnParentActiveChanged; } Parent = parent; if (parent is not null) { if (parent.IsInUniverse && !IsInUniverse) parent.Universe.Register(this); parent.AddChild(this); parent.OnActiveChanged += OnParentActiveChanged; } UpdateActive(); OnParentChanged?.InvokeSafe(this, previousParent, parent); } public void AddChild(IUniverseObject parent) { if (_children.Contains(parent)) return; _children.Add(parent); parent.SetParent(this); OnChildrenAdded?.InvokeSafe(this, parent); } public void RemoveChild(IUniverseObject child) { if (!_children.Remove(child)) return; child.SetParent(null); OnChildrenRemoved?.InvokeSafe(this, child); } protected virtual void OnAssign(IBehaviourController behaviourController) { } public bool Assign(IBehaviourController behaviourController) { if (IsInitialized) return false; _behaviourController = behaviourController; OnAssign(behaviourController); OnBehaviourControllerAssigned?.InvokeSafe(this); return true; } protected override void OnAssign(IStateEnable stateEnable) { base.OnAssign(stateEnable); stateEnable.OnEnabledChanged += OnStateEnabledChanged; } private void OnParentActiveChanged(IActive sender, bool previousState) => UpdateActive(); private void OnStateEnabledChanged(IStateEnable sender, bool previousState) => UpdateActive(); private void UpdateActive() { bool previousActive = IsActive; _isActive = StateEnable.Enabled && (Parent?.IsActive ?? true); if (previousActive != IsActive) OnActiveChanged?.InvokeSafe(this, previousActive); } protected override void UnassignInternal() { base.UnassignInternal(); StateEnable.OnEnabledChanged -= OnStateEnabledChanged; } protected override void InitializeInternal() { base.InitializeInternal(); _behaviourController ??= Factory.BehaviourControllerFactory.Instantiate(this); } public UniverseObject() { _name = GetType().Name; } public IEnumerator GetEnumerator() => _children.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _children.GetEnumerator(); }