let mods dispose unmanaged resources when SMAPI is disposing (#282)

This commit is contained in:
Jesse Plamondon-Willard 2017-05-09 22:02:17 -04:00
parent 7ba0518bfd
commit 494f9366a8
3 changed files with 34 additions and 4 deletions

View File

@ -20,6 +20,7 @@ For players:
For mod developers: 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 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). * 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 ## 1.12
See [log](https://github.com/Pathoschild/SMAPI/compare/1.11...1.12). See [log](https://github.com/Pathoschild/SMAPI/compare/1.11...1.12).

View File

@ -5,7 +5,7 @@ using StardewModdingAPI.Framework;
namespace StardewModdingAPI namespace StardewModdingAPI
{ {
/// <summary>The base class for a mod.</summary> /// <summary>The base class for a mod.</summary>
public class Mod : IMod public class Mod : IMod, IDisposable
{ {
/********* /*********
** Properties ** Properties
@ -88,6 +88,14 @@ namespace StardewModdingAPI
/// <param name="helper">Provides simplified APIs for writing mods.</param> /// <param name="helper">Provides simplified APIs for writing mods.</param>
public virtual void Entry(IModHelper helper) { } 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 ** Private methods
@ -106,5 +114,15 @@ namespace StardewModdingAPI
} }
return Path.Combine(this.PathOnDisk, "psconfigs"); 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);
}
} }
} }

View File

@ -228,14 +228,25 @@ namespace StardewModdingAPI
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary> /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose() public void Dispose()
{ {
this.Monitor.Log("Disposing...", LogLevel.Trace);
// skip if already disposed // skip if already disposed
if (this.IsDisposed) if (this.IsDisposed)
return; return;
this.IsDisposed = true; this.IsDisposed = true;
// dispose mod helpers // dispose mod data
foreach (var mod in this.ModRegistry.GetMods()) foreach (IMod mod in this.ModRegistry.GetMods())
(mod.Helper as IDisposable)?.Dispose(); {
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 // dispose core components
this.IsGameRunning = false; this.IsGameRunning = false;