using System; namespace Syntriax.Engine.Core; [System.Diagnostics.DebuggerDisplay("{GetType().Name, nq}, Priority: {Priority}, Initialized: {Initialized}")] public abstract class BehaviourBase : BaseEntity, IBehaviour { public Event OnPriorityChanged { get; private set; } = new(); public Event OnActiveChanged { get; private set; } = new(); public Event OnBehaviourControllerAssigned { get; private set; } = new(); private Action cachedOnUniverseObjectAssigned = null!; private Action cachedOnUniverseObjectActiveChanged = null!; private Action cachedOnStateEnabledChanged = null!; 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, 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(cachedOnUniverseObjectAssigned); if (behaviourController.UniverseObject is not null) OnUniverseObjectAssigned(behaviourController); OnBehaviourControllerAssigned?.Invoke(this); return true; } private void OnUniverseObjectAssigned(IHasUniverseObject sender) { sender.UniverseObject.OnActiveChanged.AddListener(cachedOnUniverseObjectActiveChanged); UpdateActive(); } protected override void OnAssign(IStateEnable stateEnable) { base.OnAssign(stateEnable); stateEnable.OnEnabledChanged.AddListener(cachedOnStateEnabledChanged); } protected override void UnassignInternal() { BehaviourController.UniverseObject.OnActiveChanged.RemoveListener(cachedOnUniverseObjectActiveChanged); StateEnable.OnEnabledChanged.RemoveListener(cachedOnStateEnabledChanged); BehaviourController.OnUniverseObjectAssigned.RemoveListener(cachedOnUniverseObjectAssigned); base.UnassignInternal(); _behaviourController = null!; } protected override void InitializeInternal() { Debug.Assert.AssertBehaviourControllerAssigned(this); Debug.Assert.AssertStateEnableAssigned(this); } private void OnStateEnabledChanged(IStateEnable sender, bool previousState) => UpdateActive(); private void OnUniverseObjectActiveChanged(IActive sender, bool previousState) => UpdateActive(); private void UpdateActive() { bool previousActive = IsActive; _isActive = StateEnable.Enabled && _behaviourController.UniverseObject.IsActive; if (previousActive != IsActive) OnActiveChanged?.Invoke(this, previousActive); } protected BehaviourBase() { cachedOnUniverseObjectAssigned = OnUniverseObjectAssigned; cachedOnUniverseObjectActiveChanged = OnUniverseObjectActiveChanged; cachedOnStateEnabledChanged = OnStateEnabledChanged; } }