150 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.Collections.Generic;
 | 
						|
 | 
						|
namespace 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 FastList<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 = [];
 | 
						|
 | 
						|
        foreach (IBehaviour behaviourItem in this.behaviours)
 | 
						|
            if (behaviourItem is T behaviour)
 | 
						|
                behaviours.Add(behaviour);
 | 
						|
 | 
						|
        return behaviours;
 | 
						|
    }
 | 
						|
 | 
						|
    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 - 1; 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);
 | 
						|
    }
 | 
						|
}
 |