diff --git a/Exiled.Events/Features/Event.cs b/Exiled.Events/Features/Event.cs index 141def259f..c27c657030 100644 --- a/Exiled.Events/Features/Event.cs +++ b/Exiled.Events/Features/Event.cs @@ -13,12 +13,19 @@ namespace Exiled.Events.Features using Exiled.API.Features; using Exiled.Events.EventArgs.Interfaces; + using MEC; /// /// The custom delegate, with empty parameters. /// public delegate void CustomEventHandler(); + /// + /// THe custom delegate, with empty parameters. Holds async events with . + /// + /// of . + public delegate IEnumerator CustomAsyncEventHandler(); + /// /// An implementation of that encapsulates a no-argument event. /// @@ -38,6 +45,8 @@ public Event() private event CustomEventHandler InnerEvent; + private event CustomAsyncEventHandler InnerAsyncEvent; + /// /// Gets a of which contains all the instances. /// @@ -55,6 +64,18 @@ public Event() return @event; } + /// + /// Subscribes a to the inner event, and checks patches if dynamic patching is enabled. + /// + /// The to subscribe the to. + /// The to subscribe to the . + /// The with the handler added to it. + public static Event operator +(Event @event, CustomAsyncEventHandler asyncEventHandler) + { + @event.Subscribe(asyncEventHandler); + return @event; + } + /// /// Unsubscribes a target from the inner event, and checks if unpatching is possible, if dynamic patching is enabled. /// @@ -67,6 +88,18 @@ public Event() return @event; } + /// + /// Unsubscribes a target from the inner event, and checks if unpatching is possible, if dynamic patching is enabled. + /// + /// The the will be unsubscribed from. + /// The that will be unsubscribed from the . + /// The with the handler unsubscribed from it. + public static Event operator -(Event @event, CustomAsyncEventHandler asyncEventHandler) + { + @event.Unsubscribe(asyncEventHandler); + return @event; + } + /// /// Subscribes a target to the inner event if the conditional is true. /// @@ -84,6 +117,23 @@ public void Subscribe(CustomEventHandler handler) InnerEvent += handler; } + /// + /// Subscribes a target to the inner event if the conditional is true. + /// + /// The handler to add. + public void Subscribe(CustomAsyncEventHandler handler) + { + Log.Assert(Events.Instance is not null, $"{nameof(Events.Instance)} is null, please ensure you have exiled_events enabled!"); + + if (Events.Instance.Config.UseDynamicPatching && !patched) + { + Events.Instance.Patcher.Patch(this); + patched = true; + } + + InnerAsyncEvent += handler; + } + /// /// Unsubscribes a target from the inner event if the conditional is true. /// @@ -93,10 +143,26 @@ public void Unsubscribe(CustomEventHandler handler) InnerEvent -= handler; } + /// + /// Unsubscribes a target from the inner event if the conditional is true. + /// + /// The handler to add. + public void Unsubscribe(CustomAsyncEventHandler handler) + { + InnerAsyncEvent -= handler; + } + /// /// Executes all listeners safely. /// public void InvokeSafely() + { + InvokeNormal(); + InvokeAsync(); + } + + /// + internal void InvokeNormal() { if (InnerEvent is null) return; @@ -113,5 +179,24 @@ public void InvokeSafely() } } } + + /// + internal void InvokeAsync() + { + if (InnerAsyncEvent is null) + return; + + foreach (CustomAsyncEventHandler handler in InnerAsyncEvent.GetInvocationList().Cast()) + { + try + { + Timing.RunCoroutine(handler()); + } + catch (Exception ex) + { + Log.Error($"Method \"{handler.Method.Name}\" of the class \"{handler.Method.ReflectedType.FullName}\" caused an exception when handling the event \"{GetType().FullName}\"\n{ex}"); + } + } + } } } diff --git a/Exiled.Events/Features/Event{T}.cs b/Exiled.Events/Features/Event{T}.cs index f8ea5f51fd..8cbd180544 100644 --- a/Exiled.Events/Features/Event{T}.cs +++ b/Exiled.Events/Features/Event{T}.cs @@ -13,6 +13,7 @@ namespace Exiled.Events.Features using Exiled.API.Features; using Exiled.Events.EventArgs.Interfaces; + using MEC; /// /// The custom delegate. @@ -21,6 +22,14 @@ namespace Exiled.Events.Features /// The instance. public delegate void CustomEventHandler(TEventArgs ev); + /// + /// The custom delegate. + /// + /// The type. + /// The instance. + /// of . + public delegate IEnumerator CustomAsyncEventHandler(TEventArgs ev); + /// /// An implementation of the interface that encapsulates an event with arguments. /// @@ -41,6 +50,8 @@ public Event() private event CustomEventHandler InnerEvent; + private event CustomAsyncEventHandler InnerAsyncEvent; + /// /// Gets a of which contains all the instances. /// @@ -58,6 +69,18 @@ public Event() return @event; } + /// + /// Subscribes a to the inner event, and checks patches if dynamic patching is enabled. + /// + /// The to subscribe the to. + /// The to subscribe to the . + /// The with the handler added to it. + public static Event operator +(Event @event, CustomAsyncEventHandler asyncEventHandler) + { + @event.Subscribe(asyncEventHandler); + return @event; + } + /// /// Unsubscribes a target from the inner event and checks if unpatching is possible, if dynamic patching is enabled. /// @@ -70,6 +93,18 @@ public Event() return @event; } + /// + /// Unsubscribes a target from the inner event, and checks if unpatching is possible, if dynamic patching is enabled. + /// + /// The the will be unsubscribed from. + /// The that will be unsubscribed from the . + /// The with the handler unsubscribed from it. + public static Event operator -(Event @event, CustomAsyncEventHandler asyncEventHandler) + { + @event.Unsubscribe(asyncEventHandler); + return @event; + } + /// /// Subscribes a target to the inner event if the conditional is true. /// @@ -87,6 +122,23 @@ public void Subscribe(CustomEventHandler handler) InnerEvent += handler; } + /// + /// Subscribes a target to the inner event if the conditional is true. + /// + /// The handler to add. + public void Subscribe(CustomAsyncEventHandler handler) + { + Log.Assert(Events.Instance is not null, $"{nameof(Events.Instance)} is null, please ensure you have exiled_events enabled!"); + + if (Events.Instance.Config.UseDynamicPatching && !patched) + { + Events.Instance.Patcher.Patch(this); + patched = true; + } + + InnerAsyncEvent += handler; + } + /// /// Unsubscribes a target from the inner event if the conditional is true. /// @@ -96,12 +148,28 @@ public void Unsubscribe(CustomEventHandler handler) InnerEvent -= handler; } + /// + /// Unsubscribes a target from the inner event if the conditional is true. + /// + /// The handler to add. + public void Unsubscribe(CustomAsyncEventHandler handler) + { + InnerAsyncEvent -= handler; + } + /// /// Executes all listeners safely. /// /// The event argument. /// Event or its arg is . public void InvokeSafely(T arg) + { + InvokeNormal(arg); + InvokeAsync(arg); + } + + /// + internal void InvokeNormal(T arg) { if (InnerEvent is null) return; @@ -118,5 +186,24 @@ public void InvokeSafely(T arg) } } } + + /// + internal void InvokeAsync(T arg) + { + if (InnerAsyncEvent is null) + return; + + foreach (CustomAsyncEventHandler handler in InnerAsyncEvent.GetInvocationList().Cast>()) + { + try + { + Timing.RunCoroutine(handler(arg)); + } + catch (Exception ex) + { + Log.Error($"Method \"{handler.Method.Name}\" of the class \"{handler.Method.ReflectedType.FullName}\" caused an exception when handling the event \"{GetType().FullName}\"\n{ex}"); + } + } + } } }