namespace Syntriax.Engine.Core; [System.Diagnostics.DebuggerDisplay("{GetType().Name, nq}, Priority: {Priority}, Initialized: {Initialized}")] public abstract class BehaviourBase : BaseEntity, IBehaviour { public Event OnPriorityChanged { get; } = new(); public Event OnActiveChanged { get; } = new(); public Event OnBehaviourControllerAssigned { get; } = new(); private readonly Event.EventHandler delegateOnUniverseObjectAssigned = null!; private readonly Event.EventHandler delegateOnUniverseObjectActiveChanged = null!; private readonly Event.EventHandler delegateOnStateEnabledChanged = null!; public IUniverse Universe => BehaviourController.UniverseObject.Universe; public IUniverseObject UniverseObject => BehaviourController.UniverseObject; private IBehaviourController _behaviourController = null!; public IBehaviourController BehaviourController => _behaviourController; private int _priority = 0; public int Priority { get => _priority; set { if (value == _priority) return; int previousPriority = _priority; _priority = value; OnPriorityChanged?.Invoke(this, new(previousPriority)); } } private bool _isActive = false; public bool IsActive => _isActive; protected virtual void OnAssign(IBehaviourController behaviourController) { } public bool Assign(IBehaviourController behaviourController) { if (IsInitialized) return false; _behaviourController = behaviourController; OnAssign(behaviourController); behaviourController.OnUniverseObjectAssigned.AddListener(delegateOnUniverseObjectAssigned); if (behaviourController.UniverseObject is not null) OnUniverseObjectAssigned(behaviourController); OnBehaviourControllerAssigned?.Invoke(this); return true; } private void OnUniverseObjectAssigned(IHasUniverseObject sender) { sender.UniverseObject.OnActiveChanged.AddListener(delegateOnUniverseObjectActiveChanged); UpdateActive(); } protected override void OnAssign(IStateEnable stateEnable) { base.OnAssign(stateEnable); stateEnable.OnEnabledChanged.AddListener(delegateOnStateEnabledChanged); } protected override void UnassignInternal() { BehaviourController.UniverseObject.OnActiveChanged.RemoveListener(delegateOnUniverseObjectActiveChanged); StateEnable.OnEnabledChanged.RemoveListener(delegateOnStateEnabledChanged); BehaviourController.OnUniverseObjectAssigned.RemoveListener(delegateOnUniverseObjectAssigned); base.UnassignInternal(); _behaviourController = null!; } protected override void InitializeInternal() { Debug.Assert.AssertBehaviourControllerAssigned(this); Debug.Assert.AssertStateEnableAssigned(this); } private void OnStateEnabledChanged(IStateEnable sender, IStateEnable.EnabledChangedArguments args) => UpdateActive(); private void OnUniverseObjectActiveChanged(IActive sender, IActive.ActiveChangedArguments args) => UpdateActive(); private void UpdateActive() { bool previousActive = IsActive; _isActive = StateEnable.Enabled && _behaviourController.UniverseObject.IsActive; if (previousActive != IsActive) OnActiveChanged?.Invoke(this, new(previousActive)); } protected BehaviourBase() { delegateOnUniverseObjectAssigned = OnUniverseObjectAssigned; delegateOnUniverseObjectActiveChanged = OnUniverseObjectActiveChanged; delegateOnStateEnabledChanged = OnStateEnabledChanged; } }