using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Syntriax.Engine.Core.Exceptions; namespace Syntriax.Engine.Core; public static class UniverseObjectExtensions { public static T SetUniverseObject(this T universeObject, string? name = "", IUniverseObject? parent = null) where T : IUniverseObject { if (!string.IsNullOrWhiteSpace(name)) universeObject.Name = name; if (parent is not null) universeObject.SetParent(parent); return universeObject; } #region Universe Object Search /// /// Gets a of the specified type. /// /// The type of to get. /// The s to search. /// The first found of the specified type; otherwise, null. public static T? GetUniverseObject(this IEnumerable universeObjects) where T : class { foreach (IUniverseObject universeObject in universeObjects) if (universeObject is T @object) return @object; return default; } /// /// Tries to get a of the specified type. /// /// The type of to get. /// The s to search. /// if a of the specified type was found in the universe objects; otherwise, . public static bool TryGetUniverseObject(this IEnumerable universeObjects, [NotNullWhen(returnValue: true)] out T? universeObject) where T : class { universeObject = GetUniverseObject(universeObjects); return universeObject is not null; } /// /// Searches through the provided s to collect a list of s of the specified type. /// /// The type of to get. /// The to search. /// The found s of the specified types public static void GetUniverseObjects(this IEnumerable universeObjects, IList foundUniverseObjects) where T : class { foundUniverseObjects.Clear(); foreach (IUniverseObject universeObject in universeObjects) if (universeObject is T @object) foundUniverseObjects.Add(@object); } #endregion #region Universe Object Search In Parent /// /// Tries to get a of the specified type in it's parents recursively. /// /// The type of to get. /// When this method returns, contains the of the specified type, if found; otherwise, null. /// if a of the specified type was found in the parent universe objects; otherwise, . public static bool TryGetUniverseObjectInParent(this IUniverseObject universeObject, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class { behaviour = GetUniverseObjectInParent(universeObject); return behaviour is not null; } /// /// Gets a of the specified type in it's parents recursively. /// /// The type of to get. /// The to start searching from. /// The of the specified type if found; otherwise, null. public static T? GetUniverseObjectInParent(this IUniverseObject universeObject) where T : class { if (universeObject.GetUniverseObject() is T localUniverseObject) return localUniverseObject; IUniverseObject? parent = universeObject; while (parent is not null) { if (parent is T behaviour) return behaviour; parent = universeObject.Parent; } return default; } /// /// Gets a of the specified type in the parents recursively. Throws an error if not found. /// /// The type of to get. /// The to start searching from. /// The of the specified type if found; otherwise, throws . public static T GetRequiredUniverseObjectInParent(this IUniverseObject universeObject) where T : class => universeObject.GetUniverseObjectInParent() ?? throw new UniverseObjectNotFoundException($"{universeObject.Name}'s {nameof(IUniverseObject)} does not contain any {typeof(T).FullName} on any parent "); #endregion #region Universe Object Search In Children /// /// Tries to get a of the specified type in it's children recursively. /// /// The type of to get. /// When this method returns, contains the of the specified type, if found; otherwise, null. /// if a of the specified type was found in the child universe objects; otherwise, . public static bool TryGetUniverseObjectInChildren(this IUniverseObject universeObject, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class { behaviour = GetUniverseObjectInChildren(universeObject); return behaviour is not null; } /// /// Gets a of the specified type in it's children recursively. /// /// The type of to get. /// The to start searching from. /// The of the specified type if found; otherwise, null. public static T? GetUniverseObjectInChildren(this IUniverseObject universeObject) where T : class { if (universeObject.GetUniverseObject() is T localUniverseObject) return localUniverseObject; foreach (IUniverseObject child in universeObject) if (GetUniverseObjectInChildren(child) is T behaviour) return behaviour; return default; } /// /// Gets a of the specified type in the children recursively. Throws an error if not found. /// /// The type of to get. /// The to start searching from. /// The of the specified type if found; otherwise, throws . public static T GetRequiredUniverseObjectInChildren(this IUniverseObject universeObject) where T : class => universeObject.GetUniverseObjectInChildren() ?? throw new UniverseObjectNotFoundException($"{universeObject.Name}'s {nameof(IUniverseObject)} does not contain any {typeof(T).FullName} on any children "); #endregion #region Behaviour Search /// /// Finds a of the specified type in the provided s. /// /// The type of to find. /// The first found of the specified type; otherwise, null. public static T? FindBehaviour(this IEnumerable universeObjects) where T : class { foreach (IUniverseObject universeObject in universeObjects) if (universeObject.BehaviourController.GetBehaviour() is T behaviour) return behaviour; return default; } /// /// Tries to find a of the specified type in the provided s. /// /// The type of to find. /// When this method returns, contains the of the specified type, if found; otherwise, null. /// if a of the specified type was found in the provided s; otherwise, . public static bool TryFindBehaviour(this IEnumerable universeObjects, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class { behaviour = FindBehaviour(universeObjects); return behaviour is not null; } /// /// Searches through the provided s to collect a list of s of the specified type. /// /// The type of to get. /// The s to search. public static void FindBehaviours(this IEnumerable universeObjects, IList behaviours) where T : class { behaviours.Clear(); List cache = []; foreach (IUniverseObject universeObject in universeObjects) { universeObject.BehaviourController.GetBehaviours(cache); foreach (T behaviour in cache) behaviours.Add(behaviour); } } #endregion #region General Search /// /// Finds an object of the specified type in the provided s and their s. /// /// /// WARNING: This is more expensive compared to or as it combines the two. If you know whether the type is either a type that gets implemented on an or use the method appropriate for it for performance. /// /// The type of to find. /// The first found instance of the specified type; otherwise, null. public static T? Find(this IEnumerable universeObjects) where T : class { if (universeObjects.GetUniverseObject() is T foundUniverseObject) return foundUniverseObject; if (universeObjects.FindBehaviour() is T foundBehaviour) return foundBehaviour; return null; } /// /// Tries to find an object of the specified type in the provided s and their s. /// /// /// WARNING: This is more expensive compared to or as it combines the two. If you know whether the type is either a type that gets implemented on an or use the method appropriate for it for performance. /// /// The type of to find. /// When this method returns, contains the of the specified type, if found; otherwise, null. /// if an object of the specified type was found in the provided s; otherwise, . public static bool TryFind(this IEnumerable universeObjects, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class { behaviour = Find(universeObjects); return behaviour is not null; } /// /// Searches through the provided s and their s to collect a list of the specified type. /// /// /// WARNING: This is more expensive compared to or as it combines the two. If you know whether the type is either a type that gets implemented on an or use the method appropriate for it for performance. /// /// The type of to get. /// List of objects found wit the specified type. /// The s to search. public static void Find(this IEnumerable universeObjects, IList instances) where T : class { instances.Clear(); List cache = []; foreach (IUniverseObject universeObject in universeObjects) { universeObject.Find(cache); foreach (T behaviour in cache) instances.Add(behaviour); } } #endregion }