diff --git a/AwperativeKernel/Kernel/Component/Component.cs b/AwperativeKernel/Kernel/Component/Component.cs index 9066d84..bb9eba6 100644 --- a/AwperativeKernel/Kernel/Component/Component.cs +++ b/AwperativeKernel/Kernel/Component/Component.cs @@ -1,6 +1,8 @@ +using System; using System.Collections.Generic; using System.Collections.Immutable; - +using System.Linq; +using System.Reflection; namespace AwperativeKernel; @@ -34,6 +36,16 @@ public abstract partial class Component : ComponentDocker + /// + internal List EventDelegates; + + + + + + + + /// /// Order for when Components are called on. Only applies between Components on the same Docker. /// @@ -54,49 +66,23 @@ public abstract partial class Component : ComponentDocker ComponentDocker = __parent; Name = __name; _tags = [..__tags]; - Create(); + + EventDelegates = new List(); for(int i = 0; i < Awperative.allEvents.Count; i++) EventDelegates.Add(null); + + + if (Awperative._TypeAssociatedTimeEvents.TryGetValue(GetType(), out HashSet presentEvents)) { + foreach (Awperative.TimeEvent presentEvent in presentEvents) { + MethodInfo info = GetType().GetMethod(presentEvent.ToString()); + Action newAction = (Action)Delegate.CreateDelegate(typeof(Action), this, info); + EventDelegates[(int)presentEvent] = newAction; + } + } else { + Debug.LogError("Awperative does not recognize the given type! Perhaps it was created after Start() was called?", ["Type"], [GetType().ToString()]); + } } - - - /// - /// Called when the Game is Closing; does not always happen depending on if it is Force Closed. - /// - protected internal virtual void Unload() {} - - /// - /// Called when the Game is Loading. - /// - protected internal virtual void Load() {} - - - - /// - /// Called every frame before Draw, it is recommended to do any Non-Drawing update logic here. - /// - protected internal virtual void Update() {} - - /// - /// Called after Update when the screen is being drawn. Please only put Drawing related logic here. - /// - protected internal virtual void Draw() {} - - - - /// - /// Called when the Component is created. - /// - protected internal virtual void Create() {} - - /// - /// Called when the Component is destroyed. Not called when the Game is closed. - /// - protected internal virtual void Destroy() {} - - - /// @@ -237,4 +223,34 @@ public abstract partial class Component : ComponentDocker /// /// Name of the Scene public void RemoveScene(string __name) => Awperative.CloseScene(__name); + + + + public ImmutableArray GetAllChildren() { + List targets = [.._Components]; + for (int i = 0; i < targets.Count; i++) targets.InsertRange(i + 1, targets[i]._Components); + return [..targets]; + } + + + + internal ImmutableArray GetAllEvents() { + if (Awperative._TypeAssociatedTimeEvents.TryGetValue(this.GetType(), out HashSet timeEvents)) { + return [..timeEvents]; + } else { + Debug.LogError("Awperative doesn't recognize this type. Perhaps it was created after Start() was called?", ["Type"], [this.GetType().Name]); + return []; + } + } + + + internal ImmutableArray GetAllGlobalEvents() { + if (Awperative._TypeAssociatedTimeEvents.TryGetValue(this.GetType(), out HashSet timeEvents)) { + foreach (Awperative.TimeEvent timeEvent in timeEvents) if (!Awperative.globalEvents.Contains(timeEvent)) timeEvents.Remove(timeEvent); + return [..timeEvents]; + } else { + Debug.LogError("Awperative doesn't recognize this type. Perhaps it was created after Start() was called?", ["Type"], [this.GetType().Name]); + return []; + } + } } \ No newline at end of file diff --git a/AwperativeKernel/Kernel/ComponentDocker/ComponentDocker.cs b/AwperativeKernel/Kernel/ComponentDocker/ComponentDocker.cs index 1614edb..40b0bf9 100644 --- a/AwperativeKernel/Kernel/ComponentDocker/ComponentDocker.cs +++ b/AwperativeKernel/Kernel/ComponentDocker/ComponentDocker.cs @@ -58,66 +58,47 @@ public abstract class ComponentDocker /// 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); + //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); - } _Components.Add(__component); + 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); } - - - - - - - - /// - /// Called by Awperative when the game is Closed, sends the event to all children; and they send it to their children. + /// Chains an event to all children, NOT MEANT FOR UPDATE OR DRAW ETC, JUST CREATE AND DESTROY /// - /// 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(); } } } + /// + internal void TryEvent(Component __component, Awperative.TimeEvent __timeEvent) { + __component.EventDelegates[(int)__timeEvent]?.Invoke(); + } - + //internal void TryEvent(Component __component, Awperative.TimeEvent __timeEvent) => __component.TryEvent(__timeEvent); + + /// - /// Called by Awperative when the game is Updated sends the event to all children; and they send it to their children. + /// Chains an event to all children, NOT MEANT FOR UPDATE OR DRAW ETC, JUST CREATE AND DESTROY /// - 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(); } } } - - - - + /// + 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()"); + } @@ -167,7 +148,9 @@ public abstract class ComponentDocker //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; } @@ -547,12 +530,13 @@ public abstract class ComponentDocker [__component.GetHashCode().ToString(), __component.GetType().ToString(), GetHashCode().ToString()]); return; } - __component.Destroy(); - __component.ChainDestroy(); + __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); } diff --git a/AwperativeKernel/Kernel/Overhead/Awperative/Awperative.cs b/AwperativeKernel/Kernel/Overhead/Awperative/Awperative.cs index 6e5059c..77e8f2e 100644 --- a/AwperativeKernel/Kernel/Overhead/Awperative/Awperative.cs +++ b/AwperativeKernel/Kernel/Overhead/Awperative/Awperative.cs @@ -1,7 +1,8 @@ +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; - +using System.Reflection; namespace AwperativeKernel; @@ -33,11 +34,11 @@ public static class Awperative /// public static ImmutableArray Scenes => [.._scenes]; internal static HashSet _scenes { get; private set; } = []; - - - - - + + + + + /// /// Creates a new Scene /// @@ -94,6 +95,30 @@ public static class Awperative /// You cannot add new hooks later; so make sure to register all of them in the Start() method. public static void Start() { Debug.Initiate(); + + //Load in all Components nd find the associated types. + Debug.LogAction("Evaluating Components!"); + foreach (Type type in Assembly.GetCallingAssembly().GetTypes()) { + if (type.IsSubclassOf(typeof(Component))) { + + List presentEvents = []; + + foreach (TimeEvent timeType in allEvents) { + if (type.GetMethod(timeType.ToString()) != null) { + presentEvents.Add(timeType); + Debug.LogState("Found Event Method " + timeType); + } + } + + + + Debug.LogAction("Evaluated Component! ", ["Type", "Time Events"], [type.Name, "[" + string.Join(", ", presentEvents.Select(x => x.ToString())) + "]"]); + _TypeAssociatedTimeEvents.Add(type, presentEvents.ToHashSet()); + } + } + + foreach (TimeEvent timeType in globalEvents) + _TimeBasedComponents.Add(timeType, new SortedSet(_componentSorter)); } @@ -105,8 +130,56 @@ public static class Awperative Base = new Base(); Base.Run(); } + + + + /// + /// + /// + internal enum TimeEvent + { + Create, + Destroy, + Load, + Unload, + Update, + Draw + } + + + + internal static ImmutableHashSet allEvents = [..Enum.GetValuesAsUnderlyingType().Cast()]; + internal static ImmutableHashSet globalEvents = [TimeEvent.Load, TimeEvent.Unload, TimeEvent.Update, TimeEvent.Draw]; + + + + /// + /// List of all type of components and the associated time events + /// + internal static Dictionary> _TypeAssociatedTimeEvents = new(new TypeComparer()); + + + internal class TypeComparer : IEqualityComparer + { + public bool Equals(Type __a, Type __b) { + return __a.Equals(__b); + } + + public int GetHashCode(Type __type) { + return __type.GetHashCode(); + } + } + + + internal static Dictionary> _TimeBasedComponents = []; - + /// + /// How Priority is sorted. + /// + internal readonly static Comparer _componentSorter = Comparer.Create((a, b) => { + int result = b.Priority.CompareTo(a.Priority); + return (result != 0) ? result : a.GetHashCode().CompareTo(b.GetHashCode()); + }); } \ No newline at end of file diff --git a/AwperativeKernel/Kernel/Overhead/Base/Base.cs b/AwperativeKernel/Kernel/Overhead/Base/Base.cs index efa70dd..5465e3a 100644 --- a/AwperativeKernel/Kernel/Overhead/Base/Base.cs +++ b/AwperativeKernel/Kernel/Overhead/Base/Base.cs @@ -22,7 +22,7 @@ public sealed class Base() : GameWindow(GameWindowSettings.Default, new NativeWi /// LoadContent() is called when the program starts; right after Initialize(). Override Load() in scripting tools or use hooks to call from this event. /// /// It is recommended to load content during LoadContent() - protected override void OnLoad() { foreach(Scene scene in Awperative.Scenes.ToList()) if(scene.Enabled) scene.ChainLoad(); } + protected override void OnLoad() { foreach (Component component in Awperative._TimeBasedComponents[Awperative.TimeEvent.Load].ToList()) component.ChainEvent(Awperative.TimeEvent.Load); base.OnLoad(); } @@ -32,7 +32,7 @@ public sealed class Base() : GameWindow(GameWindowSettings.Default, new NativeWi /// Update() is called every frame; before Draw(). Override Update() in scripting tools to call from this event. /// /// Hooks are unable to receive both Update() and Draw() - protected override void OnUpdateFrame(FrameEventArgs __args) { foreach(Scene scene in Awperative.Scenes.ToList()) if(scene.Enabled) scene.ChainUpdate(); base.OnUpdateFrame(__args); } + protected override void OnUpdateFrame(FrameEventArgs __args) { foreach (Component component in Awperative._TimeBasedComponents[Awperative.TimeEvent.Update].ToList()) component.ChainEvent(Awperative.TimeEvent.Update); base.OnUpdateFrame(__args); } @@ -42,17 +42,17 @@ public sealed class Base() : GameWindow(GameWindowSettings.Default, new NativeWi /// Draw() is called every frame; after Update(). Override Draw() in scripting tools to call from this event. /// /// Hooks are unable to receive both Update() and Draw() - protected override void OnRenderFrame(FrameEventArgs __args) { foreach(Scene scene in Awperative.Scenes.ToList()) if(scene.Enabled) scene.ChainDraw(); base.OnRenderFrame(__args); } - - - - + protected override void OnRenderFrame(FrameEventArgs __args) { foreach (Component component in Awperative._TimeBasedComponents[Awperative.TimeEvent.Draw].ToList()) component.ChainEvent(Awperative.TimeEvent.Draw); base.OnRenderFrame(__args); } + + + + /// /// EndRun() is called if the program closes. Override Terminate() in scripting tools or use hooks to call from this event. /// /// This event may not trigger if the program is force closed. - protected override void OnClosing(CancelEventArgs __args) { foreach (Scene scene in Awperative.Scenes.ToList()) if(scene.Enabled) scene.ChainUnload(); base.OnClosing(__args); } + protected override void OnClosing(CancelEventArgs __args) { foreach (Component component in Awperative._TimeBasedComponents[Awperative.TimeEvent.Unload].ToList()) component.ChainEvent(Awperative.TimeEvent.Unload); base.OnClosing(__args); } diff --git a/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.AssemblyInfo.cs b/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.AssemblyInfo.cs index 3deef72..dc4b3c6 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+c40a76cc10915d9844dfa62ddb575c0d970a66d3")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+75ebac61d0dfcd3286436ea7839c6d4506b0440e")] [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 1fcd983..989c3dd 100644 --- a/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.AssemblyInfoInputs.cache +++ b/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.AssemblyInfoInputs.cache @@ -1 +1 @@ -dbcab0853d7691ebbc60aad204f24413a91ac102969db8ce430a2cb755d1f2f2 +9247c7222c48f63b20f7850bc43f8a7199e69898cd844fe346be865677a16d9c diff --git a/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.dll b/AwperativeKernel/obj/Debug/net8.0/AwperativeKernel.dll index d8d83f6..73b5957 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 e660286..b3e302a 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 8648bdc..74ab340 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 8648bdc..74ab340 100644 Binary files a/AwperativeKernel/obj/Debug/net8.0/refint/AwperativeKernel.dll and b/AwperativeKernel/obj/Debug/net8.0/refint/AwperativeKernel.dll differ