using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; namespace AwperativeKernel; /// /// 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. /// /// Please don't inherit this. I don't know why you would /// Avery Norris public abstract class ComponentDocker { /// /// List of all Components belonging to the Docker, Please Use Add, Get, Move and Destroy to modify it. /// public ImmutableArray Components => [.._Components]; /// /// Amount of all Components in the Docker /// public int Count => _Components.Count; /// /// 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 /// internal SortedSet _Components = new(_componentSorter); /// /// How Priority is sorted. /// private readonly static Comparer _componentSorter = Comparer.Create((a, b) => { int result = b.Priority.CompareTo(a.Priority); return (result != 0) ? result : a.GetHashCode().CompareTo(b.GetHashCode()); }); /// /// Resorts member of Component list to match the Priority. /// /// Component to modify /// New priority for Component internal void UpdatePriority(Component __component, int __priority) { foreach (String tag in __component._tags) { _taggedComponents[tag].Remove(__component); } _Components.Remove(__component); __component._priority = __priority; foreach (String tag in __component._tags) { _taggedComponents[tag].Add(__component); } _Components.Add(__component); } /// /// Called by Awperative when the game is Closed, sends the event to all children; and they send it to their children. /// /// Will not always trigger if the program is force closed internal virtual void ChainUnload() { foreach (Component component in (Component[])[.._Components]) { if(component.Enabled) { component.Unload(); component.ChainUnload(); } } } /// /// Called by Awperative when the game is Opened, sends the event to all children; and they send it to their children. /// internal virtual void ChainLoad() { foreach (Component component in (Component[])[.._Components]) { if(component.Enabled) { component.Load(); component.ChainLoad(); } } } /// /// Called by Awperative when the game is Updated sends the event to all children; and they send it to their children. /// internal virtual void ChainUpdate() { foreach (Component component in (Component[])[.._Components]) { if(component.Enabled) { component.Update(); component.ChainUpdate(); } } } /// /// Called by Awperative when the game is Drawn, sends the event to all children; and they send it to their children. /// /// Only use this method for drawing methods internal virtual void ChainDraw() { foreach (Component component in (Component[])[.._Components]) { if(component.Enabled) { component.Draw(); component.ChainDraw(); } } } /// /// Called by Awperative when this is Created, sends the event to all children; and they send it to their children. /// internal virtual void ChainCreate() { foreach (Component component in (Component[])[.._Components]) { if(component.Enabled) { component.Create(); component.ChainCreate(); } } } /// /// Called by Awperative when this Component is destroyed, sends the event to all children; since they will be Destroyed too. And they send it to their children. /// /// Not called when the game is closed internal virtual void ChainDestroy() { foreach(Component component in (Component[])[.._Components]) { if(component.Enabled) { component.Destroy(); component.ChainDestroy(); } } } /// /// Add a new Component to the Docker; This is the only way they should be created. /// /// Arguments to construct the Component with /// Type of Component to instantiate /// public __Type Add<__Type>(object[] __args) where __Type : Component { //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); return (__Type) newComponent; } /// /// Adds a new Component to the Docker; This is the only way they should be created. /// /// /// public __Type Add<__Type>() where __Type : Component => Add<__Type>([]); /// /// Transfers a child Component to another Docker /// /// Component to move /// Docker to move component to /// Components cannot transfer themselves with this Method! 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; } /// /// Transfers the first found Component of a specific type to another Docker /// /// Docker to move component to /// Type of component public void Move<__Type>(ComponentDocker __componentDocker) where __Type : Component => Move(Get<__Type>(), __componentDocker); /// /// Transfers all Components in a list to another Docker. /// /// List of Components to transfer /// Docker to move Component to public void MoveAll(IEnumerable __Components, ComponentDocker __componentDocker) { foreach (Component Component in (Component[])[..__Components]) Move(Component, __componentDocker); } /// /// Transfers all Components of a type to another Docker. /// /// Target Docker /// Type of Components to transfer public void MoveAll<__Type>(ComponentDocker __componentDocker) where __Type : Component => MoveAll(GetAll<__Type>(), __componentDocker); /// /// /// Holds Components at Keys of their tags. /// internal Dictionary> _taggedComponents = []; /// /// Add component to its proper place in the dictionary and resort values to match priorities. /// /// Component to hash /// Value to try and hash 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 components)) { components.Add(__component); } else { _taggedComponents.Add(__tag, new SortedSet(_componentSorter)); _taggedComponents[__tag].Add(__component); } } /// /// /// /// /// 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 components)) { components.Remove(__component); if(components.Count == 0) _taggedComponents.Remove(__tag); } } /// /// Finds the first instance of a component with a given tag /// /// /// internal Component Get(string __tag) { if (_taggedComponents.TryGetValue(__tag, out SortedSet components)) return ((Component[])[..components])[0]; return null; } /// /// Finds all Components with a given tag /// /// /// internal ImmutableArray GetAll(string __tag) { if (_taggedComponents.TryGetValue(__tag, out SortedSet components)) return [..components]; return []; } /// /// Finds the first Component that has all the given tags /// /// /// internal Component Get(List __tags) { ImmutableArray returnValue = GetAll(__tags); return returnValue.Length > 0 ? returnValue[0] : null; } /// /// Finds all Components that have all the given tags /// /// /// internal ImmutableArray GetAll(List __tags) { if (__tags.Count == 0) return []; SortedSet 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]; } /// /// Searches and returns the first Component of a type found on the Docker. /// /// The Type of Component to search for /// 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; } /// /// Searches and returns all Components of a type found on the Docker. /// /// The Type of Components to search for /// 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]; } /// /// Returns a bool based on if the Docker contains a Component with the given tag or not /// /// /// public bool Contains(string __tag) => _taggedComponents.ContainsKey(__tag); /// /// Returns a bool based on if the Docker contains a Component of that type or not /// /// Type of the Component /// public bool Contains<__Type>() where __Type : Component => _Components.Any(x => x is __Type); /// /// Returns a bool based on if the current __Component is owned by this Docker /// /// /// public bool Contains(Component __component) => _Components.Contains(__component); /// /// Destroys a Component attached to docker /// /// 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.Destroy(); __component.ChainDestroy(); foreach (string tag in __component._tags) UnhashTaggedComponent(__component, tag); __component.ComponentDocker = null; _Components.Remove(__component); } /// /// Destroys the first found Component of a given type /// /// Type of Component to destroy public void Remove<__Type>() where __Type : Component => Remove(Get<__Type>()); /// /// Destroys all Components from a given collection. /// /// public void RemoveAll(IEnumerable __Components) { foreach (Component component in (Component[])[..__Components]) { Remove(component); } } /// /// Destroys all Components of a given type /// /// public void RemoveAll<__Type>() where __Type : Component => RemoveAll(GetAll<__Type>()); /// /// Destroys all Components attached to Docker /// public void RemoveAll() { foreach (Component component in (Component[])[.._Components]) { Remove(component); } } }