183 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			183 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System.Collections.Generic;
 | 
						|
using System.Diagnostics.CodeAnalysis;
 | 
						|
 | 
						|
using Engine.Core.Exceptions;
 | 
						|
 | 
						|
namespace Engine.Core;
 | 
						|
 | 
						|
public static class BehaviourControllerExtensions
 | 
						|
{
 | 
						|
    /// <summary>
 | 
						|
    /// Tries to get a <see cref="IBehaviour"/> of the specified type.
 | 
						|
    /// </summary>
 | 
						|
    /// <typeparam name="T">The type of <see cref="IBehaviour"/> to get.</typeparam>
 | 
						|
    /// <param name="behaviourController">The <see cref="IBehaviourController"/> to search in.</param>
 | 
						|
    /// <param name="behaviour">When this method returns, contains the <see cref="IBehaviour"/> of the specified type, if found; otherwise, null.</param>
 | 
						|
    /// <returns><see cref="true"/> if a <see cref="IBehaviour"/> of the specified type was found; otherwise, <see cref="false"/>.</returns>
 | 
						|
    public static bool TryGetBehaviour<T>(this IBehaviourController behaviourController, [NotNullWhen(returnValue: true)] out T? behaviour)
 | 
						|
    {
 | 
						|
        behaviour = behaviourController.GetBehaviour<T>();
 | 
						|
        return behaviour is not null;
 | 
						|
    }
 | 
						|
 | 
						|
    /// <summary>
 | 
						|
    /// Gets a <see cref="IBehaviour"/> of the specified type in the provided <see cref="IBehaviourController"/>. Throws an error if not found.
 | 
						|
    /// </summary>
 | 
						|
    /// <typeparam name="T">The type of <see cref="IBehaviour"/> to get.</typeparam>
 | 
						|
    /// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param>
 | 
						|
    /// <returns>The <see cref="IBehaviour"/> of the specified type if found; otherwise, throws <see cref="BehaviourNotFoundException"/>.</returns>
 | 
						|
    public static T GetRequiredBehaviour<T>(this IBehaviourController behaviourController) where T : class
 | 
						|
        => behaviourController.GetBehaviour<T>() ?? throw new BehaviourNotFoundException($"{behaviourController.UniverseObject?.Name ?? "NULL"}'s {nameof(IBehaviourController)} does not contain any {typeof(T).FullName}");
 | 
						|
 | 
						|
    /// <summary>
 | 
						|
    /// Gets an existing <see cref="IBehaviour"/> of the specified type, or adds and returns a new one if it doesn't exist.
 | 
						|
    /// </summary>
 | 
						|
    /// <typeparam name="T">The type of <see cref="IBehaviour"/> to get or add.</typeparam>
 | 
						|
    /// <param name="behaviourController">The <see cref="IBehaviourController"/> to search in.</param>
 | 
						|
    /// <param name="args">Optional arguments to pass to the constructor of the <see cref="IBehaviour"/> if a new one is added.</param>
 | 
						|
    /// <returns>The existing or newly added <see cref="IBehaviour"/> of the specified type.</returns>
 | 
						|
    public static T GetOrAddBehaviour<T>(this IBehaviourController behaviourController, params object?[]? args) where T : class, IBehaviour
 | 
						|
        => behaviourController.GetBehaviour<T>() ?? behaviourController.AddBehaviour<T>(args);
 | 
						|
 | 
						|
    /// <summary>
 | 
						|
    /// Gets an existing <see cref="IBehaviour"/> of the specified type, or adds and returns the fallback type if it doesn't exist.
 | 
						|
    /// </summary>
 | 
						|
    /// <typeparam name="TOriginal">The type of <see cref="IBehaviour"/> to get.</typeparam>
 | 
						|
    /// <typeparam name="TFallback">The type of <see cref="IBehaviour"/> to add. It must be assignable from <typeparamref name="TOriginal"/></typeparam>
 | 
						|
    /// <param name="behaviourController">The <see cref="IBehaviourController"/> to search in.</param>
 | 
						|
    /// <param name="args">Optional arguments to pass to the constructor of the <see cref="IBehaviour"/> if a new one is added.</param>
 | 
						|
    /// <returns>The existing or newly added <see cref="IBehaviour"/> of the specified type.</returns>
 | 
						|
    public static TOriginal GetOrAddBehaviour<TOriginal, TFallback>(this IBehaviourController behaviourController, params object?[]? args)
 | 
						|
            where TOriginal : class
 | 
						|
            where TFallback : class, IBehaviour, TOriginal
 | 
						|
        => behaviourController.GetBehaviour<TOriginal>() ?? behaviourController.AddBehaviour<TFallback>(args);
 | 
						|
 | 
						|
    /// <summary>
 | 
						|
    /// Tries to get a <see cref="IBehaviour"/> of the specified type in it's <see cref="IUniverseObject"/>'s parents recursively.
 | 
						|
    /// </summary>
 | 
						|
    /// <typeparam name="T">The type of <see cref="IBehaviour"/> to get.</typeparam>
 | 
						|
    /// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param>
 | 
						|
    /// <param name="behaviour">When this method returns, contains the <see cref="IBehaviour"/> of the specified type, if found; otherwise, null.</param>
 | 
						|
    /// <returns><see cref="true"/> if a <see cref="IBehaviour"/> of the specified type was found in the parent universe; otherwise, <see cref="false"/>.</returns>
 | 
						|
    public static bool TryGetBehaviourInParent<T>(this IBehaviourController behaviourController, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class
 | 
						|
    {
 | 
						|
        behaviour = GetBehaviourInParent<T>(behaviourController);
 | 
						|
        return behaviour is not null;
 | 
						|
    }
 | 
						|
 | 
						|
    /// <summary>
 | 
						|
    /// Gets a <see cref="IBehaviour"/> of the specified type in it's <see cref="IUniverseObject"/>'s parents recursively.
 | 
						|
    /// </summary>
 | 
						|
    /// <typeparam name="T">The type of <see cref="IBehaviour"/> to get.</typeparam>
 | 
						|
    /// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param>
 | 
						|
    /// <returns>The <see cref="IBehaviour"/> of the specified type if found; otherwise, null.</returns>
 | 
						|
    public static T? GetBehaviourInParent<T>(this IBehaviourController behaviourController) where T : class
 | 
						|
    {
 | 
						|
        IBehaviourController? controller = behaviourController;
 | 
						|
 | 
						|
        while (controller is not null)
 | 
						|
        {
 | 
						|
            if (controller.GetBehaviour<T>() is T behaviour)
 | 
						|
                return behaviour;
 | 
						|
 | 
						|
            controller = controller.UniverseObject.Parent?.BehaviourController;
 | 
						|
        }
 | 
						|
 | 
						|
        return default;
 | 
						|
    }
 | 
						|
 | 
						|
    /// <summary>
 | 
						|
    /// Gets a <see cref="IBehaviour"/> of the specified type in it's <see cref="IUniverseObject"/>'s parents recursively. Throws an error if not found.
 | 
						|
    /// </summary>
 | 
						|
    /// <typeparam name="T">The type of <see cref="IBehaviour"/> to get.</typeparam>
 | 
						|
    /// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param>
 | 
						|
    /// <returns>The <see cref="IBehaviour"/> of the specified type if found; otherwise, throws <see cref="BehaviourNotFoundException"/>.</returns>
 | 
						|
    public static T GetRequiredBehaviourInParent<T>(this IBehaviourController behaviourController) where T : class
 | 
						|
        => behaviourController.GetBehaviourInParent<T>() ?? throw new BehaviourNotFoundException($"{behaviourController.UniverseObject?.Name ?? "NULL"}'s {nameof(IBehaviourController)} does not contain any {typeof(T).FullName} on any parent");
 | 
						|
 | 
						|
    /// <summary>
 | 
						|
    /// Gets all <see cref="IBehaviour"/>s of the specified type in it's <see cref="IUniverseObject"/>'s parents recursively and stores them in the provided list.
 | 
						|
    /// </summary>
 | 
						|
    /// <typeparam name="T">The type of <see cref="IBehaviour"/>s to get.</typeparam>
 | 
						|
    /// <param name="behavioursInParent">The list to store the <see cref="IBehaviour"/>s.</param>
 | 
						|
    public static void GetBehavioursInParent<T>(this IBehaviourController behaviourController, IList<T> behavioursInParent) where T : class
 | 
						|
    {
 | 
						|
        IBehaviourController? controller = behaviourController;
 | 
						|
        List<T> cache = [];
 | 
						|
        behavioursInParent.Clear();
 | 
						|
 | 
						|
        while (controller is not null)
 | 
						|
        {
 | 
						|
            controller.GetBehaviours(cache);
 | 
						|
            foreach (T behaviour in cache)
 | 
						|
                behavioursInParent.Add(behaviour);
 | 
						|
 | 
						|
            controller = controller.UniverseObject.Parent?.BehaviourController;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /// <summary>
 | 
						|
    /// Tries to get a <see cref="IBehaviour"/> of the specified type in it's <see cref="IUniverseObject"/>'s children recursively.
 | 
						|
    /// </summary>
 | 
						|
    /// <typeparam name="T">The type of <see cref="IBehaviour"/> to get.</typeparam>
 | 
						|
    /// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param>
 | 
						|
    /// <param name="behaviour">When this method returns, contains the <see cref="IBehaviour"/> of the specified type, if found; otherwise, null.</param>
 | 
						|
    /// <returns><see cref="true"/> if a <see cref="IBehaviour"/> of the specified type was found in the child universe; otherwise, <see cref="false"/>.</returns>
 | 
						|
    public static bool TryGetBehaviourInChildren<T>(this IBehaviourController behaviourController, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class
 | 
						|
    {
 | 
						|
        behaviour = GetBehaviourInChildren<T>(behaviourController);
 | 
						|
        return behaviour is not null;
 | 
						|
    }
 | 
						|
 | 
						|
    /// <summary>
 | 
						|
    /// Gets a <see cref="IBehaviour"/> of the specified type in it's <see cref="IUniverseObject"/>'s children recursively.
 | 
						|
    /// </summary>
 | 
						|
    /// <typeparam name="T">The type of <see cref="IBehaviour"/> to get.</typeparam>
 | 
						|
    /// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param>
 | 
						|
    /// <returns>The <see cref="IBehaviour"/> of the specified type if found; otherwise, null.</returns>
 | 
						|
    public static T? GetBehaviourInChildren<T>(this IBehaviourController behaviourController) where T : class
 | 
						|
    {
 | 
						|
        if (behaviourController.GetBehaviour<T>() is T localBehaviour)
 | 
						|
            return localBehaviour;
 | 
						|
 | 
						|
        foreach (IUniverseObject child in behaviourController.UniverseObject.Children)
 | 
						|
            if (GetBehaviourInChildren<T>(child.BehaviourController) is T behaviour)
 | 
						|
                return behaviour;
 | 
						|
 | 
						|
        return default;
 | 
						|
    }
 | 
						|
 | 
						|
    /// <summary>
 | 
						|
    /// Gets a <see cref="IBehaviour"/> of the specified type in the children recursively. Throws an error if not found.
 | 
						|
    /// </summary>
 | 
						|
    /// <typeparam name="T">The type of <see cref="IBehaviour"/> to get.</typeparam>
 | 
						|
    /// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param>
 | 
						|
    /// <returns>The <see cref="IBehaviour"/> of the specified type if found; otherwise, throws <see cref="BehaviourNotFoundException"/>.</returns>
 | 
						|
    public static T GetRequiredBehaviourInChildren<T>(this IBehaviourController behaviourController) where T : class
 | 
						|
        => behaviourController.GetBehaviourInChildren<T>() ?? throw new BehaviourNotFoundException($"{behaviourController.UniverseObject?.Name ?? "NULL"}'s {nameof(IBehaviourController)} does not contain any {typeof(T).FullName} on any children ");
 | 
						|
 | 
						|
    /// <summary>
 | 
						|
    /// Gets all <see cref="IBehaviour"/>s of the specified type in it's <see cref="IUniverseObject"/>'s children recursively and stores them in the provided list.
 | 
						|
    /// </summary>
 | 
						|
    /// <typeparam name="T">The type of <see cref="IBehaviour"/>s to get.</typeparam>
 | 
						|
    /// <param name="behavioursInChildren">The list to store the <see cref="IBehaviour"/>s.</param>
 | 
						|
    public static void GetBehavioursInChildren<T>(this IBehaviourController behaviourController, IList<T> behavioursInChildren) where T : class
 | 
						|
    {
 | 
						|
        List<T> cache = [];
 | 
						|
        behavioursInChildren.Clear();
 | 
						|
 | 
						|
        TraverseChildrenForBehaviour(behaviourController.UniverseObject, behavioursInChildren, cache);
 | 
						|
    }
 | 
						|
 | 
						|
    private static void TraverseChildrenForBehaviour<T>(IUniverseObject universeObject, IList<T> behaviours, IList<T> cache) where T : class
 | 
						|
    {
 | 
						|
        universeObject.BehaviourController.GetBehaviours(cache);
 | 
						|
 | 
						|
        foreach (T behaviour in cache)
 | 
						|
            behaviours.Add(behaviour);
 | 
						|
 | 
						|
        foreach (IUniverseObject child in universeObject.Children)
 | 
						|
            TraverseChildrenForBehaviour(child, behaviours, cache);
 | 
						|
    }
 | 
						|
}
 |