Skip to content

Commit bcdf92b

Browse files
committed
Reapply "feat: Add priority for event handlers to Exiled Events (#423)"
This reverts commit 9e87dcd.
1 parent cc0082c commit bcdf92b

3 files changed

Lines changed: 228 additions & 45 deletions

File tree

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,4 +376,7 @@ _site/
376376
JSON/
377377

378378
# Mac DS_Store
379-
.DS_Store
379+
.DS_Store
380+
381+
# Code Rush
382+
/EXILED/.cr/*

EXILED/Exiled.Events/Features/Event.cs

Lines changed: 112 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,20 @@ namespace Exiled.Events.Features
3131
/// </summary>
3232
public class Event : IExiledEvent
3333
{
34+
private record Registration(CustomEventHandler handler, int priority);
35+
36+
private record AsyncRegistration(CustomAsyncEventHandler handler, int priority);
37+
3438
private static readonly List<Event> EventsValue = new();
3539

40+
private static readonly IComparer<Registration> RegisterComparable = Comparer<Registration>.Create((x, y) => y.priority - x.priority);
41+
42+
private static readonly IComparer<AsyncRegistration> AsyncRegisterComparable = Comparer<AsyncRegistration>.Create((x, y) => y.priority - x.priority);
43+
44+
private readonly List<Registration> innerEvent = new();
45+
46+
private readonly List<AsyncRegistration> innerAsyncEvent = new();
47+
3648
private bool patched;
3749

3850
/// <summary>
@@ -43,10 +55,6 @@ public Event()
4355
EventsValue.Add(this);
4456
}
4557

46-
private event CustomEventHandler InnerEvent;
47-
48-
private event CustomAsyncEventHandler InnerAsyncEvent;
49-
5058
/// <summary>
5159
/// Gets a <see cref="IReadOnlyList{T}"/> of <see cref="Event{T}"/> which contains all the <see cref="Event{T}"/> instances.
5260
/// </summary>
@@ -105,6 +113,14 @@ public Event()
105113
/// </summary>
106114
/// <param name="handler">The handler to add.</param>
107115
public void Subscribe(CustomEventHandler handler)
116+
=> Subscribe(handler, 0);
117+
118+
/// <summary>
119+
/// Subscribes a target <see cref="CustomEventHandler"/> to the inner event if the conditional is true.
120+
/// </summary>
121+
/// <param name="handler">The handler to add.</param>
122+
/// <param name="priority">The highest priority is the first called, the lowest the last.</param>
123+
public void Subscribe(CustomEventHandler handler, int priority)
108124
{
109125
Log.Assert(Events.Instance is not null, $"{nameof(Events.Instance)} is null, please ensure you have exiled_events enabled!");
110126

@@ -114,14 +130,36 @@ public void Subscribe(CustomEventHandler handler)
114130
patched = true;
115131
}
116132

117-
InnerEvent += handler;
133+
if (handler == null)
134+
return;
135+
136+
Registration registration = new Registration(handler, priority);
137+
int index = innerEvent.BinarySearch(registration, RegisterComparable);
138+
if (index < 0)
139+
{
140+
innerEvent.Insert(~index, registration);
141+
}
142+
else
143+
{
144+
while (index < innerEvent.Count && innerEvent[index].priority == priority)
145+
index++;
146+
innerEvent.Insert(index, registration);
147+
}
118148
}
119149

120150
/// <summary>
121151
/// Subscribes a target <see cref="CustomAsyncEventHandler"/> to the inner event if the conditional is true.
122152
/// </summary>
123153
/// <param name="handler">The handler to add.</param>
124154
public void Subscribe(CustomAsyncEventHandler handler)
155+
=> Subscribe(handler, 0);
156+
157+
/// <summary>
158+
/// Subscribes a target <see cref="CustomAsyncEventHandler"/> to the inner event if the conditional is true.
159+
/// </summary>
160+
/// <param name="handler">The handler to add.</param>
161+
/// <param name="priority">The highest priority is the first called, the lowest the last.</param>
162+
public void Subscribe(CustomAsyncEventHandler handler, int priority)
125163
{
126164
Log.Assert(Events.Instance is not null, $"{nameof(Events.Instance)} is null, please ensure you have exiled_events enabled!");
127165

@@ -131,7 +169,21 @@ public void Subscribe(CustomAsyncEventHandler handler)
131169
patched = true;
132170
}
133171

134-
InnerAsyncEvent += handler;
172+
if (handler == null)
173+
return;
174+
175+
AsyncRegistration registration = new AsyncRegistration(handler, 0);
176+
int index = innerAsyncEvent.BinarySearch(registration, AsyncRegisterComparable);
177+
if (index < 0)
178+
{
179+
innerAsyncEvent.Insert(~index, registration);
180+
}
181+
else
182+
{
183+
while (index < innerAsyncEvent.Count && innerAsyncEvent[index].priority == priority)
184+
index++;
185+
innerAsyncEvent.Insert(index, registration);
186+
}
135187
}
136188

137189
/// <summary>
@@ -140,7 +192,9 @@ public void Subscribe(CustomAsyncEventHandler handler)
140192
/// <param name="handler">The handler to add.</param>
141193
public void Unsubscribe(CustomEventHandler handler)
142194
{
143-
InnerEvent -= handler;
195+
int index = innerEvent.FindIndex(p => p.handler == handler);
196+
if (index != -1)
197+
innerEvent.RemoveAt(index);
144198
}
145199

146200
/// <summary>
@@ -149,52 +203,88 @@ public void Unsubscribe(CustomEventHandler handler)
149203
/// <param name="handler">The handler to add.</param>
150204
public void Unsubscribe(CustomAsyncEventHandler handler)
151205
{
152-
InnerAsyncEvent -= handler;
206+
int index = innerAsyncEvent.FindIndex(p => p.handler == handler);
207+
if (index != -1)
208+
innerAsyncEvent.RemoveAt(index);
153209
}
154210

155211
/// <summary>
156212
/// Executes all <see cref="CustomEventHandler"/> listeners safely.
157213
/// </summary>
158214
public void InvokeSafely()
159215
{
160-
InvokeNormal();
161-
InvokeAsync();
216+
BlendedInvoke();
162217
}
163218

164219
/// <inheritdoc cref="InvokeSafely"/>
165-
internal void InvokeNormal()
220+
internal void BlendedInvoke()
166221
{
167-
if (InnerEvent is null)
168-
return;
222+
Registration[] innerEvent = this.innerEvent.ToArray();
223+
AsyncRegistration[] innerAsyncEvent = this.innerAsyncEvent.ToArray();
224+
int count = innerEvent.Length + innerAsyncEvent.Length;
225+
int eventIndex = 0, asyncEventIndex = 0;
169226

170-
foreach (CustomEventHandler handler in InnerEvent.GetInvocationList().Cast<CustomEventHandler>())
227+
for (int i = 0; i < count; i++)
228+
{
229+
if (eventIndex < innerEvent.Length && (asyncEventIndex >= innerAsyncEvent.Length || innerEvent[eventIndex].priority >= innerAsyncEvent[asyncEventIndex].priority))
230+
{
231+
try
232+
{
233+
innerEvent[eventIndex].handler();
234+
}
235+
catch (Exception ex)
236+
{
237+
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}");
238+
}
239+
240+
eventIndex++;
241+
}
242+
else
243+
{
244+
try
245+
{
246+
Timing.RunCoroutine(innerAsyncEvent[asyncEventIndex].handler());
247+
}
248+
catch (Exception ex)
249+
{
250+
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}");
251+
}
252+
253+
asyncEventIndex++;
254+
}
255+
}
256+
}
257+
258+
/// <inheritdoc cref="InvokeSafely"/>
259+
internal void InvokeNormal()
260+
{
261+
Registration[] innerEvent = this.innerEvent.ToArray();
262+
foreach (Registration registration in innerEvent)
171263
{
172264
try
173265
{
174-
handler();
266+
registration.handler();
175267
}
176268
catch (Exception ex)
177269
{
178-
Log.Error($"Method \"{handler.Method.Name}\" of the class \"{handler.Method.ReflectedType.FullName}\" caused an exception when handling the event \"{GetType().FullName}\"\n{ex}");
270+
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}");
179271
}
180272
}
181273
}
182274

183275
/// <inheritdoc cref="InvokeSafely"/>
184276
internal void InvokeAsync()
185277
{
186-
if (InnerAsyncEvent is null)
187-
return;
188-
189-
foreach (CustomAsyncEventHandler handler in InnerAsyncEvent.GetInvocationList().Cast<CustomAsyncEventHandler>())
278+
AsyncRegistration[] innerAsyncEvent = this.innerAsyncEvent.ToArray();
279+
foreach (AsyncRegistration registration in innerAsyncEvent)
190280
{
191281
try
192282
{
193-
Timing.RunCoroutine(handler());
283+
Timing.RunCoroutine(registration.handler());
194284
}
195285
catch (Exception ex)
196286
{
197-
Log.Error($"Method \"{handler.Method.Name}\" of the class \"{handler.Method.ReflectedType.FullName}\" caused an exception when handling the event \"{GetType().FullName}\"\n{ex}");
287+
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}");
198288
}
199289
}
200290
}

0 commit comments

Comments
 (0)