diff options
-rw-r--r-- | release-notes.md | 1 | ||||
-rw-r--r-- | src/StardewModdingAPI/Mod.cs | 20 | ||||
-rw-r--r-- | src/StardewModdingAPI/Program.cs | 17 |
3 files changed, 34 insertions, 4 deletions
diff --git a/release-notes.md b/release-notes.md index c1d2c13f..ebd5f981 100644 --- a/release-notes.md +++ b/release-notes.md @@ -20,6 +20,7 @@ For players: For mod developers: * Added log entries for basic context changes (e.g. loaded save) to simplify troubleshooting. More detailed logging can be enabled by setting `VerboseLogging: true` in `StardewModdingAPI.config.json`. * Added `debug` console command to TrainerMod which lets you pass debug commands to the game (e.g. `debug warp FarmHouse 1 1` warps the player to the farmhouse). +* Mods now implement `IDisposable` to let them release any unmanaged resources. ## 1.12 See [log](https://github.com/Pathoschild/SMAPI/compare/1.11...1.12). diff --git a/src/StardewModdingAPI/Mod.cs b/src/StardewModdingAPI/Mod.cs index 8033e1fd..a3169fb3 100644 --- a/src/StardewModdingAPI/Mod.cs +++ b/src/StardewModdingAPI/Mod.cs @@ -5,7 +5,7 @@ using StardewModdingAPI.Framework; namespace StardewModdingAPI { /// <summary>The base class for a mod.</summary> - public class Mod : IMod + public class Mod : IMod, IDisposable { /********* ** Properties @@ -88,6 +88,14 @@ namespace StardewModdingAPI /// <param name="helper">Provides simplified APIs for writing mods.</param> public virtual void Entry(IModHelper helper) { } + /// <summary>Release or reset unmanaged resources.</summary> + public void Dispose() + { + (this.Helper as IDisposable)?.Dispose(); // deliberate do this outside overridable dispose method so mods don't accidentally suppress it + this.Dispose(true); + GC.SuppressFinalize(this); + } + /********* ** Private methods @@ -106,5 +114,15 @@ namespace StardewModdingAPI } return Path.Combine(this.PathOnDisk, "psconfigs"); } + + /// <summary>Release or reset unmanaged resources.</summary> + /// <param name="disposing">Whether the instance is being disposed explicitly rather than finalised. If this is false, the instance shouldn't dispose other objects since they may already be finalised.</param> + protected virtual void Dispose(bool disposing) { } + + /// <summary>Destruct the instance.</summary> + ~Mod() + { + this.Dispose(false); + } } } diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 725ac94f..a5905805 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -228,14 +228,25 @@ namespace StardewModdingAPI /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary> public void Dispose() { + this.Monitor.Log("Disposing...", LogLevel.Trace); + // skip if already disposed if (this.IsDisposed) return; this.IsDisposed = true; - // dispose mod helpers - foreach (var mod in this.ModRegistry.GetMods()) - (mod.Helper as IDisposable)?.Dispose(); + // dispose mod data + foreach (IMod mod in this.ModRegistry.GetMods()) + { + try + { + (mod as IDisposable)?.Dispose(); + } + catch (Exception ex) + { + this.Monitor.Log($"The {mod.ModManifest.Name} mod failed during disposal: {ex.GetLogSummary()}.", LogLevel.Warn); + } + } // dispose core components this.IsGameRunning = false; |