summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI/Framework')
-rw-r--r--src/SMAPI/Framework/Events/ManagedEvent.cs45
1 files changed, 36 insertions, 9 deletions
diff --git a/src/SMAPI/Framework/Events/ManagedEvent.cs b/src/SMAPI/Framework/Events/ManagedEvent.cs
index 118b73ac..172b25c0 100644
--- a/src/SMAPI/Framework/Events/ManagedEvent.cs
+++ b/src/SMAPI/Framework/Events/ManagedEvent.cs
@@ -1,6 +1,9 @@
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Linq;
+using System.Reflection;
+using StardewModdingAPI.Events;
using StardewModdingAPI.Framework.PerformanceMonitoring;
namespace StardewModdingAPI.Framework.Events
@@ -13,7 +16,7 @@ namespace StardewModdingAPI.Framework.Events
** Fields
*********/
/// <summary>The underlying event.</summary>
- private event EventHandler<TEventArgs> Event;
+ private IList<EventHandler<TEventArgs>> EventHandlers = new List<EventHandler<TEventArgs>>();
/// <summary>Writes messages to the log.</summary>
private readonly IMonitor Monitor;
@@ -77,23 +80,23 @@ namespace StardewModdingAPI.Framework.Events
/// <param name="mod">The mod which added the event handler.</param>
public void Add(EventHandler<TEventArgs> handler, IModMetadata mod)
{
- this.Event += handler;
- this.AddTracking(mod, handler, this.Event?.GetInvocationList().Cast<EventHandler<TEventArgs>>());
+ this.EventHandlers.Add(handler);
+ this.AddTracking(mod, handler, this.EventHandlers);
}
/// <summary>Remove an event handler.</summary>
/// <param name="handler">The event handler.</param>
public void Remove(EventHandler<TEventArgs> handler)
{
- this.Event -= handler;
- this.RemoveTracking(handler, this.Event?.GetInvocationList().Cast<EventHandler<TEventArgs>>());
+ this.EventHandlers.Remove(handler);
+ this.RemoveTracking(handler, this.EventHandlers);
}
/// <summary>Raise the event and notify all handlers.</summary>
/// <param name="args">The event arguments to pass.</param>
public void Raise(TEventArgs args)
{
- if (this.Event == null)
+ if (this.EventHandlers.Count == 0)
return;
@@ -118,7 +121,7 @@ namespace StardewModdingAPI.Framework.Events
/// <param name="match">A lambda which returns true if the event should be raised for the given mod.</param>
public void RaiseForMods(TEventArgs args, Func<IModMetadata, bool> match)
{
- if (this.Event == null)
+ if (this.EventHandlers.Count == 0)
return;
foreach (EventHandler<TEventArgs> handler in this.CachedInvocationList)
@@ -154,6 +157,30 @@ namespace StardewModdingAPI.Framework.Events
: mod.DisplayName;
}
+ /// <summary>
+ /// Get the event priority of an event handler.
+ /// </summary>
+ /// <param name="handler">The event handler to get the priority of.</param>
+ /// <returns>The event priority of the event handler.</returns>
+ private EventPriority GetPriorityOfHandler(EventHandler<TEventArgs> handler)
+ {
+ CustomAttributeData attr = handler.Method.CustomAttributes.FirstOrDefault(a => a.AttributeType == typeof(EventPriorityAttribute));
+ if (attr == null)
+ return EventPriority.Normal;
+ return (EventPriority) attr.ConstructorArguments[0].Value;
+ }
+
+ /// <summary>
+ /// Sort an invocation list by its priority.
+ /// </summary>
+ /// <param name="invocationList">The invocation list.</param>
+ /// <returns>An array of the event handlers sorted by their priority.</returns>
+ private EventHandler<TEventArgs>[] GetCachedInvocationList(IEnumerable<EventHandler<TEventArgs>> invocationList )
+ {
+ EventHandler<TEventArgs>[] handlers = invocationList?.ToArray() ?? new EventHandler<TEventArgs>[0];
+ return handlers.OrderBy((h1) => this.GetPriorityOfHandler(h1)).ToArray();
+ }
+
/// <summary>Track an event handler.</summary>
/// <param name="mod">The mod which added the handler.</param>
/// <param name="handler">The event handler.</param>
@@ -161,7 +188,7 @@ namespace StardewModdingAPI.Framework.Events
protected void AddTracking(IModMetadata mod, EventHandler<TEventArgs> handler, IEnumerable<EventHandler<TEventArgs>> invocationList)
{
this.SourceMods[handler] = mod;
- this.CachedInvocationList = invocationList?.ToArray() ?? new EventHandler<TEventArgs>[0];
+ this.CachedInvocationList = this.GetCachedInvocationList(invocationList);
}
/// <summary>Remove tracking for an event handler.</summary>
@@ -169,7 +196,7 @@ namespace StardewModdingAPI.Framework.Events
/// <param name="invocationList">The updated event invocation list.</param>
protected void RemoveTracking(EventHandler<TEventArgs> handler, IEnumerable<EventHandler<TEventArgs>> invocationList)
{
- this.CachedInvocationList = invocationList?.ToArray() ?? new EventHandler<TEventArgs>[0];
+ this.CachedInvocationList = this.GetCachedInvocationList(invocationList);
if (!this.CachedInvocationList.Contains(handler)) // don't remove if there's still a reference to the removed handler (e.g. it was added twice and removed once)
this.SourceMods.Remove(handler);
}