Syntriax.Engine/Engine.Core/BehaviourBase.cs
2025-05-30 18:37:35 +03:00

97 lines
3.7 KiB
C#

namespace Syntriax.Engine.Core;
[System.Diagnostics.DebuggerDisplay("{GetType().Name, nq}, Priority: {Priority}, Initialized: {Initialized}")]
public abstract class BehaviourBase : BaseEntity, IBehaviour
{
public Event<IBehaviour, IBehaviour.PriorityChangedArguments> OnPriorityChanged { get; init; } = new();
public Event<IActive, IActive.ActiveChangedArguments> OnActiveChanged { get; init; } = new();
public Event<IHasBehaviourController> OnBehaviourControllerAssigned { get; init; } = new();
private readonly Event<IHasUniverseObject>.EventHandler cachedOnUniverseObjectAssigned = null!;
private readonly Event<IActive, IActive.ActiveChangedArguments>.EventHandler cachedOnUniverseObjectActiveChanged = null!;
private readonly Event<IStateEnable, IStateEnable.EnabledChangedArguments>.EventHandler 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, 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(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, IStateEnable.EnabledChangedArguments arguments) => UpdateActive();
private void OnUniverseObjectActiveChanged(IActive sender, IActive.ActiveChangedArguments arguments) => UpdateActive();
private void UpdateActive()
{
bool previousActive = IsActive;
_isActive = StateEnable.Enabled && _behaviourController.UniverseObject.IsActive;
if (previousActive != IsActive)
OnActiveChanged?.Invoke(this, new(previousActive));
}
protected BehaviourBase()
{
cachedOnUniverseObjectAssigned = OnUniverseObjectAssigned;
cachedOnUniverseObjectActiveChanged = OnUniverseObjectActiveChanged;
cachedOnStateEnabledChanged = OnStateEnabledChanged;
}
}