diff --git a/.gitignore b/.gitignore
index 958e3428c7..722b747e7c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -376,4 +376,7 @@ _site/
JSON/
# Mac DS_Store
-.DS_Store
\ No newline at end of file
+.DS_Store
+
+# Code Rush
+/EXILED/.cr/*
diff --git a/EXILED/Exiled.Events/Features/Event.cs b/EXILED/Exiled.Events/Features/Event.cs
index 9885747c7e..fc5c0c4333 100644
--- a/EXILED/Exiled.Events/Features/Event.cs
+++ b/EXILED/Exiled.Events/Features/Event.cs
@@ -14,6 +14,7 @@ namespace Exiled.Events.Features
using Exiled.API.Features;
using Exiled.Events.EventArgs.Interfaces;
using MEC;
+ using PluginAPI.Roles;
///
/// The custom delegate, with empty parameters.
@@ -31,8 +32,20 @@ namespace Exiled.Events.Features
///
public class Event : IExiledEvent
{
+ private record Registration(CustomEventHandler handler, int priority);
+
+ private record AsyncRegistration(CustomAsyncEventHandler handler, int priority);
+
private static readonly List EventsValue = new();
+ private static readonly IComparer RegisterComparable = Comparer.Create((x, y) => y.priority - x.priority);
+
+ private static readonly IComparer AsyncRegisterComparable = Comparer.Create((x, y) => y.priority - x.priority);
+
+ private readonly List innerEvent = new();
+
+ private readonly List innerAsyncEvent = new();
+
private bool patched;
///
@@ -43,10 +56,6 @@ public Event()
EventsValue.Add(this);
}
- private event CustomEventHandler InnerEvent;
-
- private event CustomAsyncEventHandler InnerAsyncEvent;
-
///
/// Gets a of which contains all the instances.
///
@@ -105,6 +114,14 @@ public Event()
///
/// The handler to add.
public void Subscribe(CustomEventHandler handler)
+ => Subscribe(handler, 0);
+
+ ///
+ /// Subscribes a target to the inner event if the conditional is true.
+ ///
+ /// The handler to add.
+ /// The highest priority is the first called, the lowest the last.
+ public void Subscribe(CustomEventHandler handler, int priority)
{
Log.Assert(Events.Instance is not null, $"{nameof(Events.Instance)} is null, please ensure you have exiled_events enabled!");
@@ -114,7 +131,21 @@ public void Subscribe(CustomEventHandler handler)
patched = true;
}
- InnerEvent += handler;
+ if (handler == null)
+ return;
+
+ Registration registration = new Registration(handler, priority);
+ int index = innerEvent.BinarySearch(registration, RegisterComparable);
+ if (index < 0)
+ {
+ innerEvent.Insert(~index, registration);
+ }
+ else
+ {
+ while (index < innerEvent.Count && innerEvent[index].priority == priority)
+ index++;
+ innerEvent.Insert(index, registration);
+ }
}
///
@@ -122,6 +153,14 @@ public void Subscribe(CustomEventHandler handler)
///
/// The handler to add.
public void Subscribe(CustomAsyncEventHandler handler)
+ => Subscribe(handler, 0);
+
+ ///
+ /// Subscribes a target to the inner event if the conditional is true.
+ ///
+ /// The handler to add.
+ /// The highest priority is the first called, the lowest the last.
+ public void Subscribe(CustomAsyncEventHandler handler, int priority)
{
Log.Assert(Events.Instance is not null, $"{nameof(Events.Instance)} is null, please ensure you have exiled_events enabled!");
@@ -131,7 +170,21 @@ public void Subscribe(CustomAsyncEventHandler handler)
patched = true;
}
- InnerAsyncEvent += handler;
+ if (handler == null)
+ return;
+
+ AsyncRegistration registration = new AsyncRegistration(handler, 0);
+ int index = innerAsyncEvent.BinarySearch(registration, AsyncRegisterComparable);
+ if (index < 0)
+ {
+ innerAsyncEvent.Insert(~index, registration);
+ }
+ else
+ {
+ while (index < innerAsyncEvent.Count && innerAsyncEvent[index].priority == priority)
+ index++;
+ innerAsyncEvent.Insert(index, registration);
+ }
}
///
@@ -140,7 +193,9 @@ public void Subscribe(CustomAsyncEventHandler handler)
/// The handler to add.
public void Unsubscribe(CustomEventHandler handler)
{
- InnerEvent -= handler;
+ int index = innerEvent.FindIndex(p => p.handler == handler);
+ if (index != -1)
+ innerEvent.RemoveAt(index);
}
///
@@ -149,7 +204,9 @@ public void Unsubscribe(CustomEventHandler handler)
/// The handler to add.
public void Unsubscribe(CustomAsyncEventHandler handler)
{
- InnerAsyncEvent -= handler;
+ int index = innerAsyncEvent.FindIndex(p => p.handler == handler);
+ if (index != -1)
+ innerAsyncEvent.RemoveAt(index);
}
///
@@ -157,25 +214,61 @@ public void Unsubscribe(CustomAsyncEventHandler handler)
///
public void InvokeSafely()
{
- InvokeNormal();
- InvokeAsync();
+ BlendedInvoke();
}
///
- internal void InvokeNormal()
+ internal void BlendedInvoke()
{
- if (InnerEvent is null)
- return;
+ Registration[] innerEvent = this.innerEvent.ToArray();
+ AsyncRegistration[] innerAsyncEvent = this.innerAsyncEvent.ToArray();
+ int count = innerEvent.Length + innerAsyncEvent.Length;
+ int eventIndex = 0, asyncEventIndex = 0;
- foreach (CustomEventHandler handler in InnerEvent.GetInvocationList().Cast())
+ for (int i = 0; i < count; i++)
+ {
+ if (eventIndex < innerEvent.Length && (asyncEventIndex >= innerAsyncEvent.Length || innerEvent[eventIndex].priority >= innerAsyncEvent[asyncEventIndex].priority))
+ {
+ try
+ {
+ innerEvent[eventIndex].handler();
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"Method \"{innerEvent[eventIndex].handler.Method.Name}\" of the class \"{innerEvent[eventIndex].handler.Method.ReflectedType.FullName}\" caused an exception when handling the event \"{GetType().FullName}\"\n{ex}");
+ }
+
+ eventIndex++;
+ }
+ else
+ {
+ try
+ {
+ Timing.RunCoroutine(innerAsyncEvent[asyncEventIndex].handler());
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"Method \"{innerAsyncEvent[asyncEventIndex].handler.Method.Name}\" of the class \"{innerAsyncEvent[asyncEventIndex].handler.Method.ReflectedType.FullName}\" caused an exception when handling the event \"{GetType().FullName}\"\n{ex}");
+ }
+
+ asyncEventIndex++;
+ }
+ }
+ }
+
+ ///
+ internal void InvokeNormal()
+ {
+ Registration[] innerEvent = this.innerEvent.ToArray();
+ foreach (Registration registration in innerEvent)
{
try
{
- handler();
+ registration.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}");
+ Log.Error($"Method \"{registration.handler.Method.Name}\" of the class \"{registration.handler.Method.ReflectedType.FullName}\" caused an exception when handling the event \"{GetType().FullName}\"\n{ex}");
}
}
}
@@ -183,18 +276,16 @@ internal void InvokeNormal()
///
internal void InvokeAsync()
{
- if (InnerAsyncEvent is null)
- return;
-
- foreach (CustomAsyncEventHandler handler in InnerAsyncEvent.GetInvocationList().Cast())
+ AsyncRegistration[] innerAsyncEvent = this.innerAsyncEvent.ToArray();
+ foreach (AsyncRegistration registration in innerAsyncEvent)
{
try
{
- Timing.RunCoroutine(handler());
+ Timing.RunCoroutine(registration.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}");
+ Log.Error($"Method \"{registration.handler.Method.Name}\" of the class \"{registration.handler.Method.ReflectedType.FullName}\" caused an exception when handling the event \"{GetType().FullName}\"\n{ex}");
}
}
}
diff --git a/EXILED/Exiled.Events/Features/Event{T}.cs b/EXILED/Exiled.Events/Features/Event{T}.cs
index e9b6e546b9..2d6252b91e 100644
--- a/EXILED/Exiled.Events/Features/Event{T}.cs
+++ b/EXILED/Exiled.Events/Features/Event{T}.cs
@@ -36,8 +36,20 @@ namespace Exiled.Events.Features
/// The specified that the event will use.
public class Event : IExiledEvent
{
+ private record Registration(CustomEventHandler handler, int priority);
+
+ private record AsyncRegistration(CustomAsyncEventHandler handler, int priority);
+
private static readonly Dictionary> TypeToEvent = new();
+ private static readonly IComparer RegisterComparable = Comparer.Create((x, y) => y.priority - x.priority);
+
+ private static readonly IComparer AsyncRegisterComparable = Comparer.Create((x, y) => y.priority - x.priority);
+
+ private readonly List innerEvent = new();
+
+ private readonly List innerAsyncEvent = new();
+
private bool patched;
///
@@ -48,10 +60,6 @@ public Event()
TypeToEvent.Add(typeof(T), this);
}
- private event CustomEventHandler InnerEvent;
-
- private event CustomAsyncEventHandler InnerAsyncEvent;
-
///
/// Gets a of which contains all the instances.
///
@@ -110,6 +118,14 @@ public Event()
///
/// The handler to add.
public void Subscribe(CustomEventHandler handler)
+ => Subscribe(handler, 0);
+
+ ///
+ /// Subscribes a target to the inner event if the conditional is true.
+ ///
+ /// The handler to add.
+ /// The highest priority is the first called, the lowest the last.
+ public void Subscribe(CustomEventHandler handler, int priority)
{
Log.Assert(Events.Instance is not null, $"{nameof(Events.Instance)} is null, please ensure you have exiled_events enabled!");
@@ -119,7 +135,21 @@ public void Subscribe(CustomEventHandler handler)
patched = true;
}
- InnerEvent += handler;
+ if (handler == null)
+ return;
+
+ Registration registration = new Registration(handler, priority);
+ int index = innerEvent.BinarySearch(registration, RegisterComparable);
+ if (index < 0)
+ {
+ innerEvent.Insert(~index, registration);
+ }
+ else
+ {
+ while (index < innerEvent.Count && innerEvent[index].priority == priority)
+ index++;
+ innerEvent.Insert(index, registration);
+ }
}
///
@@ -127,6 +157,14 @@ public void Subscribe(CustomEventHandler handler)
///
/// The handler to add.
public void Subscribe(CustomAsyncEventHandler handler)
+ => Subscribe(handler, 0);
+
+ ///
+ /// Subscribes a target to the inner event if the conditional is true.
+ ///
+ /// The handler to add.
+ /// The highest priority is the first called, the lowest the last.
+ public void Subscribe(CustomAsyncEventHandler handler, int priority)
{
Log.Assert(Events.Instance is not null, $"{nameof(Events.Instance)} is null, please ensure you have exiled_events enabled!");
@@ -136,7 +174,21 @@ public void Subscribe(CustomAsyncEventHandler handler)
patched = true;
}
- InnerAsyncEvent += handler;
+ if (handler == null)
+ return;
+
+ AsyncRegistration registration = new AsyncRegistration(handler, 0);
+ int index = innerAsyncEvent.BinarySearch(registration, AsyncRegisterComparable);
+ if (index < 0)
+ {
+ innerAsyncEvent.Insert(~index, registration);
+ }
+ else
+ {
+ while (index < innerAsyncEvent.Count && innerAsyncEvent[index].priority == priority)
+ index++;
+ innerAsyncEvent.Insert(index, registration);
+ }
}
///
@@ -145,7 +197,9 @@ public void Subscribe(CustomAsyncEventHandler handler)
/// The handler to add.
public void Unsubscribe(CustomEventHandler handler)
{
- InnerEvent -= handler;
+ int index = innerEvent.FindIndex(p => p.handler == handler);
+ if (index != -1)
+ innerEvent.RemoveAt(index);
}
///
@@ -154,7 +208,9 @@ public void Unsubscribe(CustomEventHandler handler)
/// The handler to add.
public void Unsubscribe(CustomAsyncEventHandler handler)
{
- InnerAsyncEvent -= handler;
+ int index = innerAsyncEvent.FindIndex(p => p.handler == handler);
+ if (index != -1)
+ innerAsyncEvent.RemoveAt(index);
}
///
@@ -164,25 +220,61 @@ public void Unsubscribe(CustomAsyncEventHandler handler)
/// Event or its arg is .
public void InvokeSafely(T arg)
{
- InvokeNormal(arg);
- InvokeAsync(arg);
+ BlendedInvoke(arg);
}
///
- internal void InvokeNormal(T arg)
+ internal void BlendedInvoke(T arg)
{
- if (InnerEvent is null)
- return;
+ Registration[] innerEvent = this.innerEvent.ToArray();
+ AsyncRegistration[] innerAsyncEvent = this.innerAsyncEvent.ToArray();
+ int count = innerEvent.Length + innerAsyncEvent.Length;
+ int eventIndex = 0, asyncEventIndex = 0;
- foreach (CustomEventHandler handler in InnerEvent.GetInvocationList().Cast>())
+ for (int i = 0; i < count; i++)
+ {
+ if (eventIndex < innerEvent.Length && (asyncEventIndex >= innerAsyncEvent.Length || innerEvent[eventIndex].priority >= innerAsyncEvent[asyncEventIndex].priority))
+ {
+ try
+ {
+ innerEvent[eventIndex].handler(arg);
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"Method \"{innerEvent[eventIndex].handler.Method.Name}\" of the class \"{innerEvent[eventIndex].handler.Method.ReflectedType.FullName}\" caused an exception when handling the event \"{GetType().FullName}\"\n{ex}");
+ }
+
+ eventIndex++;
+ }
+ else
+ {
+ try
+ {
+ Timing.RunCoroutine(innerAsyncEvent[asyncEventIndex].handler(arg));
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"Method \"{innerAsyncEvent[asyncEventIndex].handler.Method.Name}\" of the class \"{innerAsyncEvent[asyncEventIndex].handler.Method.ReflectedType.FullName}\" caused an exception when handling the event \"{GetType().FullName}\"\n{ex}");
+ }
+
+ asyncEventIndex++;
+ }
+ }
+ }
+
+ ///
+ internal void InvokeNormal(T arg)
+ {
+ Registration[] innerEvent = this.innerEvent.ToArray();
+ foreach (Registration registration in innerEvent)
{
try
{
- handler(arg);
+ registration.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}");
+ Log.Error($"Method \"{registration.handler.Method.Name}\" of the class \"{registration.handler.Method.ReflectedType.FullName}\" caused an exception when handling the event \"{GetType().FullName}\"\n{ex}");
}
}
}
@@ -190,18 +282,16 @@ internal void InvokeNormal(T arg)
///
internal void InvokeAsync(T arg)
{
- if (InnerAsyncEvent is null)
- return;
-
- foreach (CustomAsyncEventHandler handler in InnerAsyncEvent.GetInvocationList().Cast>())
+ AsyncRegistration[] innerAsyncEvent = this.innerAsyncEvent.ToArray();
+ foreach (AsyncRegistration registration in innerAsyncEvent)
{
try
{
- Timing.RunCoroutine(handler(arg));
+ Timing.RunCoroutine(registration.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}");
+ Log.Error($"Method \"{registration.handler.Method.Name}\" of the class \"{registration.handler.Method.ReflectedType.FullName}\" caused an exception when handling the event \"{GetType().FullName}\"\n{ex}");
}
}
}