summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/SMAPI/Framework/Monitor.cs33
-rw-r--r--src/SMAPI/Framework/SCore.cs17
-rw-r--r--src/SMAPI/Framework/SGame.cs23
-rw-r--r--src/SMAPI/IMonitor.cs7
4 files changed, 35 insertions, 45 deletions
diff --git a/src/SMAPI/Framework/Monitor.cs b/src/SMAPI/Framework/Monitor.cs
index 617bfd85..3771f114 100644
--- a/src/SMAPI/Framework/Monitor.cs
+++ b/src/SMAPI/Framework/Monitor.cs
@@ -1,6 +1,5 @@
using System;
using System.Linq;
-using System.Threading;
using StardewModdingAPI.Framework.Logging;
using StardewModdingAPI.Internal.ConsoleWriting;
@@ -27,16 +26,10 @@ namespace StardewModdingAPI.Framework
/// <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();
- /// <summary>Propagates notification that SMAPI should exit.</summary>
- private readonly CancellationTokenSource ExitTokenSource;
-
/*********
** 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>
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="consoleInterceptor">Intercepts access to the console output.</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="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
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.ConsoleWriter = new ColorfulConsoleWriter(Constants.Platform, colorScheme);
this.ConsoleInterceptor = consoleInterceptor;
- this.ExitTokenSource = exitTokenSource;
this.IsVerbose = isVerbose;
}
@@ -91,14 +82,6 @@ namespace StardewModdingAPI.Framework
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>
internal void Newline()
{
@@ -107,6 +90,13 @@ namespace StardewModdingAPI.Framework
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>
/// <param name="input">The user input to log.</param>
internal void LogUserInput(string input)
@@ -120,13 +110,6 @@ namespace StardewModdingAPI.Framework
/*********
** 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>
/// <param name="source">The name of the mod logging the message.</param>
/// <param name="message">The message to log.</param>
diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs
index e8d5b672..03a27fa9 100644
--- a/src/SMAPI/Framework/SCore.cs
+++ b/src/SMAPI/Framework/SCore.cs
@@ -57,7 +57,7 @@ namespace StardewModdingAPI.Framework
private readonly Monitor MonitorForGame;
/// <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>
private readonly Reflector Reflection = new Reflector();
@@ -144,7 +144,7 @@ namespace StardewModdingAPI.Framework
// init basics
this.Settings = JsonConvert.DeserializeObject<SConfig>(File.ReadAllText(Constants.ApiConfigPath));
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,
ShowTraceInConsole = this.Settings.DeveloperMode,
@@ -222,7 +222,8 @@ namespace StardewModdingAPI.Framework
modRegistry: this.ModRegistry,
deprecationManager: SCore.DeprecationManager,
onGameInitialised: this.InitialiseAfterGameStart,
- onGameExiting: this.Dispose
+ onGameExiting: this.Dispose,
+ cancellationToken: this.CancellationToken
);
StardewValley.Program.gamePtr = this.GameInstance;
@@ -237,7 +238,7 @@ namespace StardewModdingAPI.Framework
// add exit handler
new Thread(() =>
{
- this.CancellationTokenSource.Token.WaitHandle.WaitOne();
+ this.CancellationToken.Token.WaitHandle.WaitOne();
if (this.IsGameRunning)
{
try
@@ -363,7 +364,7 @@ namespace StardewModdingAPI.Framework
this.IsGameRunning = false;
this.ConsoleManager?.Dispose();
this.ContentCore?.Dispose();
- this.CancellationTokenSource?.Dispose();
+ this.CancellationToken?.Dispose();
this.GameInstance?.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>
private void InitialiseBeforeFirstAssetLoaded()
{
- if (this.Monitor.IsExiting)
+ if (this.CancellationToken.IsCancellationRequested)
{
this.Monitor.Log("SMAPI shutting down: aborting initialisation.", LogLevel.Warn);
return;
@@ -482,7 +483,7 @@ namespace StardewModdingAPI.Framework
inputThread.Start();
// 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);
if (inputThread.ThreadState == ThreadState.Running)
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>
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,
ShowTraceInConsole = this.Settings.DeveloperMode,
diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs
index c06f62cf..2d43f8c4 100644
--- a/src/SMAPI/Framework/SGame.cs
+++ b/src/SMAPI/Framework/SGame.cs
@@ -43,7 +43,7 @@ namespace StardewModdingAPI.Framework
** SMAPI state
****/
/// <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>
private readonly IMonitor MonitorForGame;
@@ -85,6 +85,9 @@ namespace StardewModdingAPI.Framework
/// <summary>Simplifies access to private game code.</summary>
private readonly Reflector Reflection;
+ /// <summary>Propagates notification that SMAPI should exit.</summary>
+ private readonly CancellationTokenSource CancellationToken;
+
/****
** Game state
****/
@@ -137,7 +140,8 @@ namespace StardewModdingAPI.Framework
/// <param name="deprecationManager">Manages deprecation warnings.</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>
- 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;
SGame.ConstructorHack = null;
@@ -161,6 +165,7 @@ namespace StardewModdingAPI.Framework
Game1.input = new SInputState();
Game1.multiplayer = new SMultiplayer(monitor, eventManager, jsonHelper, modRegistry, reflection, this.OnModMessageReceived);
Game1.hooks = new SModHooks(this.OnNewDayAfterFade);
+ this.CancellationToken = cancellationToken;
// init observables
Game1.locations = new ObservableCollection<GameLocation>();
@@ -274,7 +279,7 @@ namespace StardewModdingAPI.Framework
}
// Abort if SMAPI is exiting.
- if (this.Monitor.IsExiting)
+ if (this.CancellationToken.IsCancellationRequested)
{
this.Monitor.Log("SMAPI shutting down: aborting update.", LogLevel.Trace);
return;
@@ -805,7 +810,7 @@ namespace StardewModdingAPI.Framework
// exit if irrecoverable
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
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;
}
@@ -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();
+ }
}
}
diff --git a/src/SMAPI/IMonitor.cs b/src/SMAPI/IMonitor.cs
index 943c1c59..f2d110b8 100644
--- a/src/SMAPI/IMonitor.cs
+++ b/src/SMAPI/IMonitor.cs
@@ -6,9 +6,6 @@ namespace StardewModdingAPI
/*********
** 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>
bool IsVerbose { get; }
@@ -24,9 +21,5 @@ namespace StardewModdingAPI
/// <summary>Log a message that only appears when <see cref="IsVerbose"/> is enabled.</summary>
/// <param name="message">The message to log.</param>
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);
}
}