diff options
-rw-r--r-- | src/SMAPI/Framework/SGame.cs | 17 | ||||
-rw-r--r-- | src/SMAPI/Program.cs | 14 |
2 files changed, 23 insertions, 8 deletions
diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index b383fcce..b983de49 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -114,6 +114,9 @@ namespace StardewModdingAPI.Framework /// <summary>A callback to invoke after the game finishes initialising.</summary> private readonly Action OnGameInitialised; + /// <summary>A callback to invoke when the game exits.</summary> + private readonly Action OnGameExiting; + /// <summary>Simplifies access to private game code.</summary> private readonly Reflector Reflection; @@ -136,7 +139,8 @@ namespace StardewModdingAPI.Framework /// <param name="reflection">Simplifies access to private game code.</param> /// <param name="eventManager">Manages SMAPI events for mods.</param> /// <param name="onGameInitialised">A callback to invoke after the game finishes initialising.</param> - internal SGame(IMonitor monitor, Reflector reflection, EventManager eventManager, Action onGameInitialised) + /// <param name="onGameExiting">A callback to invoke when the game exits.</param> + internal SGame(IMonitor monitor, Reflector reflection, EventManager eventManager, Action onGameInitialised, Action onGameExiting) { // init XNA Game1.graphics.GraphicsProfile = GraphicsProfile.HiDef; @@ -147,6 +151,7 @@ namespace StardewModdingAPI.Framework this.FirstUpdate = true; this.Reflection = reflection; this.OnGameInitialised = onGameInitialised; + this.OnGameExiting = onGameExiting; if (this.ContentCore == null) // shouldn't happen since CreateContentManager is called first, but let's init here just in case this.ContentCore = new ContentCore(this.Content.ServiceProvider, this.Content.RootDirectory, Thread.CurrentThread.CurrentUICulture, this.Monitor, reflection); @@ -167,6 +172,16 @@ namespace StardewModdingAPI.Framework }); } + /// <summary>Perform cleanup logic when the game exits.</summary> + /// <param name="sender">The event sender.</param> + /// <param name="args">The event args.</param> + /// <remarks>This overrides the logic in <see cref="Game1.OnExiting"/> and <see cref="Game1.exitEvent"/> to let SMAPI clean up before exit.</remarks> + protected override void OnExiting(object sender, EventArgs args) + { + Game1.multiplayer.Disconnect(); + this.OnGameExiting?.Invoke(); + } + /**** ** Intercepted methods & events ****/ diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs index cf1c082a..8f91c32b 100644 --- a/src/SMAPI/Program.cs +++ b/src/SMAPI/Program.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; @@ -30,6 +31,7 @@ using StardewModdingAPI.Framework.Utilities; using StardewValley; using Monitor = StardewModdingAPI.Framework.Monitor; using SObject = StardewValley.Object; +using ThreadState = System.Threading.ThreadState; namespace StardewModdingAPI { @@ -197,7 +199,7 @@ namespace StardewModdingAPI // override game SGame.MonitorDuringInitialisation = this.Monitor; SGame.ReflectorDuringInitialisation = this.Reflection; - this.GameInstance = new SGame(this.Monitor, this.Reflection, this.EventManager, this.InitialiseAfterGameStart); + this.GameInstance = new SGame(this.Monitor, this.Reflection, this.EventManager, this.InitialiseAfterGameStart, this.Dispose); StardewValley.Program.gamePtr = this.GameInstance; // add exit handler @@ -221,10 +223,6 @@ namespace StardewModdingAPI }).Start(); // hook into game events -#if SMAPI_FOR_WINDOWS - ((Form)Control.FromHandle(this.GameInstance.Window.Handle)).FormClosing += (sender, args) => this.Dispose(); -#endif - this.GameInstance.Exiting += (sender, e) => this.Dispose(); ContentEvents.AfterLocaleChanged += (sender, e) => this.OnLocaleChanged(); // set window titles @@ -271,12 +269,11 @@ 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; + this.Monitor.Log("Disposing...", LogLevel.Trace); // dispose mod data foreach (IModMetadata mod in this.ModRegistry.GetAll()) @@ -298,6 +295,9 @@ namespace StardewModdingAPI this.CancellationTokenSource?.Dispose(); this.GameInstance?.Dispose(); this.LogFile?.Dispose(); + + // end game (moved from Game1.OnExiting to let us clean up first) + Process.GetCurrentProcess().Kill(); } |