Got Some Early Reflection

This commit is contained in:
2026-02-24 19:52:30 -05:00
parent 75ebac61d0
commit abccecd295
10 changed files with 180 additions and 107 deletions

View File

@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
namespace AwperativeKernel; namespace AwperativeKernel;
@@ -34,6 +36,16 @@ public abstract partial class Component : ComponentDocker
///
internal List<Action> EventDelegates;
/// <summary> /// <summary>
/// Order for when Components are called on. Only applies between Components on the same Docker. /// Order for when Components are called on. Only applies between Components on the same Docker.
/// </summary> /// </summary>
@@ -54,46 +66,20 @@ public abstract partial class Component : ComponentDocker
ComponentDocker = __parent; ComponentDocker = __parent;
Name = __name; Name = __name;
_tags = [..__tags]; _tags = [..__tags];
Create();
EventDelegates = new List<Action>(); for(int i = 0; i < Awperative.allEvents.Count; i++) EventDelegates.Add(null);
if (Awperative._TypeAssociatedTimeEvents.TryGetValue(GetType(), out HashSet<Awperative.TimeEvent> 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()]);
}
} }
/// <summary>
/// Called when the Game is Closing; does not always happen depending on if it is Force Closed.
/// </summary>
protected internal virtual void Unload() {}
/// <summary>
/// Called when the Game is Loading.
/// </summary>
protected internal virtual void Load() {}
/// <summary>
/// Called every frame before Draw, it is recommended to do any Non-Drawing update logic here.
/// </summary>
protected internal virtual void Update() {}
/// <summary>
/// Called after Update when the screen is being drawn. Please only put Drawing related logic here.
/// </summary>
protected internal virtual void Draw() {}
/// <summary>
/// Called when the Component is created.
/// </summary>
protected internal virtual void Create() {}
/// <summary>
/// Called when the Component is destroyed. Not called when the Game is closed.
/// </summary>
protected internal virtual void Destroy() {}
@@ -237,4 +223,34 @@ public abstract partial class Component : ComponentDocker
/// </summary> /// </summary>
/// <param name="__name">Name of the Scene</param> /// <param name="__name">Name of the Scene</param>
public void RemoveScene(string __name) => Awperative.CloseScene(__name); public void RemoveScene(string __name) => Awperative.CloseScene(__name);
public ImmutableArray<Component> GetAllChildren() {
List<Component> targets = [.._Components];
for (int i = 0; i < targets.Count; i++) targets.InsertRange(i + 1, targets[i]._Components);
return [..targets];
}
internal ImmutableArray<Awperative.TimeEvent> GetAllEvents() {
if (Awperative._TypeAssociatedTimeEvents.TryGetValue(this.GetType(), out HashSet<Awperative.TimeEvent> 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<Awperative.TimeEvent> GetAllGlobalEvents() {
if (Awperative._TypeAssociatedTimeEvents.TryGetValue(this.GetType(), out HashSet<Awperative.TimeEvent> 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 [];
}
}
} }

View File

@@ -58,66 +58,47 @@ public abstract class ComponentDocker
/// <param name="__component"> Component to modify</param> /// <param name="__component"> Component to modify</param>
/// <param name="__priority"> New priority for Component</param> /// <param name="__priority"> New priority for Component</param>
internal void UpdatePriority(Component __component, int __priority) { internal void UpdatePriority(Component __component, int __priority) {
foreach (String tag in __component._tags) { //add ownership enforcement/method
_taggedComponents[tag].Remove(__component);
} _Components.Remove(__component); 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; __component._priority = __priority;
foreach (String tag in __component._tags) { foreach (String tag in __component._tags) _taggedComponents[tag].Add(__component);
_taggedComponents[tag].Add(__component); foreach (Awperative.TimeEvent timeEvent in __component.GetAllEvents()) { Awperative._TimeBasedComponents[timeEvent].Add(__component);}
} _Components.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> /// <summary>
/// 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
/// </summary> /// </summary>
/// <remarks> Will not always trigger if the program is force closed </remarks> /// <param name="__timeEvent"></param>
internal virtual void ChainUnload() { foreach (Component component in (Component[])[.._Components]) { if(component.Enabled) { component.Unload(); component.ChainUnload(); } } } internal void ChainEvent(Awperative.TimeEvent __timeEvent) {
/// <summary>
/// Called by Awperative when the game is Opened, sends the event to all children; and they send it to their children.
/// </summary>
internal virtual void ChainLoad() { foreach (Component component in (Component[])[.._Components]) { if(component.Enabled) { component.Load(); component.ChainLoad(); } } }
/// <summary>
/// Called by Awperative when the game is Updated sends the event to all children; and they send it to their children.
/// </summary>
internal virtual void ChainUpdate() { foreach (Component component in (Component[])[.._Components]) { if(component.Enabled) { component.Update(); component.ChainUpdate(); } } }
/// <summary>
/// Called by Awperative when the game is Drawn, sends the event to all children; and they send it to their children.
/// </summary>
/// <remarks> Only use this method for drawing methods</remarks>
internal virtual void ChainDraw() { foreach (Component component in (Component[])[.._Components]) { if(component.Enabled) { component.Draw(); component.ChainDraw(); } } }
/// <summary>
/// Called by Awperative when this is Created, sends the event to all children; and they send it to their children.
/// </summary>
internal virtual void ChainCreate() { foreach (Component component in (Component[])[.._Components]) { if(component.Enabled) { component.Create(); component.ChainCreate(); } } }
/// <summary>
/// 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.
/// </summary>
/// <remarks> Not called when the game is closed</remarks>
internal virtual void ChainDestroy() { foreach(Component component in (Component[])[.._Components]) { if(component.Enabled) { component.Destroy(); component.ChainDestroy(); } } }
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 //Add to docker and initialize the new Component
_Components.Add(newComponent); _Components.Add(newComponent);
newComponent.Initiate(this, name, tags); 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; return (__Type) newComponent;
} }
@@ -547,12 +530,13 @@ public abstract class ComponentDocker
[__component.GetHashCode().ToString(), __component.GetType().ToString(), GetHashCode().ToString()]); return; [__component.GetHashCode().ToString(), __component.GetType().ToString(), GetHashCode().ToString()]); return;
} }
__component.Destroy(); __component.ChainEvent(Awperative.TimeEvent.Destroy);
__component.ChainDestroy();
foreach (string tag in __component._tags) UnhashTaggedComponent(__component, tag); foreach (string tag in __component._tags) UnhashTaggedComponent(__component, tag);
__component.ComponentDocker = null; __component.ComponentDocker = null;
_Components.Remove(__component); _Components.Remove(__component);
foreach (Awperative.TimeEvent timeEvent in __component.GetAllEvents()) Awperative._TimeBasedComponents[timeEvent].Remove(__component);
} }

View File

@@ -1,7 +1,8 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Reflection;
namespace AwperativeKernel; namespace AwperativeKernel;
@@ -94,6 +95,30 @@ public static class Awperative
/// <remarks> You cannot add new hooks later; so make sure to register all of them in the Start() method.</remarks> /// <remarks> You cannot add new hooks later; so make sure to register all of them in the Start() method.</remarks>
public static void Start() { public static void Start() {
Debug.Initiate(); 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<TimeEvent> 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<Component>(_componentSorter));
} }
@@ -108,5 +133,53 @@ public static class Awperative
/// <summary>
///
/// </summary>
internal enum TimeEvent
{
Create,
Destroy,
Load,
Unload,
Update,
Draw
}
internal static ImmutableHashSet<TimeEvent> allEvents = [..Enum.GetValuesAsUnderlyingType<TimeEvent>().Cast<TimeEvent>()];
internal static ImmutableHashSet<TimeEvent> globalEvents = [TimeEvent.Load, TimeEvent.Unload, TimeEvent.Update, TimeEvent.Draw];
/// <summary>
/// List of all type of components and the associated time events
/// </summary>
internal static Dictionary<Type, HashSet<TimeEvent>> _TypeAssociatedTimeEvents = new(new TypeComparer());
internal class TypeComparer : IEqualityComparer<Type>
{
public bool Equals(Type __a, Type __b) {
return __a.Equals(__b);
}
public int GetHashCode(Type __type) {
return __type.GetHashCode();
}
}
internal static Dictionary<TimeEvent, SortedSet<Component>> _TimeBasedComponents = [];
/// <summary>
/// How Priority is sorted.
/// </summary>
internal 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());
});
} }

View File

@@ -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. /// LoadContent() is called when the program starts; right after Initialize(). Override Load() in scripting tools or use hooks to call from this event.
/// </summary> /// </summary>
/// <remarks> It is recommended to load content during LoadContent()</remarks> /// <remarks> It is recommended to load content during LoadContent()</remarks>
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. /// Update() is called every frame; before Draw(). Override Update() in scripting tools to call from this event.
/// </summary> /// </summary>
/// <remarks> Hooks are unable to receive both Update() and Draw()</remarks> /// <remarks> Hooks are unable to receive both Update() and Draw()</remarks>
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,7 +42,7 @@ 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. /// Draw() is called every frame; after Update(). Override Draw() in scripting tools to call from this event.
/// </summary> /// </summary>
/// <remarks> Hooks are unable to receive both Update() and Draw()</remarks> /// <remarks> Hooks are unable to receive both Update() and Draw()</remarks>
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); }
@@ -52,7 +52,7 @@ public sealed class Base() : GameWindow(GameWindowSettings.Default, new NativeWi
/// EndRun() is called if the program closes. Override Terminate() in scripting tools or use hooks to call from this event. /// EndRun() is called if the program closes. Override Terminate() in scripting tools or use hooks to call from this event.
/// </summary> /// </summary>
/// <remarks> This event may not trigger if the program is force closed.</remarks> /// <remarks> This event may not trigger if the program is force closed.</remarks>
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); }

View File

@@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("AwperativeKernel")] [assembly: System.Reflection.AssemblyCompanyAttribute("AwperativeKernel")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] [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.AssemblyProductAttribute("AwperativeKernel")]
[assembly: System.Reflection.AssemblyTitleAttribute("AwperativeKernel")] [assembly: System.Reflection.AssemblyTitleAttribute("AwperativeKernel")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

View File

@@ -1 +1 @@
dbcab0853d7691ebbc60aad204f24413a91ac102969db8ce430a2cb755d1f2f2 9247c7222c48f63b20f7850bc43f8a7199e69898cd844fe346be865677a16d9c