summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2020-08-09 11:56:40 -0400
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2020-08-09 11:56:40 -0400
commit066f1857a145c8b9e80a095d2dee1be6419f957b (patch)
tree2ebfc4533fa204e1264286067a419f17aa981de7
parentc03430ec7eba11462664a043f14e2f2a122674a1 (diff)
downloadSMAPI-066f1857a145c8b9e80a095d2dee1be6419f957b.tar.gz
SMAPI-066f1857a145c8b9e80a095d2dee1be6419f957b.tar.bz2
SMAPI-066f1857a145c8b9e80a095d2dee1be6419f957b.zip
fix error when mods add/remove events asynchronously
-rw-r--r--docs/release-notes.md5
-rw-r--r--src/SMAPI/Framework/Events/ManagedEvent.cs43
-rw-r--r--src/SMAPI/PatchMode.cs2
3 files changed, 31 insertions, 19 deletions
diff --git a/docs/release-notes.md b/docs/release-notes.md
index c139ac1a..7f522ce0 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -8,6 +8,9 @@
-->
## Upcoming release
+* For players:
+ * Fixed rare error when a mod adds/removes event handlers asynchronously.
+
* For the web UI:
* Updated the JSON validator/schema for Content Patcher 1.16.
@@ -16,7 +19,7 @@ Released 02 August 2020 for Stardew Valley 1.4.1 or later.
* For players:
* Improved compatibility with some Linux terminals (thanks to jlaw and Spatterjaaay!).
- * Fixed rare crash when a mod adds/removes an event handler from an event handler.
+ * Fixed rare error when a mod adds/removes an event handler from an event handler.
* Fixed string sorting/comparison for some special characters.
* For the Console Commands mod:
diff --git a/src/SMAPI/Framework/Events/ManagedEvent.cs b/src/SMAPI/Framework/Events/ManagedEvent.cs
index 8b25a9b5..f2dfb2ab 100644
--- a/src/SMAPI/Framework/Events/ManagedEvent.cs
+++ b/src/SMAPI/Framework/Events/ManagedEvent.cs
@@ -70,27 +70,33 @@ namespace StardewModdingAPI.Framework.Events
/// <param name="mod">The mod which added the event handler.</param>
public void Add(EventHandler<TEventArgs> handler, IModMetadata mod)
{
- EventPriority priority = handler.Method.GetCustomAttribute<EventPriorityAttribute>()?.Priority ?? EventPriority.Normal;
- var managedHandler = new ManagedEventHandler<TEventArgs>(handler, this.RegistrationIndex++, priority, mod);
+ lock (this.Handlers)
+ {
+ EventPriority priority = handler.Method.GetCustomAttribute<EventPriorityAttribute>()?.Priority ?? EventPriority.Normal;
+ var managedHandler = new ManagedEventHandler<TEventArgs>(handler, this.RegistrationIndex++, priority, mod);
- this.Handlers.Add(managedHandler);
- this.CachedHandlers = null;
- this.HasNewHandlers = true;
+ this.Handlers.Add(managedHandler);
+ this.CachedHandlers = null;
+ this.HasNewHandlers = true;
+ }
}
/// <summary>Remove an event handler.</summary>
/// <param name="handler">The event handler.</param>
public void Remove(EventHandler<TEventArgs> handler)
{
- // match C# events: if a handler is listed multiple times, remove the last one added
- for (int i = this.Handlers.Count - 1; i >= 0; i--)
+ lock (this.Handlers)
{
- if (this.Handlers[i].Handler != handler)
- continue;
+ // match C# events: if a handler is listed multiple times, remove the last one added
+ for (int i = this.Handlers.Count - 1; i >= 0; i--)
+ {
+ if (this.Handlers[i].Handler != handler)
+ continue;
- this.Handlers.RemoveAt(i);
- this.CachedHandlers = null;
- break;
+ this.Handlers.RemoveAt(i);
+ this.CachedHandlers = null;
+ break;
+ }
}
}
@@ -106,14 +112,17 @@ namespace StardewModdingAPI.Framework.Events
// update cached data
// (This is debounced here to avoid repeatedly sorting when handlers are added/removed,
// and keeping a separate cached list allows changes during enumeration.)
- var handlers = this.CachedHandlers; // iterate local copy in case a mod adds/removes a handler while handling the event
+ var handlers = this.CachedHandlers; // iterate local copy in case a mod adds/removes a handler while handling the event, which will set this field to null
if (handlers == null)
{
- if (this.HasNewHandlers && this.Handlers.Any(p => p.Priority != EventPriority.Normal))
- this.Handlers.Sort();
+ lock (this.Handlers)
+ {
+ if (this.HasNewHandlers && this.Handlers.Any(p => p.Priority != EventPriority.Normal))
+ this.Handlers.Sort();
- this.CachedHandlers = handlers = this.Handlers.ToArray();
- this.HasNewHandlers = false;
+ this.CachedHandlers = handlers = this.Handlers.ToArray();
+ this.HasNewHandlers = false;
+ }
}
// raise event
diff --git a/src/SMAPI/PatchMode.cs b/src/SMAPI/PatchMode.cs
index b4286a89..34d3007d 100644
--- a/src/SMAPI/PatchMode.cs
+++ b/src/SMAPI/PatchMode.cs
@@ -1,4 +1,4 @@
-namespace StardewModdingAPI
+namespace StardewModdingAPI
{
/// <summary>Indicates how an image should be patched.</summary>
public enum PatchMode