Syntriax.Engine/Engine.Core/BehaviourController.cs
Syntriax 61e2761580 perf!: events refactored throughout all the project to use Event<> class
All delegate events are refactored to use the Event<TSender> and Event<TSender, TArgument> for performance issues regarding delegate events creating garbage, also this gives us better control on event invocation since C# Delegates did also create unnecessary garbage during Delegate.DynamicInvoke
2025-05-31 00:32:58 +03:00

155 lines
4.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
namespace Syntriax.Engine.Core;
[System.Diagnostics.DebuggerDisplay("Behaviour Count: {behaviours.Count}")]
public class BehaviourController : BaseEntity, IBehaviourController
{
public Event<IBehaviourController, IBehaviourController.BehaviourAddedArguments> OnBehaviourAdded { get; } = new();
public Event<IBehaviourController, IBehaviourController.BehaviourRemovedArguments> OnBehaviourRemoved { get; } = new();
public Event<IHasUniverseObject> OnUniverseObjectAssigned { get; } = new();
private readonly List<IBehaviour> behaviours = new(Constants.BEHAVIOURS_SIZE_INITIAL);
private IUniverseObject _universeObject = null!;
public IUniverseObject UniverseObject => _universeObject;
public int Count => behaviours.Count;
public IBehaviour this[Index index] => behaviours[index];
public T AddBehaviour<T>(T behaviour) where T : class, IBehaviour
{
InsertBehaviourByPriority(behaviour);
behaviour.Assign(this);
if (IsInitialized)
behaviour.Initialize();
behaviour.OnPriorityChanged.AddListener(OnPriorityChange);
OnBehaviourAdded?.Invoke(this, new(behaviour));
return behaviour;
}
public T AddBehaviour<T>(params object?[]? args) where T : class, IBehaviour
{
T behaviour = Factory.BehaviourFactory.Instantiate<T>(args);
return AddBehaviour(behaviour);
}
public T? GetBehaviour<T>()
{
foreach (IBehaviour behaviourItem in behaviours)
if (behaviourItem is T result)
return result;
return default;
}
public IReadOnlyList<T> GetBehaviours<T>()
{
List<T>? behaviours = null;
foreach (IBehaviour behaviourItem in this.behaviours)
{
if (behaviourItem is not T behaviour)
continue;
behaviours ??= [];
behaviours.Add(behaviour);
}
return behaviours ?? Enumerable.Empty<T>().ToList();
}
public void GetBehaviours<T>(IList<T> results)
{
results.Clear();
foreach (IBehaviour behaviourItem in behaviours)
{
if (behaviourItem is not T behaviour)
continue;
results.Add(behaviour);
}
}
public void RemoveBehaviour<T>(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>(T behaviour) where T : class, IBehaviour
{
if (!behaviours.Contains(behaviour))
throw new Exception($"{behaviour.GetType().Name} does not exist in {UniverseObject.Name}'s {nameof(IBehaviourController)}.");
behaviour.OnPriorityChanged.RemoveListener(OnPriorityChange);
behaviour.Finalize();
behaviours.Remove(behaviour);
OnBehaviourRemoved?.Invoke(this, new(behaviour));
}
protected virtual void OnAssign(IUniverseObject universeObject) { }
public bool Assign(IUniverseObject universeObject)
{
if (UniverseObject is not null && UniverseObject.IsInitialized)
return false;
_universeObject = universeObject;
OnAssign(universeObject);
OnUniverseObjectAssigned?.Invoke(this);
return true;
}
protected override void InitializeInternal()
{
Debug.Assert.AssertUniverseObjectAssigned(this);
foreach (IBehaviour behaviour in behaviours)
behaviour.Initialize();
}
protected override void FinalizeInternal()
{
foreach (IBehaviour behaviour in behaviours)
behaviour.Finalize();
}
public BehaviourController() { }
public BehaviourController(IUniverseObject universeObject) => Assign(universeObject);
private void InsertBehaviourByPriority<T>(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, IBehaviour.PriorityChangedArguments args)
{
behaviours.Remove(sender);
InsertBehaviourByPriority(sender);
}
}