diff --git a/AwperativeKernel.sln.DotSettings.user b/AwperativeKernel.sln.DotSettings.user index 13e04fa..de6613a 100644 --- a/AwperativeKernel.sln.DotSettings.user +++ b/AwperativeKernel.sln.DotSettings.user @@ -1,4 +1,6 @@  + ForceIncluded + ForceIncluded <AssemblyExplorer> <Assembly Path="/Users/averynorris/Programming/Test/Awperative/Awperative/bin/Debug/net8.0/Awperative.dll" /> </AssemblyExplorer> \ No newline at end of file diff --git a/AwperativeKernel/Kernel/Component/Component.cs b/AwperativeKernel/Kernel/Component/Component.cs index e4f7652..79fe4ad 100644 --- a/AwperativeKernel/Kernel/Component/Component.cs +++ b/AwperativeKernel/Kernel/Component/Component.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Collections.ObjectModel; +using System.Diagnostics; using System.Linq; using System.Reflection; using Microsoft.VisualBasic; @@ -12,15 +13,15 @@ namespace AwperativeKernel; -public abstract partial class Component : ComponentDocker +public abstract partial class Component : ComponentDocker, IDisposable { - - - + + + /// /// Current parent of the Component. Can be either Scene or another Component. /// - public ComponentDocker ComponentDocker { get; internal set; } + public ComponentDocker ComponentDocker { get; internal set; } = null; @@ -38,12 +39,8 @@ public abstract partial class Component : ComponentDocker - /// - internal Collection EventDelegates = []; - - @@ -58,30 +55,6 @@ public abstract partial class Component : ComponentDocker - /// - /// To be called when the Component is created. - /// - /// Docker that this spawned in this Component - /// Name of the component - internal void Initiate(ComponentDocker __parent, string __name, ICollection __tags, Type __type) { - ComponentDocker = __parent; - Name = __name; - _tags = [..__tags]; - - if (Awperative._TypeAssociatedTimeEvents.TryGetValue(__type, out byte eventProfile)) { - - for (int i = 0; i < Awperative.ComponentEvents.Count; i++) { - if ((eventProfile & (1 << i)) > 0) - EventDelegates.Add((Action)Delegate.CreateDelegate(typeof(Action), this, __type.GetMethod(Awperative.ComponentEvents[i])!)); - else EventDelegates.Add(null); - } - } else { - Debug.LogError("Awperative does not recognize the given type! Perhaps it was created after Start() was called?", ["Type"], [__type.Name]); - } - } - - - /// @@ -98,7 +71,8 @@ public abstract partial class Component : ComponentDocker public void TryEvent(int __timeEvent) { - EventDelegates[__timeEvent]?.Invoke(); + Action eventDelegates = Awperative._TypeAssociatedTimeEvents[GetType()][__timeEvent]; + eventDelegates?.Invoke(this); } @@ -234,4 +208,8 @@ public abstract partial class Component : ComponentDocker for (int i = 0; i < targets.Count; i++) targets.InsertRange(i + 1, targets[i]._Components); return [..targets]; } + + public virtual void Dispose() { + GC.SuppressFinalize(this); + } } \ No newline at end of file diff --git a/AwperativeKernel/Kernel/ComponentDocker/Attributes/DockerOwns.cs b/AwperativeKernel/Kernel/ComponentDocker/Attributes/DockerOwns.cs new file mode 100644 index 0000000..61e39cf --- /dev/null +++ b/AwperativeKernel/Kernel/ComponentDocker/Attributes/DockerOwns.cs @@ -0,0 +1,223 @@ +using System; + + +namespace AwperativeKernel; + + +/// +/// Requires that the Docker owns the parameter +/// +[AttributeUsage(AttributeTargets.Parameter)] +public class DockerOwns : Attribute +{ + + + /// + /// Verifies if the Component is actually owned by Docker. Throws an error if not. + /// + /// Docker we are checking ownership for + /// Component to check for + public static bool VerifyOrThrow(ComponentDocker __docker, Component __component) { + if (__docker.Contains(__component)) return true; + + Debug.LogError("Docker does not own the Component!", ["ComponentType", "ComponentName", "ComponentHash", "DockerType", "DockerName", "DockerHash"], [ + __component.GetType().Name, + __component.Name, + __component.GetHashCode().ToString("N0"), + __docker.GetType().Name, + __docker switch { Scene scene => scene.Name, Component component => component.Name, _ => "unknown" }, + __docker.GetHashCode().ToString("N0") + ]); + + return Awperative.IgnoreErrors; + } +} + + + +/// +/// Requires that the Docker does not own the parameter +/// +[AttributeUsage(AttributeTargets.Parameter)] +public class DockerDoesntOwn : Attribute +{ + + + /// + /// Verifies if the Component is actually not owned by Docker. Throws an error if not. + /// + /// Docker we are checking ownership for + /// Component to check for + public static bool VerifyOrThrow(ComponentDocker __docker, Component __component) { + if (!__docker.Contains(__component)) return true; + + Debug.LogError("Docker owns the Component!", ["ComponentType", "ComponentName", "ComponentHash", "DockerType", "DockerName", "DockerHash"], [ + __component.GetType().Name, + __component.Name, + __component.GetHashCode().ToString("N0"), + __docker.GetType().Name, + __docker switch { Scene scene => scene.Name, Component component => component.Name, _ => "unknown" }, + __docker.GetHashCode().ToString("N0") + ]); + + return Awperative.IgnoreErrors; + } +} + + + +/// +/// Requires that the component is not attached to any Docker +/// +[AttributeUsage(AttributeTargets.Parameter)] +public class OrphanComponent : Attribute +{ + + + /// + /// Verifies if the Component is an orphan, not fully accurate, because it only checks if the docker is null, this means it is technically possible + /// to have a component already attached to a docker, and still verify it as false if Docker is null, but this should be impossible in practice. + /// + /// + /// + public static bool VerifyOrThrow(Component __component) { + if (__component.ComponentDocker == null) return true; + + Debug.LogError("Component is already owned!", ["ComponentType", "ComponentName", "ComponentHash", "DockerType", "DockerName", "DockerHash"], [ + __component.GetType().Name, + __component.Name, + __component.GetHashCode().ToString("N0"), + __component.ComponentDocker.GetType().Name, + __component.ComponentDocker switch { Scene scene => scene.Name, Component component => component.Name, _ => "unknown" }, + __component.ComponentDocker.GetHashCode().ToString("N0") + ]); + + return Awperative.IgnoreErrors; + } +} + + + +/// +/// Requires that the Component is not null +/// +[AttributeUsage(AttributeTargets.Parameter)] +public class ComponentNotNull : Attribute +{ + + + /// + /// Verifies if the Component is not null! Throws an error otherwise. + /// + /// + /// + public static bool VerifyOrThrow(Component __component) { + if (__component != null) return true; + + Debug.LogError("Component is null!"); + + return Awperative.IgnoreErrors; + } +} + + + +/// +/// Requires that the Docker is not null +/// +[AttributeUsage(AttributeTargets.Parameter)] +public class DockerNotNull : Attribute +{ + + + /// + /// Verifies if the Docker is not null! Throws an error otherwise. + /// + /// + /// + public static bool VerifyOrThrow(ComponentDocker __componentDocker) { + if (__componentDocker != null) return true; + + Debug.LogError("Docker is null!"); + + return Awperative.IgnoreErrors; + } +} + + + +/// +/// Requires that the Scene is not null +/// +[AttributeUsage(AttributeTargets.Parameter)] +public class SceneNotNull : Attribute +{ + + + /// + /// Verifies if the Scene is not null! Throws an error otherwise. + /// + /// + /// + public static bool VerifyOrThrow(Scene __scene) { + if (__scene != null) return true; + + Debug.LogError("Scene is null!"); + + return Awperative.IgnoreErrors; + } +} + + + +/// +/// Requires that the object is not null +/// +[AttributeUsage(AttributeTargets.Parameter)] +public class NotNull : Attribute +{ + + + /// + /// Verifies if the Scene is not null! Throws an error otherwise. + /// + /// + /// + public static bool VerifyOrThrow(Object __object) { + if (__object != null) return true; + + Debug.LogError("A Given parameter is null!", ["Type"], + [__object.GetType().Name + ]); + + return Awperative.IgnoreErrors; + } +} + + + +/// +/// Requires that the Docker is a different docker than the one given +/// +[AttributeUsage(AttributeTargets.Parameter)] +public class DifferentDocker : Attribute +{ + + + /// + /// Verifies if the Dockers are different! + /// + /// + /// + public static bool VerifyOrThrow(ComponentDocker __docker, ComponentDocker __other) { + if (__docker != __other) return true; + + Debug.LogError("The Dockers are the same!", ["DockerType, DockerName, DockerHash"], [ + __docker.GetType().Name, + __docker switch { Scene scene => scene.Name, Component component => component.Name, _ => "unknown" }, + __docker.GetHashCode().ToString("N0") + ]); + + return Awperative.IgnoreErrors; + } +} \ No newline at end of file diff --git a/AwperativeKernel/Kernel/ComponentDocker/ComponentDockEnum.cs b/AwperativeKernel/Kernel/ComponentDocker/ComponentDockEnum.cs new file mode 100644 index 0000000..11fde12 --- /dev/null +++ b/AwperativeKernel/Kernel/ComponentDocker/ComponentDockEnum.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections; +using System.Collections.Generic; + + +namespace AwperativeKernel; + + + +/// +/// Provides an Enumerator for the Component Docker, Loops through all Components in the Docker all for your convenience :) +/// +/// Reference to the Component Docker's components, (List to Enumerate through) +/// Enumerates on a snapshot of the list. This allows you to modify the ComponentDocker's collection during the loop. +/// Avery Norris +public class ComponentDockEnum(Component[] __components) : IEnumerator, IEnumerator, IDisposable +{ + + + + //Current index of the loop + private int index = -1; + + + + /// + /// Gets the current Component; + /// + public Component Current => __components[index]; + + + + /// + /// Get the current Component as a generic object + /// + object IEnumerator.Current => Current; + + + + /// + /// Proceeds to the next index of the loop + /// + /// Returns true or false, depending on whether the Enumeration should continue + bool IEnumerator.MoveNext() { ++index; return index < __components.Length; } + + + + /// + /// Resets the loop back to the very start + /// + public void Reset() => index = -1; + + + + /// + /// Destroys the enumerator + /// + public void Dispose() => GC.SuppressFinalize(this); + + + +} \ No newline at end of file diff --git a/AwperativeKernel/Kernel/ComponentDocker/ComponentDocker.cs b/AwperativeKernel/Kernel/ComponentDocker/Core/ComponentDocker.cs similarity index 51% rename from AwperativeKernel/Kernel/ComponentDocker/ComponentDocker.cs rename to AwperativeKernel/Kernel/ComponentDocker/Core/ComponentDocker.cs index 837a7b9..688b341 100644 --- a/AwperativeKernel/Kernel/ComponentDocker/ComponentDocker.cs +++ b/AwperativeKernel/Kernel/ComponentDocker/Core/ComponentDocker.cs @@ -1,9 +1,11 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; -using System.Collections.ObjectModel; +using System.Diagnostics; using System.Linq; using System.Reflection; +using AwperativeKernel.Attributes; namespace AwperativeKernel; @@ -14,9 +16,33 @@ namespace AwperativeKernel; /// /// Please don't inherit this. I don't know why you would /// Avery Norris -public abstract class ComponentDocker +public abstract partial class ComponentDocker : IEnumerable, IEnumerable, IEquatable, IEquatable { + public bool Equals(Component __other) { + if (this is Component component) { + return component == __other; + } else return false; + } + + public bool Equals(ComponentDocker __other) { + return this == __other; + } + + + //blocks external inheritance + internal ComponentDocker() {} + + + IEnumerator IEnumerable.GetEnumerator() { + return GetEnumerator(); + } + + public IEnumerator GetEnumerator() { + Console.WriteLine("enumerator called" + _Components.Count); + return new ComponentDockEnum([.._Components]); + } + /// @@ -37,7 +63,9 @@ public abstract class ComponentDocker /// 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); + internal List _Components = new(); + internal Dictionary> _ComponentDictionary = new(); + internal Dictionary> _taggedComponents = new(); @@ -60,163 +88,34 @@ public abstract class ComponentDocker /// New priority for Component internal void UpdatePriority(Component __component, int __priority) { //add ownership enforcement/method - - foreach (String tag in __component._tags) _taggedComponents[tag].Remove(__component); _Components.Remove(__component); - + _Components.Sort(_componentSorter); __component._priority = __priority; - - foreach (String tag in __component._tags) _taggedComponents[tag].Add(__component); _Components.Add(__component); } //internal void TryEvent(Component __component, Awperative.TimeEvent __timeEvent) => __component.TryEvent(__timeEvent); - - internal void ChainEvent(int __timeEvent) { foreach (Component component in _Components) { component.TryEvent(__timeEvent); component.ChainEvent(__timeEvent); }} - - - - - - - - - - - /// - /// 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 - /// s - public __Type Add<__Type>(object[] __args, string name = "", ICollection tags = null) where __Type : Component { - - Type newComponentType = typeof(__Type); - - if(name == "") { name = newComponentType.Name; } - if (tags == null) tags = []; - - - - - //Component does not have a constructor that matches the given args - if (newComponentType.GetConstructor(__args.Select(x => x.GetType()).ToArray()) == null) { - Debug.LogError("Component cannot be constructed with the given arguments", - ["Type", "Args"], - [newComponentType.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(newComponentType, __args); } - catch { - Debug.LogError("Component creation failed!", ["Type", "Args", "Docker"], - [newComponentType.ToString(), "[" + string.Join(", ", __args.Select(x => x.ToString())) + "]", GetHashCode().ToString()]); return null; + internal void ChainEvent(int __timeEvent) { + for (int i = 0; i < _Components.Count; i++) { + _Components[i].TryEvent(__timeEvent); + _Components[i].ChainEvent(__timeEvent); } - - - //If Component is null do not add - if(newComponent == null) { - Debug.LogError("Activator created Null Component", ["Type", "Args", "Docker"], - [newComponentType.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, newComponentType); - - newComponent.TryEvent(4); - newComponent.ChainEvent(4); - - return (__Type) newComponent; } - - - - /// - /// Adds a new Component to the Docker; This is the only way they should be created. - /// - /// - /// - public __Type Add<__Type>(string name = "", string[] tags = null) where __Type : Component => Add<__Type>([], name: name, tags: tags); + + + + - - - - - - /// - /// 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); + + + + + @@ -224,13 +123,9 @@ public abstract class ComponentDocker + + - - - /// /// - /// Holds Components at Keys of their tags. - /// - internal Dictionary> _taggedComponents = []; @@ -463,97 +358,33 @@ public abstract class ComponentDocker - /// - /// 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; - } + private void AddComponentToLists(Component __component) { + var Type = __component.GetType(); + _Components.Add(__component); + if (!_ComponentDictionary.TryAdd(Type, [__component])) _ComponentDictionary[Type].Add(__component); - - //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.TryEvent(5); - __component.ChainEvent(5); - - foreach (string tag in __component._tags) UnhashTaggedComponent(__component, tag); - __component.ComponentDocker = null; - - _Components.Remove(__component); + for(var i = 0; i < __component.Tags.Length; i++) { HashTaggedComponent(__component.Tags[i], __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>()); + private void RemoveComponentFromLists(Component __component) { + var Type = __component.GetType(); + _Components.Remove(__component); + + if(!_ComponentDictionary.ContainsKey(Type)) _ComponentDictionary[Type].Remove(__component); + + for(var i = 0; i < __component.Tags.Length; i++) { UnhashTaggedComponent(__component.Tags[i], __component); } + } + private void HashTaggedComponent(string __tag, Component __component) { + if (!_taggedComponents.TryAdd(__component.Tags[i], [__component])) + _taggedComponents[__component.Tags[i]].Add(__component); + } - /// - /// Destroys all Components from a given collection. - /// - /// - public void RemoveAll(IEnumerable __Components) { foreach (Component component in (Component[])[..__Components]) { Remove(component); } } + private void UnhashTaggedComponent(string __tag, Component __component) { + if(!_taggedComponents.ContainsKey(__tag)) _taggedComponents[__tag].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); } } - - - - - } \ No newline at end of file diff --git a/AwperativeKernel/Kernel/ComponentDocker/Core/ComponentDockerExposure.cs b/AwperativeKernel/Kernel/ComponentDocker/Core/ComponentDockerExposure.cs new file mode 100644 index 0000000..e396e20 --- /dev/null +++ b/AwperativeKernel/Kernel/ComponentDocker/Core/ComponentDockerExposure.cs @@ -0,0 +1,32 @@ + + +namespace AwperativeKernel; + + +public abstract partial class ComponentDocker +{ + + + /// + /// Returns a bool based on if the Docker contains a Component with the given tag or not + /// + /// + /// + public bool Contains([NotNull] string __tag) => NotNull.VerifyOrThrow(__tag) && _taggedComponents.ContainsKey(__tag); + + + /// + /// Returns a bool for if the Docker contains a Component of that type or not + /// + /// Type of the Component + public bool Contains<__Type>() where __Type : Component => _ComponentDictionary.ContainsKey(typeof(__Type)); + + + + /// + /// Returns a bool based on if the current __Component is owned by this Docker + /// + /// + /// + public bool Contains([ComponentNotNull,DockerOwns] Component __component) => NotNull.VerifyOrThrow(__component) && DockerOwns.VerifyOrThrow(this, __component) && _Components.Contains(__component); +} \ No newline at end of file diff --git a/AwperativeKernel/Kernel/ComponentDocker/Core/ComponentDockerManagement.cs b/AwperativeKernel/Kernel/ComponentDocker/Core/ComponentDockerManagement.cs new file mode 100644 index 0000000..292fdde --- /dev/null +++ b/AwperativeKernel/Kernel/ComponentDocker/Core/ComponentDockerManagement.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; + + +namespace AwperativeKernel; + + +public abstract partial class ComponentDocker +{ + + + + /// + /// Adds a previously instantiated Component to the Docker + /// + /// The Component to add + /// This is NOT meant to transfer a Component from one docker to another (Please use Move() for that). + /// And If you are just instantiating an Empty Component, also consider instead using Add<Type>(); + /// Avery Norris + #nullable enable + public void Add([ComponentNotNull,OrphanComponent] Component __component) { + if(!ComponentNotNull.VerifyOrThrow(__component)) return; + if(!OrphanComponent.VerifyOrThrow(__component)) return; + + //Component has already been added to another docker + if (__component.ComponentDocker != null) { Debug.LogError("You cannot use add if the Component already belongs to a Docker, use Component.Transfer();"); return; } + + InitiateComponent(__component); + } + + + + /// + /// Add a new Component to the Docker; and returns a reference to it! + /// + /// Type of Component to instantiate + /// Component cannot have a Constructor + /// Avery Norris + public __Type Add<__Type>() where __Type : Component, new() { Component newComponent = new __Type(); InitiateComponent(newComponent); return (__Type)newComponent; } + + + + /// + /// Add a new Component to the Docker; and returns a reference to it! + /// + /// Type of Component to instantiate + /// Component cannot have a Constructor + /// Avery Norris + public __Type Add<__Type>(string name = null, int priority = 0, Collection tags = null) where __Type : Component, new() { + Component newComponent = new __Type(); + newComponent.Name = name ??= typeof(__Type).Name; + newComponent._tags = [..tags ??= []]; + newComponent._priority = priority; + + InitiateComponent(newComponent); return (__Type)newComponent; + } + + + + + + /// + /// Sets important Component variables; and tries to send the Create() event. + /// + /// + /// + private void InitiateComponent(Component __component) { + //add to Component Docker's lists + AddComponentToLists(__component); + + __component.ComponentDocker = this; + //create event + __component.TryEvent(4); __component.ChainEvent(4); + } + + + + + + /// + /// Transfers a Component to another Docker + /// + /// Component to move + /// Docker to move component to + /// Components cannot transfer themselves with this Method! + public void Move([ComponentNotNull,DockerOwns] Component __component, [DockerNotNull,DifferentDocker] ComponentDocker __componentDocker) { + if(!ComponentNotNull.VerifyOrThrow(__component)) return; + if(!DockerOwns.VerifyOrThrow(this, __component)) return; + if(!DockerNotNull.VerifyOrThrow(__componentDocker)) return; + if(!DifferentDocker.VerifyOrThrow(this, __componentDocker)) return; + + if (!Contains(__component)) { + Debug.LogError("Docker does not have ownership over Component!", ["ComponentType"], [__component.GetType().Name]); return; + } + + if (__componentDocker == this) { + Debug.LogError("Docker already has Component!", ["ComponentType"], [__component.GetType().Name]); return; + } + + var type = __component.GetType(); + + //Modify collections on both Dockers + RemoveComponentFromLists(__component); + __componentDocker.AddComponentToLists(__component); + + __component.ComponentDocker = __componentDocker; + } + + + + /// + /// Transfers the first found Component of a specific type to another Docker + /// + /// Docker to move the Component to + /// Type of component + public void Move<__Type>([DockerNotNull,DifferentDocker] ComponentDocker __componentDocker) where __Type : Component => Move(Get<__Type>(), __componentDocker); + + + + /// + /// Transfers all Components in a collection to another Docker. + /// + /// The Components that need to be transferred + /// Docker to move Component to + public void MoveAll([ComponentNotNull,DockerOwns] IEnumerable __Components, [DockerNotNull,DifferentDocker] 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>([DockerNotNull, DifferentDocker] ComponentDocker __componentDocker) where __Type : Component => MoveAll(GetAll<__Type>(), __componentDocker); + + + + + + /// + /// Destroys a Component attached to the Docker + /// + /// + public void Destroy([ComponentNotNull,DockerOwns] Component __component) { + if(!ComponentNotNull.VerifyOrThrow(__component)) return; + if(!DockerOwns.VerifyOrThrow(this, __component)) return; + + __component.TryEvent(5); + __component.ChainEvent(5); + + RemoveComponentFromLists(__component); + __component.ComponentDocker = null; + + __component.Dispose(); + } + + + + /// + /// Destroys the first found Component of a given type + /// + /// Type of Component to destroy + public void Destroy<__Type>() where __Type : Component => Destroy(Get<__Type>()); + + + + /// + /// Destroys all Components from a given collection. + /// + /// + public void DestroyAll([ComponentNotNull, DockerOwns] Collection __Components) { for (var i = 0; i < __Components.Count; i++) Destroy(__Components[i]); } + + + + /// + /// Destroys all Components of a given type + /// + /// + public void DestroyAll<__Type>() where __Type : Component => DestroyAll(GetAll<__Type>()); + + + + /// + /// Destroys all Components attached to Docker + /// + public void DestroyAll() { for(var i = 0; i < _Components.Count; i++) Destroy(_Components[i]); } +} \ No newline at end of file diff --git a/AwperativeKernel/Kernel/Debug/Debug.cs b/AwperativeKernel/Kernel/Debug/Debug.cs index d1fb2ba..a5885ae 100644 --- a/AwperativeKernel/Kernel/Debug/Debug.cs +++ b/AwperativeKernel/Kernel/Debug/Debug.cs @@ -146,15 +146,17 @@ public static class Debug /// /// Message to debug public static void LogError(string __message) => LogGeneric(__message, "ERR", [], []); - + /// /// Writes the current message to the log file. With any given call sign. /// /// Message to debug /// Names of values to debug /// Values to debug - public static void LogError(string __message, string[] __parameters, string[] __values) => LogGeneric(__message, "ERR", __parameters, __values); - + public static void LogError(string __message, string[] __parameters, string[] __values) { + if(Awperative.DebugErrors) LogGeneric(__message, "ERR", __parameters, __values, Awperative.ThrowExceptions); + } + /// /// Writes the current message to the log file if the condition is true. /// @@ -173,11 +175,14 @@ public static class Debug /// Message identifier /// Names of values to debug /// Values to debug - public static void LogGeneric(string __message, string __callSign, string[] __parameters, string[] __values) { + /// Should this throw an exception instead + public static void LogGeneric(string __message, string __callSign, string[] __parameters, string[] __values, bool __exception = false) { string output = "\n\n" + __callSign + "- \"" + __message + "\"\n STK-" + new StackTrace(); for (int i = 0; i < __parameters.Length || i < __values.Length; i++) output += "\n " + __parameters[i] + "- " + __values[i]; + + if (__exception) throw new Exception(output); File.AppendAllText(LogFilePath, output); } diff --git a/AwperativeKernel/Kernel/Overhead/Awperative/Awperative.cs b/AwperativeKernel/Kernel/Overhead/Awperative/Awperative.cs index ae6b605..33fcbb9 100644 --- a/AwperativeKernel/Kernel/Overhead/Awperative/Awperative.cs +++ b/AwperativeKernel/Kernel/Overhead/Awperative/Awperative.cs @@ -2,7 +2,9 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Linq.Expressions; using System.Reflection; @@ -44,6 +46,7 @@ public static class Awperative public static bool DebugMode = false; + @@ -111,22 +114,37 @@ public static class Awperative foreach (Type type in Assembly.GetCallingAssembly().GetTypes()) { if (type.IsSubclassOf(typeof(Component))) { + + Action[] timeEvents = new Action[ComponentEvents.Count]; + byte eventProfile = 0; List debugProfile = []; for(int i = 0; i < ComponentEvents.Count; i++) { - if (type.GetMethod(ComponentEvents[i]) != null) { - eventProfile |= (byte)(1 << i); + MethodInfo eventMethod = type.GetMethod(ComponentEvents[i]); + + if (eventMethod != null) { + debugProfile.Add(ComponentEvents[i]); - } + + var ComponentInstanceParameter = Expression.Parameter(typeof(Component), "__component"); + var Casting = Expression.Convert(ComponentInstanceParameter, type); + var Call = Expression.Call(Casting, eventMethod); + var Lambda = Expression.Lambda>(Call, ComponentInstanceParameter); + timeEvents[i] = Lambda.Compile(); + + } else timeEvents[i] = null; } Debug.LogAction("Evaluated Component! ", ["Type", "Time Events", "Profile"], [type.Name, "[" + string.Join(", ", debugProfile.Select(x => x.ToString())) + "]", eventProfile.ToString()]); - _TypeAssociatedTimeEvents.Add(type, eventProfile); + _TypeAssociatedTimeEvents.Add(type, timeEvents); } } + + + } @@ -134,6 +152,7 @@ public static class Awperative /// /// Starts Awperative up! This method runs forever. /// + [DoesNotReturn] public static void Run() { Base = new Base(); Base.Run(); @@ -158,5 +177,30 @@ public static class Awperative /// List of all type of components and the associated time events /// Each event is a 0 or 1 based on true or false, stored at their index in the byte /// - internal static Dictionary _TypeAssociatedTimeEvents = []; + internal static Dictionary[]> _TypeAssociatedTimeEvents = []; + + + + public static SafetyLevel safetyLevel { + get => _safetyLevel; + set { + ThrowExceptions = value is SafetyLevel.Extreme; + IgnoreErrors = value is SafetyLevel.Low or SafetyLevel.None; + DebugErrors = value is not SafetyLevel.None; + _safetyLevel = value; + } + } private static SafetyLevel _safetyLevel; + + public static bool ThrowExceptions { get; private set; } = false; + public static bool IgnoreErrors { get; private set; } = false; + public static bool DebugErrors { get; private set; } = true; + + + //What to do if there is an error, keep in mind low and none still can have errors, because you are turning off validation checking + public enum SafetyLevel { + Extreme, //Throw exceptions and stop the whole program + Normal, //Just debug it to the console, and halt current process + Low, //Push through tasks but debug error + None, //Ignore most/all errors and do not debug it, + } } \ No newline at end of file diff --git a/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.AssemblyInfo.cs b/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.AssemblyInfo.cs index 1c415ff..f3ac88e 100644 --- a/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.AssemblyInfo.cs +++ b/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.AssemblyInfo.cs @@ -13,7 +13,7 @@ using System.Reflection; [assembly: System.Reflection.AssemblyCompanyAttribute("AwperativeKernel")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+32fdae32482131f6e177956aee0f9ddcdf9877cf")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+abd47153ad47e5c2d5300dcab27ac4628f468ab1")] [assembly: System.Reflection.AssemblyProductAttribute("AwperativeKernel")] [assembly: System.Reflection.AssemblyTitleAttribute("AwperativeKernel")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] diff --git a/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.AssemblyInfoInputs.cache b/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.AssemblyInfoInputs.cache index d42d723..5663421 100644 --- a/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.AssemblyInfoInputs.cache +++ b/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.AssemblyInfoInputs.cache @@ -1 +1 @@ -22a4163440a667e1fc9f683e846ca5e0db424c2a4e8629dde601d67fa1038af8 +8e04a8f03c26d3cf7cdf50da4979193904b566d6f40392f132e749a5bd9092b9 diff --git a/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.csproj.CoreCompileInputs.cache b/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.csproj.CoreCompileInputs.cache index c5e7555..29e9348 100644 --- a/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.csproj.CoreCompileInputs.cache +++ b/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.csproj.CoreCompileInputs.cache @@ -1 +1 @@ -1492481e4eae3b80db2d149ab088600d21214f29161b6bc87c6dbab466600b9b +e4b135c3045a438e4953bde74a036a568da5652715efda203daab787973e7f7e diff --git a/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.dll b/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.dll index f7d5ab8..89b7af5 100644 Binary files a/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.dll and b/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.dll differ diff --git a/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.pdb b/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.pdb index 33d249e..8e3e3bf 100644 Binary files a/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.pdb and b/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.pdb differ diff --git a/AwperativeKernel/obj/Debug/net8.0/ref/AwperativeKernel.dll b/AwperativeKernel/obj/Debug/net8.0/ref/AwperativeKernel.dll index 7ca0f88..1b1cce7 100644 Binary files a/AwperativeKernel/obj/Debug/net8.0/ref/AwperativeKernel.dll and b/AwperativeKernel/obj/Debug/net8.0/ref/AwperativeKernel.dll differ diff --git a/AwperativeKernel/obj/Debug/net8.0/refint/AwperativeKernel.dll b/AwperativeKernel/obj/Debug/net8.0/refint/AwperativeKernel.dll index 7ca0f88..1b1cce7 100644 Binary files a/AwperativeKernel/obj/Debug/net8.0/refint/AwperativeKernel.dll and b/AwperativeKernel/obj/Debug/net8.0/refint/AwperativeKernel.dll differ