577 lines
20 KiB
C#
577 lines
20 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
|
|
|
|
namespace AwperativeKernel;
|
|
|
|
/// <summary>
|
|
/// Base class for all Awperative Entities. Responsible for Managing hierarchy between Components and Scenes, has Extensive Component Manipulation Available.
|
|
/// Also transfers Time and Carries most of the responsibilities akin to the Component.
|
|
/// </summary>
|
|
/// <remarks> Please don't inherit this. I don't know why you would</remarks>
|
|
/// <author> Avery Norris </author>
|
|
public abstract class ComponentDocker
|
|
{
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// List of all Components belonging to the Docker, Please Use Add, Get, Move and Destroy to modify it.
|
|
/// </summary>
|
|
public ImmutableArray<Component> Components => [.._Components];
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Amount of all Components in the Docker
|
|
/// </summary>
|
|
public int Count => _Components.Count;
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Core of Docker, contains all of our precious Components. Sorts them by their priorities with highest going first.
|
|
/// If they are equal it defaults to hash codes to ensure consistent Behavior
|
|
/// </summary>
|
|
internal SortedSet<Component> _Components = new(_componentSorter);
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// How Priority is sorted.
|
|
/// </summary>
|
|
private readonly static Comparer<Component> _componentSorter = Comparer<Component>.Create((a, b) => {
|
|
int result = b.Priority.CompareTo(a.Priority);
|
|
return (result != 0) ? result : a.GetHashCode().CompareTo(b.GetHashCode());
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Resorts member of Component list to match the Priority.
|
|
/// </summary>
|
|
/// <param name="__component"> Component to modify</param>
|
|
/// <param name="__priority"> New priority for Component</param>
|
|
internal void UpdatePriority(Component __component, int __priority) {
|
|
//add ownership enforcement/method
|
|
|
|
foreach (String tag in __component._tags) _taggedComponents[tag].Remove(__component);
|
|
foreach (Awperative.TimeEvent timeEvent in __component.GetAllEvents()) { Awperative._TimeBasedComponents[timeEvent].Remove(__component);}
|
|
_Components.Remove(__component);
|
|
|
|
__component._priority = __priority;
|
|
|
|
foreach (String tag in __component._tags) _taggedComponents[tag].Add(__component);
|
|
foreach (Awperative.TimeEvent timeEvent in __component.GetAllEvents()) { Awperative._TimeBasedComponents[timeEvent].Add(__component);}
|
|
_Components.Add(__component);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Chains an event to all children, NOT MEANT FOR UPDATE OR DRAW ETC, JUST CREATE AND DESTROY
|
|
/// </summary>
|
|
/// <param name="__timeEvent"></param>
|
|
internal void TryEvent(Component __component, Awperative.TimeEvent __timeEvent) {
|
|
__component.EventDelegates[(int)__timeEvent]?.Invoke();
|
|
}
|
|
|
|
|
|
//internal void TryEvent(Component __component, Awperative.TimeEvent __timeEvent) => __component.TryEvent(__timeEvent);
|
|
|
|
|
|
/// <summary>
|
|
/// Chains an event to all children, NOT MEANT FOR UPDATE OR DRAW ETC, JUST CREATE AND DESTROY
|
|
/// </summary>
|
|
/// <param name="__timeEvent"></param>
|
|
internal void ChainEvent(Awperative.TimeEvent __timeEvent) {
|
|
|
|
if (this is Component dockerComponent) {
|
|
|
|
TryEvent(dockerComponent, __timeEvent);
|
|
foreach (Component component in _Components.ToList()) {
|
|
component.EventDelegates[(int)__timeEvent]?.Invoke();
|
|
component.ChainEvent(__timeEvent);
|
|
}
|
|
} else Debug.LogError("Please do not call chain event on anything besides a Component! It is meant for Create() and Destroy()");
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Add a new Component to the Docker; This is the only way they should be created.
|
|
/// </summary>
|
|
/// <param name="__args"> Arguments to construct the Component with</param>
|
|
/// <typeparam name="__Type"> Type of Component to instantiate</typeparam>
|
|
/// <returns></returns>
|
|
public __Type Add<__Type>(object[] __args, string name = "", string[] tags = null) where __Type : Component {
|
|
|
|
if(name == "") { name = typeof(__Type).Name; }
|
|
if (tags == null) tags = [];
|
|
|
|
|
|
|
|
|
|
//Component does not have a constructor that matches the given args
|
|
if (typeof(__Type).GetConstructor(__args.Select(x => x.GetType()).ToArray()) == null) {
|
|
Debug.LogError("Component cannot be constructed with the given arguments",
|
|
["Type", "Args"],
|
|
[typeof(__Type).ToString(), "[" + string.Join(", ", __args.Select(x => x.ToString())) + "]"]); return null;
|
|
};
|
|
|
|
|
|
Component newComponent;
|
|
|
|
|
|
//Tries to instantiate Component, and sends a fail call if an issue occurs.
|
|
try { newComponent = (__Type)Activator.CreateInstance(typeof(__Type), __args); }
|
|
catch {
|
|
Debug.LogError("Component creation failed!", ["Type", "Args", "Docker"],
|
|
[typeof(__Type).ToString(), "[" + string.Join(", ", __args.Select(x => x.ToString())) + "]", GetHashCode().ToString()]); return null;
|
|
}
|
|
|
|
|
|
//If Component is null do not add
|
|
if(newComponent == null) {
|
|
Debug.LogError("Activator created Null Component", ["Type", "Args", "Docker"],
|
|
[typeof(__Type).ToString(), "[" + string.Join(", ", __args.Select(x => x.ToString())) + "]", GetHashCode().ToString()]); return null;
|
|
}
|
|
|
|
|
|
//Add to docker and initialize the new Component
|
|
_Components.Add(newComponent);
|
|
newComponent.Initiate(this, name, tags);
|
|
foreach (Awperative.TimeEvent timeEvent in newComponent.GetAllGlobalEvents()) { Awperative._TimeBasedComponents[timeEvent].Add(newComponent); }
|
|
|
|
newComponent.ChainEvent(Awperative.TimeEvent.Create);
|
|
|
|
return (__Type) newComponent;
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Adds a new Component to the Docker; This is the only way they should be created.
|
|
/// </summary>
|
|
/// <typeparam name="__Type"></typeparam>
|
|
/// <returns></returns>
|
|
public __Type Add<__Type>(string name = "", string[] tags = null) where __Type : Component => Add<__Type>([], name: name, tags: tags);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Transfers a child Component to another Docker
|
|
/// </summary>
|
|
/// <param name="__component"> Component to move</param>
|
|
/// <param name="__componentDocker"> Docker to move component to</param>
|
|
/// <remarks> Components cannot transfer themselves with this Method!</remarks>
|
|
public void Move(Component __component, ComponentDocker __componentDocker) {
|
|
|
|
|
|
|
|
//This allows self transfer behavior while preserving Docker's actual job, Before all other statements to prevent Double-Debugging.
|
|
if (__component == this) { __component.ComponentDocker.Move(__component, __componentDocker); return; }
|
|
|
|
|
|
|
|
if (__component == null) {
|
|
Debug.LogError("Component is null!", ["CurrentDocker", "NewDocker"],
|
|
[GetHashCode().ToString(), __componentDocker.GetHashCode().ToString()]); return; }
|
|
|
|
|
|
|
|
if (!_Components.Contains(__component)) {
|
|
Debug.LogError("Docker does not have ownership of Component", ["Component", "Type", "CurrentDocker", "NewDocker"],
|
|
[__component.GetHashCode().ToString(), __component.GetType().ToString(), GetHashCode().ToString(), __componentDocker.GetHashCode().ToString()]); return; }
|
|
|
|
|
|
|
|
//Update docker lists
|
|
__componentDocker._Components.Add(__component);
|
|
_Components.Remove(__component);
|
|
|
|
|
|
|
|
//Update components parent
|
|
__component.ComponentDocker = __componentDocker;
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Transfers the first found Component of a specific type to another Docker
|
|
/// </summary>
|
|
/// <param name="__componentDocker"> Docker to move component to</param>
|
|
/// <typeparam name="__Type"> Type of component</typeparam>
|
|
public void Move<__Type>(ComponentDocker __componentDocker) where __Type : Component => Move(Get<__Type>(), __componentDocker);
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Transfers all Components in a list to another Docker.
|
|
/// </summary>
|
|
/// <param name="__Components"> List of Components to transfer</param>
|
|
/// <param name="__componentDocker"> Docker to move Component to</param>
|
|
public void MoveAll(IEnumerable<Component> __Components, ComponentDocker __componentDocker) { foreach (Component Component in (Component[])[..__Components]) Move(Component, __componentDocker); }
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Transfers all Components of a type to another Docker.
|
|
/// </summary>
|
|
/// <param name="__componentDocker"> Target Docker</param>
|
|
/// <typeparam name="__Type"> Type of Components to transfer</typeparam>
|
|
public void MoveAll<__Type>(ComponentDocker __componentDocker) where __Type : Component => MoveAll(GetAll<__Type>(), __componentDocker);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// /// <summary>
|
|
/// Holds Components at Keys of their tags.
|
|
/// </summary>
|
|
internal Dictionary<string, SortedSet<Component>> _taggedComponents = [];
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Add component to its proper place in the dictionary and resort values to match priorities.
|
|
/// </summary>
|
|
/// <param name="__component"> Component to hash</param>
|
|
/// <param name="__tag"> Value to try and hash</param>
|
|
internal void HashTaggedComponent(Component __component, string __tag) {
|
|
|
|
if (!__component._tags.Add(__tag)) {
|
|
Debug.LogError("Component already has tag!", ["Component", "Type", "Tag", "Docker"],
|
|
[__component.GetHashCode().ToString(), __component.GetType().ToString(), __tag, GetHashCode().ToString()]); return;
|
|
}
|
|
|
|
if (_taggedComponents.TryGetValue(__tag, out SortedSet<Component> components)) {
|
|
components.Add(__component);
|
|
|
|
} else { _taggedComponents.Add(__tag, new SortedSet<Component>(_componentSorter)); _taggedComponents[__tag].Add(__component); }
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="__component"></param>
|
|
/// <param name="__tag"></param>
|
|
internal void UnhashTaggedComponent(Component __component, string __tag) {
|
|
|
|
if (!__component._tags.Remove(__tag)) {
|
|
Debug.LogError("Component already doesn't have that tag!", ["Component", "Type", "Tag", "Docker"],
|
|
[__component.GetHashCode().ToString(), __component.GetType().ToString(), __tag, GetHashCode().ToString()]); return;
|
|
}
|
|
|
|
|
|
if (_taggedComponents.TryGetValue(__tag, out SortedSet<Component> components)) {
|
|
components.Remove(__component);
|
|
|
|
if(components.Count == 0)
|
|
_taggedComponents.Remove(__tag);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Finds the first instance of a component with a given tag
|
|
/// </summary>
|
|
/// <param name="__tag"> Tag to search for</param>
|
|
/// <returns></returns>
|
|
internal Component Get(string __tag) {
|
|
if (_taggedComponents.TryGetValue(__tag, out SortedSet<Component> components))
|
|
return ((Component[])[..components])[0];
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Finds the first instance of a component with a given tag
|
|
/// </summary>
|
|
/// <param name="__tag"> Tag to search for</param>
|
|
/// <param name="__component">Component that has been found</param>
|
|
/// <returns></returns>
|
|
internal bool TryGet(string __tag, out Component __component) { __component = Get(__tag); return __component != null; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Finds all Components with a given tag
|
|
/// </summary>
|
|
/// <param name="__tag"></param>
|
|
/// <returns></returns>
|
|
internal ImmutableArray<Component> GetAll(string __tag) {
|
|
if (_taggedComponents.TryGetValue(__tag, out SortedSet<Component> components))
|
|
return [..components];
|
|
|
|
return [];
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Searches for all Components with a given tag
|
|
/// </summary>
|
|
/// <param name="__tag"></param>
|
|
/// <param name="__components"></param>
|
|
/// <returns></returns>
|
|
internal bool TryGetAll(string __tag, out ImmutableArray<Component> __components) { __components = GetAll(__tag); return __components.Length > 0; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Finds the first Component that has all the given tags
|
|
/// </summary>
|
|
/// <param name="__tags"></param>
|
|
/// <returns></returns>
|
|
internal Component Get(List<string> __tags) { ImmutableArray<Component> returnValue = GetAll(__tags); return returnValue.Length > 0 ? returnValue[0] : null; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Finds the first Component that has all the given tags
|
|
/// </summary>
|
|
/// <param name="__tags"></param>
|
|
/// <returns></returns>
|
|
internal bool TryGet(List<string> __tags, out Component __component) { __component = Get(__tags); return __component != null; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Finds all Components that have all the given tags
|
|
/// </summary>
|
|
/// <param name="__tags"></param>
|
|
/// <returns></returns>
|
|
internal ImmutableArray<Component> GetAll(List<string> __tags) {
|
|
|
|
if (__tags.Count == 0)
|
|
return [];
|
|
|
|
SortedSet<Component> foundComponents = _taggedComponents[__tags[0]];
|
|
|
|
for (int i = 1; i < __tags.Count; i++) {
|
|
foreach (Component component in (Component[])[..foundComponents]) {
|
|
if (!_taggedComponents[__tags[i]].Contains(component)) foundComponents.Remove(component);
|
|
}
|
|
}
|
|
|
|
return [..foundComponents];
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Tries to get all components with the given tags
|
|
/// </summary>
|
|
/// <param name="__tags"></param>
|
|
/// <param name="__components"></param>
|
|
/// <returns></returns>
|
|
internal bool TryGetAll(List<string> __tags, out ImmutableArray<Component> __components) { __components = GetAll(__tags); return __components.Length > 0; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Searches and returns the first Component of a type found on the Docker.
|
|
/// </summary>
|
|
/// <typeparam name="__Type"> The Type of Component to search for</typeparam>
|
|
/// <returns></returns>
|
|
public __Type Get<__Type>() where __Type : Component {
|
|
|
|
|
|
|
|
//Iterates through the loop and returns if a match is found
|
|
foreach (Component component in (Component[])[.._Components])
|
|
if (component is __Type foundComponent) return foundComponent;
|
|
|
|
|
|
|
|
//Throws error if there is no Component found
|
|
Debug.LogError("Docker does not have target Component", ["Type", "Docker"],
|
|
[typeof(__Type).ToString(), GetHashCode().ToString()]); return null;
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="__component"></param>
|
|
/// <typeparam name="__Type"></typeparam>
|
|
/// <returns></returns>
|
|
public bool TryGet<__Type>(out __Type __component) where __Type : Component { __component = Get<__Type>(); return __component != null; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Searches and returns all Components of a type found on the Docker.
|
|
/// </summary>
|
|
/// <typeparam name="__Type"> The Type of Components to search for</typeparam>
|
|
/// <returns></returns>
|
|
public ImmutableArray<__Type> GetAll<__Type>() where __Type : Component {
|
|
|
|
|
|
|
|
List<__Type> foundComponents = [];
|
|
|
|
|
|
//Iterates through the loop and returns if a match is found
|
|
foreach (Component component in (Component[])[.._Components]) {
|
|
if (component is __Type foundComponent) {
|
|
foundComponents.Add(foundComponent);
|
|
}
|
|
}
|
|
|
|
|
|
//Throws error if there is no Component found
|
|
if (foundComponents.Count == 0) {
|
|
Debug.LogError("Docker does not have target Component", ["Type", "Docker"],
|
|
[typeof(__Type).ToString(), GetHashCode().ToString()]);
|
|
return [];
|
|
}
|
|
|
|
|
|
|
|
return [..foundComponents];
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="__components"></param>
|
|
/// <typeparam name="__Type"></typeparam>
|
|
/// <returns></returns>
|
|
public bool TryGetAll<__Type>(out ImmutableArray<__Type> __components) where __Type : Component { __components = GetAll<__Type>(); return __components.Length > 0; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Returns a bool based on if the Docker contains a Component with the given tag or not
|
|
/// </summary>
|
|
/// <param name="__tag"></param>
|
|
/// <returns></returns>
|
|
public bool Contains(string __tag) => _taggedComponents.ContainsKey(__tag);
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Returns a bool based on if the Docker contains a Component of that type or not
|
|
/// </summary>
|
|
/// <typeparam name="__Type">Type of the Component</typeparam>
|
|
/// <returns></returns>
|
|
public bool Contains<__Type>() where __Type : Component => _Components.Any(x => x is __Type);
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Returns a bool based on if the current __Component is owned by this Docker
|
|
/// </summary>
|
|
/// <param name="__component"></param>
|
|
/// <returns></returns>
|
|
public bool Contains(Component __component) => _Components.Contains(__component);
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Destroys a Component attached to docker
|
|
/// </summary>
|
|
/// <param name="__component"></param>
|
|
public void Remove(Component __component) {
|
|
|
|
//Component is null
|
|
if (__component == null) {
|
|
Debug.LogError("Component is null", ["CurrentDocker"],
|
|
[GetHashCode().ToString()]); return;
|
|
}
|
|
|
|
|
|
|
|
//Docker doesn't have Component
|
|
if (!_Components.Contains(__component)) {
|
|
Debug.LogError("Docker does not have ownership of Component", ["Component", "Type", "CurrentDocker"],
|
|
[__component.GetHashCode().ToString(), __component.GetType().ToString(), GetHashCode().ToString()]); return;
|
|
}
|
|
|
|
__component.ChainEvent(Awperative.TimeEvent.Destroy);
|
|
|
|
foreach (string tag in __component._tags) UnhashTaggedComponent(__component, tag);
|
|
__component.ComponentDocker = null;
|
|
|
|
_Components.Remove(__component);
|
|
foreach (Awperative.TimeEvent timeEvent in __component.GetAllEvents()) Awperative._TimeBasedComponents[timeEvent].Remove(__component);
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Destroys the first found Component of a given type
|
|
/// </summary>
|
|
/// <typeparam name="__Type"> Type of Component to destroy</typeparam>
|
|
public void Remove<__Type>() where __Type : Component => Remove(Get<__Type>());
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Destroys all Components from a given collection.
|
|
/// </summary>
|
|
/// <param name="__Components"></param>
|
|
public void RemoveAll(IEnumerable<Component> __Components) { foreach (Component component in (Component[])[..__Components]) { Remove(component); } }
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Destroys all Components of a given type
|
|
/// </summary>
|
|
/// <typeparam name="__Type"></typeparam>
|
|
public void RemoveAll<__Type>() where __Type : Component => RemoveAll(GetAll<__Type>());
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Destroys all Components attached to Docker
|
|
/// </summary>
|
|
public void RemoveAll() { foreach (Component component in (Component[])[.._Components]) { Remove(component); } }
|
|
|
|
|
|
|
|
|
|
|
|
} |