diff --git a/MiraAPI.Example/ExampleEventHandlers.cs b/MiraAPI.Example/ExampleEventHandlers.cs index e196b28..e2368f7 100644 --- a/MiraAPI.Example/ExampleEventHandlers.cs +++ b/MiraAPI.Example/ExampleEventHandlers.cs @@ -12,11 +12,7 @@ public static class ExampleEventHandlers { public static void Initialize() { - // Register event handlers here - MiraEventManager.RegisterEventHandler>(FreezeButtonClickHandler, 1); - MiraEventManager.RegisterEventHandler>(FreezeButtonCancelledHandler); - MiraEventManager.RegisterEventHandler(UpdateSystemEventHandler); - + // You can register event handlers with the MiraEventManager class. MiraEventManager.RegisterEventHandler(@event => { Logger.Info($"{@event.Source.Data.PlayerName} is about to kill {@event.Target.Data.PlayerName}"); @@ -33,12 +29,15 @@ public static class ExampleEventHandlers }); } + // Events can be registered using an attribute as well. + [RegisterEvent] public static void UpdateSystemEventHandler(UpdateSystemEvent @event) { Logger.Error(@event.SystemType.ToString()); } // Example event handler + [RegisterEvent(1)] public static void FreezeButtonClickHandler(MiraButtonClickEvent @event) { Logger.Warning("Freeze button clicked!"); @@ -51,6 +50,7 @@ public static class ExampleEventHandlers } // Example event handler + [RegisterEvent] public static void FreezeButtonCancelledHandler(MiraButtonCancelledEvent @event) { Logger.Warning("Freeze button cancelled!"); diff --git a/MiraAPI/Events/MiraEventManager.cs b/MiraAPI/Events/MiraEventManager.cs index eff933d..b375504 100644 --- a/MiraAPI/Events/MiraEventManager.cs +++ b/MiraAPI/Events/MiraEventManager.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Reflection; +using Reactor.Utilities; namespace MiraAPI.Events; @@ -54,6 +56,30 @@ public static class MiraEventManager return true; } + /// + /// Register an event. + /// + /// The type of event. + /// The MethodInfo of the event handler. + /// The priority of the event handler. Higher values are called first. + public static void RegisterEventHandler(Type type, MethodInfo methodInfo, int priority = 0) + { + if (!type.IsSubclassOf(typeof(MiraEvent))) + { + Logger.Error($"Type must be a subclass of MiraEvent: {nameof(type)}"); + return; + } + + if (!EventWrappers.TryGetValue(type, out var handlers)) + { + handlers = []; + EventWrappers.Add(type, handlers); + } + + var @delegate = Delegate.CreateDelegate(typeof(Action<>).MakeGenericType(type), methodInfo); + handlers.Add(new MiraEventWrapper(@delegate, priority)); + } + /// /// Register an event. /// diff --git a/MiraAPI/Events/RegisterEventAttribute.cs b/MiraAPI/Events/RegisterEventAttribute.cs new file mode 100644 index 0000000..6988d79 --- /dev/null +++ b/MiraAPI/Events/RegisterEventAttribute.cs @@ -0,0 +1,24 @@ +using System; + +namespace MiraAPI.Events; + +/// +/// Register an event. +/// +[AttributeUsage(AttributeTargets.Method)] +public class RegisterEventAttribute : Attribute +{ + /// + /// Gets the priority of the event. + /// + public int Priority { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The priority of the event. + public RegisterEventAttribute(int priority = 0) + { + Priority = priority; + } +} diff --git a/MiraAPI/PluginLoading/MiraPluginManager.cs b/MiraAPI/PluginLoading/MiraPluginManager.cs index 42be8e0..1fc6be7 100644 --- a/MiraAPI/PluginLoading/MiraPluginManager.cs +++ b/MiraAPI/PluginLoading/MiraPluginManager.cs @@ -49,6 +49,24 @@ public sealed class MiraPluginManager continue; } + foreach (var method in type.GetMethods(BindingFlags.Static | BindingFlags.Public)) + { + var eventAttribute = method.GetCustomAttribute(); + if (eventAttribute != null) + { + Logger.Message("Registering event"); + var parameters = method.GetParameters(); + if (parameters.Length != 1 || !parameters[0].ParameterType.IsSubclassOf(typeof(MiraEvent))) + { + Logger.Error($"Invalid event registration method {method.Name} in {type.Name}"); + continue; + } + + var paramType = parameters[0].ParameterType; + MiraEventManager.RegisterEventHandler(paramType, method, eventAttribute.Priority); + } + } + if (RegisterModifier(type, info)) { continue;