diff options
author | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2020-08-09 11:56:40 -0400 |
---|---|---|
committer | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2020-08-09 11:56:40 -0400 |
commit | 066f1857a145c8b9e80a095d2dee1be6419f957b (patch) | |
tree | 2ebfc4533fa204e1264286067a419f17aa981de7 | |
parent | c03430ec7eba11462664a043f14e2f2a122674a1 (diff) | |
download | SMAPI-066f1857a145c8b9e80a095d2dee1be6419f957b.tar.gz SMAPI-066f1857a145c8b9e80a095d2dee1be6419f957b.tar.bz2 SMAPI-066f1857a145c8b9e80a095d2dee1be6419f957b.zip |
fix error when mods add/remove events asynchronously
-rw-r--r-- | docs/release-notes.md | 5 | ||||
-rw-r--r-- | src/SMAPI/Framework/Events/ManagedEvent.cs | 43 | ||||
-rw-r--r-- | src/SMAPI/PatchMode.cs | 2 |
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 |