drop monitor.ExitGameImmediately method
This is bad practice in most cases, and was only used by two mods which didn't legitimately need to exit immediately.
This commit is contained in:
parent
e18ffc009d
commit
a450b0ebef
|
@ -18,7 +18,8 @@ These changes have not been released yet.
|
||||||
* Added `Context.IsGameLaunched` field.
|
* Added `Context.IsGameLaunched` field.
|
||||||
* Mods are now loaded much earlier in the game launch. This lets mods intercept any content asset, but the game is not fully initialised when `Entry` is called (use the `GameLaunched` event if you need to run code when the game is initialised).
|
* Mods are now loaded much earlier in the game launch. This lets mods intercept any content asset, but the game is not fully initialised when `Entry` is called (use the `GameLaunched` event if you need to run code when the game is initialised).
|
||||||
* When a mod is incompatible, the trace logs now list all detected issues instead of the first one.
|
* When a mod is incompatible, the trace logs now list all detected issues instead of the first one.
|
||||||
* Dropped support for all deprecated APIs.
|
* Removed all deprecated APIs.
|
||||||
|
* Removed the `Monitor.ExitGameImmediately` method.
|
||||||
* Updated to Json.NET 12.0.1.
|
* Updated to Json.NET 12.0.1.
|
||||||
|
|
||||||
## 2.11.3
|
## 2.11.3
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
|
||||||
using StardewModdingAPI.Framework.Logging;
|
using StardewModdingAPI.Framework.Logging;
|
||||||
using StardewModdingAPI.Internal.ConsoleWriting;
|
using StardewModdingAPI.Internal.ConsoleWriting;
|
||||||
|
|
||||||
|
@ -27,16 +26,10 @@ namespace StardewModdingAPI.Framework
|
||||||
/// <summary>The maximum length of the <see cref="LogLevel"/> values.</summary>
|
/// <summary>The maximum length of the <see cref="LogLevel"/> values.</summary>
|
||||||
private static readonly int MaxLevelLength = (from level in Enum.GetValues(typeof(LogLevel)).Cast<LogLevel>() select level.ToString().Length).Max();
|
private static readonly int MaxLevelLength = (from level in Enum.GetValues(typeof(LogLevel)).Cast<LogLevel>() select level.ToString().Length).Max();
|
||||||
|
|
||||||
/// <summary>Propagates notification that SMAPI should exit.</summary>
|
|
||||||
private readonly CancellationTokenSource ExitTokenSource;
|
|
||||||
|
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
** Accessors
|
** Accessors
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Whether SMAPI is aborting. Mods don't need to worry about this unless they have background tasks.</summary>
|
|
||||||
public bool IsExiting => this.ExitTokenSource.IsCancellationRequested;
|
|
||||||
|
|
||||||
/// <summary>Whether verbose logging is enabled. This enables more detailed diagnostic messages than are normally needed.</summary>
|
/// <summary>Whether verbose logging is enabled. This enables more detailed diagnostic messages than are normally needed.</summary>
|
||||||
public bool IsVerbose { get; }
|
public bool IsVerbose { get; }
|
||||||
|
|
||||||
|
@ -57,10 +50,9 @@ namespace StardewModdingAPI.Framework
|
||||||
/// <param name="source">The name of the module which logs messages using this instance.</param>
|
/// <param name="source">The name of the module which logs messages using this instance.</param>
|
||||||
/// <param name="consoleInterceptor">Intercepts access to the console output.</param>
|
/// <param name="consoleInterceptor">Intercepts access to the console output.</param>
|
||||||
/// <param name="logFile">The log file to which to write messages.</param>
|
/// <param name="logFile">The log file to which to write messages.</param>
|
||||||
/// <param name="exitTokenSource">Propagates notification that SMAPI should exit.</param>
|
|
||||||
/// <param name="colorScheme">The console color scheme to use.</param>
|
/// <param name="colorScheme">The console color scheme to use.</param>
|
||||||
/// <param name="isVerbose">Whether verbose logging is enabled. This enables more detailed diagnostic messages than are normally needed.</param>
|
/// <param name="isVerbose">Whether verbose logging is enabled. This enables more detailed diagnostic messages than are normally needed.</param>
|
||||||
public Monitor(string source, ConsoleInterceptionManager consoleInterceptor, LogFileManager logFile, CancellationTokenSource exitTokenSource, MonitorColorScheme colorScheme, bool isVerbose)
|
public Monitor(string source, ConsoleInterceptionManager consoleInterceptor, LogFileManager logFile, MonitorColorScheme colorScheme, bool isVerbose)
|
||||||
{
|
{
|
||||||
// validate
|
// validate
|
||||||
if (string.IsNullOrWhiteSpace(source))
|
if (string.IsNullOrWhiteSpace(source))
|
||||||
|
@ -71,7 +63,6 @@ namespace StardewModdingAPI.Framework
|
||||||
this.LogFile = logFile ?? throw new ArgumentNullException(nameof(logFile), "The log file manager cannot be null.");
|
this.LogFile = logFile ?? throw new ArgumentNullException(nameof(logFile), "The log file manager cannot be null.");
|
||||||
this.ConsoleWriter = new ColorfulConsoleWriter(Constants.Platform, colorScheme);
|
this.ConsoleWriter = new ColorfulConsoleWriter(Constants.Platform, colorScheme);
|
||||||
this.ConsoleInterceptor = consoleInterceptor;
|
this.ConsoleInterceptor = consoleInterceptor;
|
||||||
this.ExitTokenSource = exitTokenSource;
|
|
||||||
this.IsVerbose = isVerbose;
|
this.IsVerbose = isVerbose;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,14 +82,6 @@ namespace StardewModdingAPI.Framework
|
||||||
this.Log(message, LogLevel.Trace);
|
this.Log(message, LogLevel.Trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Immediately exit the game without saving. This should only be invoked when an irrecoverable fatal error happens that risks save corruption or game-breaking bugs.</summary>
|
|
||||||
/// <param name="reason">The reason for the shutdown.</param>
|
|
||||||
public void ExitGameImmediately(string reason)
|
|
||||||
{
|
|
||||||
this.LogFatal($"{this.Source} requested an immediate game shutdown: {reason}");
|
|
||||||
this.ExitTokenSource.Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Write a newline to the console and log file.</summary>
|
/// <summary>Write a newline to the console and log file.</summary>
|
||||||
internal void Newline()
|
internal void Newline()
|
||||||
{
|
{
|
||||||
|
@ -107,6 +90,13 @@ namespace StardewModdingAPI.Framework
|
||||||
this.LogFile.WriteLine("");
|
this.LogFile.WriteLine("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Log a fatal error message.</summary>
|
||||||
|
/// <param name="message">The message to log.</param>
|
||||||
|
internal void LogFatal(string message)
|
||||||
|
{
|
||||||
|
this.LogImpl(this.Source, message, ConsoleLogLevel.Critical);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Log console input from the user.</summary>
|
/// <summary>Log console input from the user.</summary>
|
||||||
/// <param name="input">The user input to log.</param>
|
/// <param name="input">The user input to log.</param>
|
||||||
internal void LogUserInput(string input)
|
internal void LogUserInput(string input)
|
||||||
|
@ -120,13 +110,6 @@ namespace StardewModdingAPI.Framework
|
||||||
/*********
|
/*********
|
||||||
** Private methods
|
** Private methods
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Log a fatal error message.</summary>
|
|
||||||
/// <param name="message">The message to log.</param>
|
|
||||||
private void LogFatal(string message)
|
|
||||||
{
|
|
||||||
this.LogImpl(this.Source, message, ConsoleLogLevel.Critical);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Write a message line to the log.</summary>
|
/// <summary>Write a message line to the log.</summary>
|
||||||
/// <param name="source">The name of the mod logging the message.</param>
|
/// <param name="source">The name of the mod logging the message.</param>
|
||||||
/// <param name="message">The message to log.</param>
|
/// <param name="message">The message to log.</param>
|
||||||
|
|
|
@ -57,7 +57,7 @@ namespace StardewModdingAPI.Framework
|
||||||
private readonly Monitor MonitorForGame;
|
private readonly Monitor MonitorForGame;
|
||||||
|
|
||||||
/// <summary>Tracks whether the game should exit immediately and any pending initialisation should be cancelled.</summary>
|
/// <summary>Tracks whether the game should exit immediately and any pending initialisation should be cancelled.</summary>
|
||||||
private readonly CancellationTokenSource CancellationTokenSource = new CancellationTokenSource();
|
private readonly CancellationTokenSource CancellationToken = new CancellationTokenSource();
|
||||||
|
|
||||||
/// <summary>Simplifies access to private game code.</summary>
|
/// <summary>Simplifies access to private game code.</summary>
|
||||||
private readonly Reflector Reflection = new Reflector();
|
private readonly Reflector Reflection = new Reflector();
|
||||||
|
@ -144,7 +144,7 @@ namespace StardewModdingAPI.Framework
|
||||||
// init basics
|
// init basics
|
||||||
this.Settings = JsonConvert.DeserializeObject<SConfig>(File.ReadAllText(Constants.ApiConfigPath));
|
this.Settings = JsonConvert.DeserializeObject<SConfig>(File.ReadAllText(Constants.ApiConfigPath));
|
||||||
this.LogFile = new LogFileManager(logPath);
|
this.LogFile = new LogFileManager(logPath);
|
||||||
this.Monitor = new Monitor("SMAPI", this.ConsoleManager, this.LogFile, this.CancellationTokenSource, this.Settings.ColorScheme, this.Settings.VerboseLogging)
|
this.Monitor = new Monitor("SMAPI", this.ConsoleManager, this.LogFile, this.Settings.ColorScheme, this.Settings.VerboseLogging)
|
||||||
{
|
{
|
||||||
WriteToConsole = writeToConsole,
|
WriteToConsole = writeToConsole,
|
||||||
ShowTraceInConsole = this.Settings.DeveloperMode,
|
ShowTraceInConsole = this.Settings.DeveloperMode,
|
||||||
|
@ -222,7 +222,8 @@ namespace StardewModdingAPI.Framework
|
||||||
modRegistry: this.ModRegistry,
|
modRegistry: this.ModRegistry,
|
||||||
deprecationManager: SCore.DeprecationManager,
|
deprecationManager: SCore.DeprecationManager,
|
||||||
onGameInitialised: this.InitialiseAfterGameStart,
|
onGameInitialised: this.InitialiseAfterGameStart,
|
||||||
onGameExiting: this.Dispose
|
onGameExiting: this.Dispose,
|
||||||
|
cancellationToken: this.CancellationToken
|
||||||
);
|
);
|
||||||
StardewValley.Program.gamePtr = this.GameInstance;
|
StardewValley.Program.gamePtr = this.GameInstance;
|
||||||
|
|
||||||
|
@ -237,7 +238,7 @@ namespace StardewModdingAPI.Framework
|
||||||
// add exit handler
|
// add exit handler
|
||||||
new Thread(() =>
|
new Thread(() =>
|
||||||
{
|
{
|
||||||
this.CancellationTokenSource.Token.WaitHandle.WaitOne();
|
this.CancellationToken.Token.WaitHandle.WaitOne();
|
||||||
if (this.IsGameRunning)
|
if (this.IsGameRunning)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -363,7 +364,7 @@ namespace StardewModdingAPI.Framework
|
||||||
this.IsGameRunning = false;
|
this.IsGameRunning = false;
|
||||||
this.ConsoleManager?.Dispose();
|
this.ConsoleManager?.Dispose();
|
||||||
this.ContentCore?.Dispose();
|
this.ContentCore?.Dispose();
|
||||||
this.CancellationTokenSource?.Dispose();
|
this.CancellationToken?.Dispose();
|
||||||
this.GameInstance?.Dispose();
|
this.GameInstance?.Dispose();
|
||||||
this.LogFile?.Dispose();
|
this.LogFile?.Dispose();
|
||||||
|
|
||||||
|
@ -378,7 +379,7 @@ namespace StardewModdingAPI.Framework
|
||||||
/// <summary>Initialise mods before the first game asset is loaded. At this point the core content managers are loaded (so mods can load their own assets), but the game is mostly uninitialised.</summary>
|
/// <summary>Initialise mods before the first game asset is loaded. At this point the core content managers are loaded (so mods can load their own assets), but the game is mostly uninitialised.</summary>
|
||||||
private void InitialiseBeforeFirstAssetLoaded()
|
private void InitialiseBeforeFirstAssetLoaded()
|
||||||
{
|
{
|
||||||
if (this.Monitor.IsExiting)
|
if (this.CancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
this.Monitor.Log("SMAPI shutting down: aborting initialisation.", LogLevel.Warn);
|
this.Monitor.Log("SMAPI shutting down: aborting initialisation.", LogLevel.Warn);
|
||||||
return;
|
return;
|
||||||
|
@ -482,7 +483,7 @@ namespace StardewModdingAPI.Framework
|
||||||
inputThread.Start();
|
inputThread.Start();
|
||||||
|
|
||||||
// keep console thread alive while the game is running
|
// keep console thread alive while the game is running
|
||||||
while (this.IsGameRunning && !this.Monitor.IsExiting)
|
while (this.IsGameRunning && !this.CancellationToken.IsCancellationRequested)
|
||||||
Thread.Sleep(1000 / 10);
|
Thread.Sleep(1000 / 10);
|
||||||
if (inputThread.ThreadState == ThreadState.Running)
|
if (inputThread.ThreadState == ThreadState.Running)
|
||||||
inputThread.Abort();
|
inputThread.Abort();
|
||||||
|
@ -1336,7 +1337,7 @@ namespace StardewModdingAPI.Framework
|
||||||
/// <param name="name">The name of the module which will log messages with this instance.</param>
|
/// <param name="name">The name of the module which will log messages with this instance.</param>
|
||||||
private Monitor GetSecondaryMonitor(string name)
|
private Monitor GetSecondaryMonitor(string name)
|
||||||
{
|
{
|
||||||
return new Monitor(name, this.ConsoleManager, this.LogFile, this.CancellationTokenSource, this.Settings.ColorScheme, this.Settings.VerboseLogging)
|
return new Monitor(name, this.ConsoleManager, this.LogFile, this.Settings.ColorScheme, this.Settings.VerboseLogging)
|
||||||
{
|
{
|
||||||
WriteToConsole = this.Monitor.WriteToConsole,
|
WriteToConsole = this.Monitor.WriteToConsole,
|
||||||
ShowTraceInConsole = this.Settings.DeveloperMode,
|
ShowTraceInConsole = this.Settings.DeveloperMode,
|
||||||
|
|
|
@ -43,7 +43,7 @@ namespace StardewModdingAPI.Framework
|
||||||
** SMAPI state
|
** SMAPI state
|
||||||
****/
|
****/
|
||||||
/// <summary>Encapsulates monitoring and logging for SMAPI.</summary>
|
/// <summary>Encapsulates monitoring and logging for SMAPI.</summary>
|
||||||
private readonly IMonitor Monitor;
|
private readonly Monitor Monitor;
|
||||||
|
|
||||||
/// <summary>Encapsulates monitoring and logging on the game's behalf.</summary>
|
/// <summary>Encapsulates monitoring and logging on the game's behalf.</summary>
|
||||||
private readonly IMonitor MonitorForGame;
|
private readonly IMonitor MonitorForGame;
|
||||||
|
@ -85,6 +85,9 @@ namespace StardewModdingAPI.Framework
|
||||||
/// <summary>Simplifies access to private game code.</summary>
|
/// <summary>Simplifies access to private game code.</summary>
|
||||||
private readonly Reflector Reflection;
|
private readonly Reflector Reflection;
|
||||||
|
|
||||||
|
/// <summary>Propagates notification that SMAPI should exit.</summary>
|
||||||
|
private readonly CancellationTokenSource CancellationToken;
|
||||||
|
|
||||||
/****
|
/****
|
||||||
** Game state
|
** Game state
|
||||||
****/
|
****/
|
||||||
|
@ -137,7 +140,8 @@ namespace StardewModdingAPI.Framework
|
||||||
/// <param name="deprecationManager">Manages deprecation warnings.</param>
|
/// <param name="deprecationManager">Manages deprecation warnings.</param>
|
||||||
/// <param name="onGameInitialised">A callback to invoke after the game finishes initialising.</param>
|
/// <param name="onGameInitialised">A callback to invoke after the game finishes initialising.</param>
|
||||||
/// <param name="onGameExiting">A callback to invoke when the game exits.</param>
|
/// <param name="onGameExiting">A callback to invoke when the game exits.</param>
|
||||||
internal SGame(IMonitor monitor, IMonitor monitorForGame, Reflector reflection, EventManager eventManager, JsonHelper jsonHelper, ModRegistry modRegistry, DeprecationManager deprecationManager, Action onGameInitialised, Action onGameExiting)
|
/// <param name="cancellationToken">Propagates notification that SMAPI should exit.</param>
|
||||||
|
internal SGame(Monitor monitor, IMonitor monitorForGame, Reflector reflection, EventManager eventManager, JsonHelper jsonHelper, ModRegistry modRegistry, DeprecationManager deprecationManager, Action onGameInitialised, Action onGameExiting, CancellationTokenSource cancellationToken)
|
||||||
{
|
{
|
||||||
this.OnLoadingFirstAsset = SGame.ConstructorHack.OnLoadingFirstAsset;
|
this.OnLoadingFirstAsset = SGame.ConstructorHack.OnLoadingFirstAsset;
|
||||||
SGame.ConstructorHack = null;
|
SGame.ConstructorHack = null;
|
||||||
|
@ -161,6 +165,7 @@ namespace StardewModdingAPI.Framework
|
||||||
Game1.input = new SInputState();
|
Game1.input = new SInputState();
|
||||||
Game1.multiplayer = new SMultiplayer(monitor, eventManager, jsonHelper, modRegistry, reflection, this.OnModMessageReceived);
|
Game1.multiplayer = new SMultiplayer(monitor, eventManager, jsonHelper, modRegistry, reflection, this.OnModMessageReceived);
|
||||||
Game1.hooks = new SModHooks(this.OnNewDayAfterFade);
|
Game1.hooks = new SModHooks(this.OnNewDayAfterFade);
|
||||||
|
this.CancellationToken = cancellationToken;
|
||||||
|
|
||||||
// init observables
|
// init observables
|
||||||
Game1.locations = new ObservableCollection<GameLocation>();
|
Game1.locations = new ObservableCollection<GameLocation>();
|
||||||
|
@ -274,7 +279,7 @@ namespace StardewModdingAPI.Framework
|
||||||
}
|
}
|
||||||
|
|
||||||
// Abort if SMAPI is exiting.
|
// Abort if SMAPI is exiting.
|
||||||
if (this.Monitor.IsExiting)
|
if (this.CancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
this.Monitor.Log("SMAPI shutting down: aborting update.", LogLevel.Trace);
|
this.Monitor.Log("SMAPI shutting down: aborting update.", LogLevel.Trace);
|
||||||
return;
|
return;
|
||||||
|
@ -805,7 +810,7 @@ namespace StardewModdingAPI.Framework
|
||||||
|
|
||||||
// exit if irrecoverable
|
// exit if irrecoverable
|
||||||
if (!this.UpdateCrashTimer.Decrement())
|
if (!this.UpdateCrashTimer.Decrement())
|
||||||
this.Monitor.ExitGameImmediately("the game crashed when updating, and SMAPI was unable to recover the game.");
|
this.ExitGameImmediately("The game crashed when updating, and SMAPI was unable to recover the game.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -827,7 +832,7 @@ namespace StardewModdingAPI.Framework
|
||||||
// exit if irrecoverable
|
// exit if irrecoverable
|
||||||
if (!this.DrawCrashTimer.Decrement())
|
if (!this.DrawCrashTimer.Decrement())
|
||||||
{
|
{
|
||||||
this.Monitor.ExitGameImmediately("the game crashed when drawing, and SMAPI was unable to recover the game.");
|
this.ExitGameImmediately("The game crashed when drawing, and SMAPI was unable to recover the game.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1481,5 +1486,13 @@ namespace StardewModdingAPI.Framework
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Immediately exit the game without saving. This should only be invoked when an irrecoverable fatal error happens that risks save corruption or game-breaking bugs.</summary>
|
||||||
|
/// <param name="message">The fatal log message.</param>
|
||||||
|
private void ExitGameImmediately(string message)
|
||||||
|
{
|
||||||
|
this.Monitor.LogFatal(message);
|
||||||
|
this.CancellationToken.Cancel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,6 @@ namespace StardewModdingAPI
|
||||||
/*********
|
/*********
|
||||||
** Accessors
|
** Accessors
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Whether SMAPI is aborting. Mods don't need to worry about this unless they have background tasks.</summary>
|
|
||||||
bool IsExiting { get; }
|
|
||||||
|
|
||||||
/// <summary>Whether verbose logging is enabled. This enables more detailed diagnostic messages than are normally needed.</summary>
|
/// <summary>Whether verbose logging is enabled. This enables more detailed diagnostic messages than are normally needed.</summary>
|
||||||
bool IsVerbose { get; }
|
bool IsVerbose { get; }
|
||||||
|
|
||||||
|
@ -24,9 +21,5 @@ namespace StardewModdingAPI
|
||||||
/// <summary>Log a message that only appears when <see cref="IsVerbose"/> is enabled.</summary>
|
/// <summary>Log a message that only appears when <see cref="IsVerbose"/> is enabled.</summary>
|
||||||
/// <param name="message">The message to log.</param>
|
/// <param name="message">The message to log.</param>
|
||||||
void VerboseLog(string message);
|
void VerboseLog(string message);
|
||||||
|
|
||||||
/// <summary>Immediately exit the game without saving. This should only be invoked when an irrecoverable fatal error happens that risks save corruption or game-breaking bugs.</summary>
|
|
||||||
/// <param name="reason">The reason for the shutdown.</param>
|
|
||||||
void ExitGameImmediately(string reason);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue