diff options
| -rw-r--r-- | src/StardewModdingAPI/Command.cs | 39 | ||||
| -rw-r--r-- | src/StardewModdingAPI/Config.cs | 18 | ||||
| -rw-r--r-- | src/StardewModdingAPI/Constants.cs | 3 | ||||
| -rw-r--r-- | src/StardewModdingAPI/Events/PlayerEvents.cs | 18 | ||||
| -rw-r--r-- | src/StardewModdingAPI/Events/TimeEvents.cs | 16 | ||||
| -rw-r--r-- | src/StardewModdingAPI/Framework/InternalExtensions.cs | 16 | ||||
| -rw-r--r-- | src/StardewModdingAPI/Framework/Monitor.cs | 9 | ||||
| -rw-r--r-- | src/StardewModdingAPI/Framework/RequestExitDelegate.cs | 7 | ||||
| -rw-r--r-- | src/StardewModdingAPI/Log.cs | 16 | ||||
| -rw-r--r-- | src/StardewModdingAPI/Mod.cs | 24 | ||||
| -rw-r--r-- | src/StardewModdingAPI/Program.cs | 287 | ||||
| -rw-r--r-- | src/StardewModdingAPI/StardewModdingAPI.csproj | 1 |
12 files changed, 294 insertions, 160 deletions
diff --git a/src/StardewModdingAPI/Command.cs b/src/StardewModdingAPI/Command.cs index 1cbb01ff..6b056ce7 100644 --- a/src/StardewModdingAPI/Command.cs +++ b/src/StardewModdingAPI/Command.cs @@ -12,12 +12,22 @@ namespace StardewModdingAPI /********* ** Properties *********/ - /**** - ** SMAPI - ****/ /// <summary>The commands registered with SMAPI.</summary> private static readonly IDictionary<string, Command> LegacyCommands = new Dictionary<string, Command>(StringComparer.InvariantCultureIgnoreCase); + /// <summary>Manages console commands.</summary> + private static CommandManager CommandManager; + + /// <summary>Manages deprecation warnings.</summary> + private static DeprecationManager DeprecationManager; + + /// <summary>Tracks the installed mods.</summary> + private static ModRegistry ModRegistry; + + + /********* + ** Accessors + *********/ /// <summary>The event raised when this command is submitted through the console.</summary> public event EventHandler<EventArgsCommand> CommandFired; @@ -43,6 +53,17 @@ namespace StardewModdingAPI /**** ** Command ****/ + /// <summary>Injects types required for backwards compatibility.</summary> + /// <param name="commandManager">Manages console commands.</param> + /// <param name="deprecationManager">Manages deprecation warnings.</param> + /// <param name="modRegistry">Tracks the installed mods.</param> + internal static void Shim(CommandManager commandManager, DeprecationManager deprecationManager, ModRegistry modRegistry) + { + Command.CommandManager = commandManager; + Command.DeprecationManager = deprecationManager; + Command.ModRegistry = modRegistry; + } + /// <summary>Construct an instance.</summary> /// <param name="name">The name of the command.</param> /// <param name="description">A human-readable description of what the command does.</param> @@ -73,8 +94,8 @@ namespace StardewModdingAPI /// <param name="monitor">Encapsulates monitoring and logging.</param> public static void CallCommand(string input, IMonitor monitor) { - Program.DeprecationManager.Warn("Command.CallCommand", "1.9", DeprecationLevel.Notice); - Program.CommandManager.Trigger(input); + Command.DeprecationManager.Warn("Command.CallCommand", "1.9", DeprecationLevel.Notice); + Command.CommandManager.Trigger(input); } /// <summary>Register a command with SMAPI.</summary> @@ -86,18 +107,18 @@ namespace StardewModdingAPI name = name?.Trim().ToLower(); // raise deprecation warning - Program.DeprecationManager.Warn("Command.RegisterCommand", "1.9", DeprecationLevel.Notice); + Command.DeprecationManager.Warn("Command.RegisterCommand", "1.9", DeprecationLevel.Notice); // validate if (Command.LegacyCommands.ContainsKey(name)) throw new InvalidOperationException($"The '{name}' command is already registered!"); // add command - string modName = Program.ModRegistry.GetModFromStack() ?? "<unknown mod>"; + string modName = Command.ModRegistry.GetModFromStack() ?? "<unknown mod>"; string documentation = args?.Length > 0 ? $"{description} - {string.Join(", ", args)}" : description; - Program.CommandManager.Add(modName, name, documentation, Command.Fire); + Command.CommandManager.Add(modName, name, documentation, Command.Fire); // add legacy command Command command = new Command(name, description, args); @@ -109,7 +130,7 @@ namespace StardewModdingAPI /// <param name="name">The command name to find.</param> public static Command FindCommand(string name) { - Program.DeprecationManager.Warn("Command.FindCommand", "1.9", DeprecationLevel.Notice); + Command.DeprecationManager.Warn("Command.FindCommand", "1.9", DeprecationLevel.Notice); if (name == null) return null; diff --git a/src/StardewModdingAPI/Config.cs b/src/StardewModdingAPI/Config.cs index 037c0fdf..f253930d 100644 --- a/src/StardewModdingAPI/Config.cs +++ b/src/StardewModdingAPI/Config.cs @@ -12,6 +12,13 @@ namespace StardewModdingAPI public abstract class Config { /********* + ** Properties + *********/ + /// <summary>Manages deprecation warnings.</summary> + private static DeprecationManager DeprecationManager; + + + /********* ** Accessors *********/ /// <summary>The full path to the configuration file.</summary> @@ -26,6 +33,13 @@ namespace StardewModdingAPI /********* ** Public methods *********/ + /// <summary>Injects types required for backwards compatibility.</summary> + /// <param name="deprecationManager">Manages deprecation warnings.</param> + internal static void Shim(DeprecationManager deprecationManager) + { + Config.DeprecationManager = deprecationManager; + } + /// <summary>Construct an instance of the config class.</summary> /// <typeparam name="T">The config class type.</typeparam> [Obsolete("This base class is obsolete since SMAPI 1.0. See the latest project README for details.")] @@ -111,8 +125,8 @@ namespace StardewModdingAPI /// <summary>Construct an instance.</summary> protected Config() { - Program.DeprecationManager.Warn("the Config class", "1.0", DeprecationLevel.Notice); - Program.DeprecationManager.MarkWarned($"{nameof(Mod)}.{nameof(Mod.BaseConfigPath)}", "1.0"); // typically used to construct config, avoid redundant warnings + Config.DeprecationManager.Warn("the Config class", "1.0", DeprecationLevel.Notice); + Config.DeprecationManager.MarkWarned($"{nameof(Mod)}.{nameof(Mod.BaseConfigPath)}", "1.0"); // typically used to construct config, avoid redundant warnings } } diff --git a/src/StardewModdingAPI/Constants.cs b/src/StardewModdingAPI/Constants.cs index db0c2622..262ba61d 100644 --- a/src/StardewModdingAPI/Constants.cs +++ b/src/StardewModdingAPI/Constants.cs @@ -59,9 +59,6 @@ namespace StardewModdingAPI /// <summary>The GitHub repository to check for updates.</summary> internal const string GitHubRepository = "Pathoschild/SMAPI"; - /// <summary>The title of the SMAPI console window.</summary> - internal static string ConsoleTitle => $"Stardew Modding API Console - Version {Constants.ApiVersion} - Mods Loaded: {Program.ModsLoaded}"; - /// <summary>The file path for the SMAPI configuration file.</summary> internal static string ApiConfigPath => Path.Combine(Constants.ExecutionPath, $"{typeof(Program).Assembly.GetName().Name}.config.json"); diff --git a/src/StardewModdingAPI/Events/PlayerEvents.cs b/src/StardewModdingAPI/Events/PlayerEvents.cs index 99bdac16..996077ab 100644 --- a/src/StardewModdingAPI/Events/PlayerEvents.cs +++ b/src/StardewModdingAPI/Events/PlayerEvents.cs @@ -11,6 +11,13 @@ namespace StardewModdingAPI.Events public static class PlayerEvents { /********* + ** Properties + *********/ + /// <summary>Manages deprecation warnings.</summary> + private static DeprecationManager DeprecationManager; + + + /********* ** Events *********/ /// <summary>Raised after the player loads a saved game.</summary> @@ -31,6 +38,13 @@ namespace StardewModdingAPI.Events /********* ** Internal methods *********/ + /// <summary>Injects types required for backwards compatibility.</summary> + /// <param name="deprecationManager">Manages deprecation warnings.</param> + internal static void Shim(DeprecationManager deprecationManager) + { + PlayerEvents.DeprecationManager = deprecationManager; + } + /// <summary>Raise a <see cref="LoadedGame"/> event.</summary> /// <param name="monitor">Encapsulates monitoring and logging.</param> /// <param name="loaded">Whether the save has been loaded. This is always true.</param> @@ -42,7 +56,7 @@ namespace StardewModdingAPI.Events string name = $"{nameof(PlayerEvents)}.{nameof(PlayerEvents.LoadedGame)}"; Delegate[] handlers = PlayerEvents.LoadedGame.GetInvocationList(); - Program.DeprecationManager.WarnForEvent(handlers, name, "1.6", DeprecationLevel.Notice); + PlayerEvents.DeprecationManager.WarnForEvent(handlers, name, "1.6", DeprecationLevel.Notice); monitor.SafelyRaiseGenericEvent(name, handlers, null, loaded); } @@ -58,7 +72,7 @@ namespace StardewModdingAPI.Events string name = $"{nameof(PlayerEvents)}.{nameof(PlayerEvents.FarmerChanged)}"; Delegate[] handlers = PlayerEvents.FarmerChanged.GetInvocationList(); - Program.DeprecationManager.WarnForEvent(handlers, name, "1.6", DeprecationLevel.Notice); + PlayerEvents.DeprecationManager.WarnForEvent(handlers, name, "1.6", DeprecationLevel.Notice); monitor.SafelyRaiseGenericEvent(name, handlers, null, new EventArgsFarmerChanged(priorFarmer, newFarmer)); } diff --git a/src/StardewModdingAPI/Events/TimeEvents.cs b/src/StardewModdingAPI/Events/TimeEvents.cs index a140a223..0f9257c1 100644 --- a/src/StardewModdingAPI/Events/TimeEvents.cs +++ b/src/StardewModdingAPI/Events/TimeEvents.cs @@ -7,6 +7,13 @@ namespace StardewModdingAPI.Events public static class TimeEvents { /********* + ** Properties + *********/ + /// <summary>Manages deprecation warnings.</summary> + private static DeprecationManager DeprecationManager; + + + /********* ** Events *********/ /// <summary>Raised after the game begins a new day, including when loading a save.</summary> @@ -32,6 +39,13 @@ namespace StardewModdingAPI.Events /********* ** Internal methods *********/ + /// <summary>Injects types required for backwards compatibility.</summary> + /// <param name="deprecationManager">Manages deprecation warnings.</param> + internal static void Shim(DeprecationManager deprecationManager) + { + TimeEvents.DeprecationManager = deprecationManager; + } + /// <summary>Raise an <see cref="AfterDayStarted"/> event.</summary> /// <param name="monitor">Encapsulates monitoring and logging.</param> internal static void InvokeAfterDayStarted(IMonitor monitor) @@ -88,7 +102,7 @@ namespace StardewModdingAPI.Events string name = $"{nameof(TimeEvents)}.{nameof(TimeEvents.OnNewDay)}"; Delegate[] handlers = TimeEvents.OnNewDay.GetInvocationList(); - Program.DeprecationManager.WarnForEvent(handlers, name, "1.6", DeprecationLevel.Notice); + TimeEvents.DeprecationManager.WarnForEvent(handlers, name, "1.6", DeprecationLevel.Notice); monitor.SafelyRaiseGenericEvent(name, handlers, null, new EventArgsNewDay(priorDay, newDay, isTransitioning)); } } diff --git a/src/StardewModdingAPI/Framework/InternalExtensions.cs b/src/StardewModdingAPI/Framework/InternalExtensions.cs index c4bd2d35..4ca79518 100644 --- a/src/StardewModdingAPI/Framework/InternalExtensions.cs +++ b/src/StardewModdingAPI/Framework/InternalExtensions.cs @@ -9,8 +9,22 @@ namespace StardewModdingAPI.Framework internal static class InternalExtensions { /********* + ** Properties + *********/ + /// <summary>Tracks the installed mods.</summary> + private static ModRegistry ModRegistry; + + + /********* ** Public methods *********/ + /// <summary>Injects types required for backwards compatibility.</summary> + /// <param name="modRegistry">Tracks the installed mods.</param> + internal static void Shim(ModRegistry modRegistry) + { + InternalExtensions.ModRegistry = modRegistry; + } + /**** ** IMonitor ****/ @@ -103,7 +117,7 @@ namespace StardewModdingAPI.Framework foreach (Delegate handler in handlers) { - string modName = Program.ModRegistry.GetModFrom(handler) ?? "an unknown mod"; // suppress stack trace for unknown mods, not helpful here + string modName = InternalExtensions.ModRegistry.GetModFrom(handler) ?? "an unknown mod"; // suppress stack trace for unknown mods, not helpful here deprecationManager.Warn(modName, nounPhrase, version, severity); } } diff --git a/src/StardewModdingAPI/Framework/Monitor.cs b/src/StardewModdingAPI/Framework/Monitor.cs index c1735917..64075f2f 100644 --- a/src/StardewModdingAPI/Framework/Monitor.cs +++ b/src/StardewModdingAPI/Framework/Monitor.cs @@ -34,6 +34,9 @@ namespace StardewModdingAPI.Framework [LogLevel.Alert] = ConsoleColor.Magenta }; + /// <summary>A delegate which requests that SMAPI immediately exit the game. This should only be invoked when an irrecoverable fatal error happens that risks save corruption or game-breaking bugs.</summary> + private RequestExitDelegate RequestExit; + /********* ** Accessors @@ -55,7 +58,8 @@ namespace StardewModdingAPI.Framework /// <param name="source">The name of the module which logs messages using this instance.</param> /// <param name="consoleManager">Manages access to the console output.</param> /// <param name="logFile">The log file to which to write messages.</param> - public Monitor(string source, ConsoleInterceptionManager consoleManager, LogFileManager logFile) + /// <param name="requestExitDelegate">A delegate which requests that SMAPI immediately exit the game.</param> + public Monitor(string source, ConsoleInterceptionManager consoleManager, LogFileManager logFile, RequestExitDelegate requestExitDelegate) { // validate if (string.IsNullOrWhiteSpace(source)) @@ -81,8 +85,7 @@ namespace StardewModdingAPI.Framework /// <param name="reason">The reason for the shutdown.</param> public void ExitGameImmediately(string reason) { - Program.ExitGameImmediately(this.Source, reason); - Program.GameInstance.Exit(); + this.RequestExit(this.Source, reason); } /// <summary>Log a fatal error message.</summary> diff --git a/src/StardewModdingAPI/Framework/RequestExitDelegate.cs b/src/StardewModdingAPI/Framework/RequestExitDelegate.cs new file mode 100644 index 00000000..12d0ea0c --- /dev/null +++ b/src/StardewModdingAPI/Framework/RequestExitDelegate.cs @@ -0,0 +1,7 @@ +namespace StardewModdingAPI.Framework +{ + /// <summary>A delegate which requests that SMAPI immediately exit the game. This should only be invoked when an irrecoverable fatal error happens that risks save corruption or game-breaking bugs.</summary> + /// <param name="module">The module which requested an immediate exit.</param> + /// <param name="reason">The reason provided for the shutdown.</param> + internal delegate void RequestExitDelegate(string module, string reason); +}
\ No newline at end of file diff --git a/src/StardewModdingAPI/Log.cs b/src/StardewModdingAPI/Log.cs index 5cb794f9..da98baba 100644 --- a/src/StardewModdingAPI/Log.cs +++ b/src/StardewModdingAPI/Log.cs @@ -10,6 +10,13 @@ namespace StardewModdingAPI public static class Log { /********* + ** Properties + *********/ + /// <summary>Manages deprecation warnings.</summary> + private static DeprecationManager DeprecationManager; + + + /********* ** Accessors *********/ /// <summary>The underlying logger.</summary> @@ -22,6 +29,13 @@ namespace StardewModdingAPI /********* ** Public methods *********/ + /// <summary>Injects types required for backwards compatibility.</summary> + /// <param name="deprecationManager">Manages deprecation warnings.</param> + internal static void Shim(DeprecationManager deprecationManager) + { + Log.DeprecationManager = deprecationManager; + } + /**** ** Exceptions ****/ @@ -292,7 +306,7 @@ namespace StardewModdingAPI /// <summary>Raise a deprecation warning.</summary> private static void WarnDeprecated() { - Program.DeprecationManager.Warn($"the {nameof(Log)} class", "1.1", DeprecationLevel.Notice); + Log.DeprecationManager.Warn($"the {nameof(Log)} class", "1.1", DeprecationLevel.Notice); } /// <summary>Get the name of the mod logging a message from the stack.</summary> diff --git a/src/StardewModdingAPI/Mod.cs b/src/StardewModdingAPI/Mod.cs index c8456a29..d3fe882f 100644 --- a/src/StardewModdingAPI/Mod.cs +++ b/src/StardewModdingAPI/Mod.cs @@ -10,6 +10,9 @@ namespace StardewModdingAPI /********* ** Properties *********/ + /// <summary>Manages deprecation warnings.</summary> + private static DeprecationManager DeprecationManager; + /// <summary>The backing field for <see cref="Mod.PathOnDisk"/>.</summary> private string _pathOnDisk; @@ -32,7 +35,7 @@ namespace StardewModdingAPI { get { - Program.DeprecationManager.Warn($"{nameof(Mod)}.{nameof(Mod.PathOnDisk)}", "1.0", DeprecationLevel.Notice); + Mod.DeprecationManager.Warn($"{nameof(Mod)}.{nameof(Mod.PathOnDisk)}", "1.0", DeprecationLevel.Notice); return this._pathOnDisk; } internal set { this._pathOnDisk = value; } @@ -44,8 +47,8 @@ namespace StardewModdingAPI { get { - Program.DeprecationManager.Warn($"{nameof(Mod)}.{nameof(Mod.BaseConfigPath)}", "1.0", DeprecationLevel.Notice); - Program.DeprecationManager.MarkWarned($"{nameof(Mod)}.{nameof(Mod.PathOnDisk)}", "1.0"); // avoid redundant warnings + Mod.DeprecationManager.Warn($"{nameof(Mod)}.{nameof(Mod.BaseConfigPath)}", "1.0", DeprecationLevel.Notice); + Mod.DeprecationManager.MarkWarned($"{nameof(Mod)}.{nameof(Mod.PathOnDisk)}", "1.0"); // avoid redundant warnings return Path.Combine(this.PathOnDisk, "config.json"); } } @@ -60,8 +63,8 @@ namespace StardewModdingAPI { get { - Program.DeprecationManager.Warn($"{nameof(Mod)}.{nameof(Mod.PerSaveConfigPath)}", "1.0", DeprecationLevel.Info); - Program.DeprecationManager.MarkWarned($"{nameof(Mod)}.{nameof(Mod.PerSaveConfigFolder)}", "1.0"); // avoid redundant warnings + Mod.DeprecationManager.Warn($"{nameof(Mod)}.{nameof(Mod.PerSaveConfigPath)}", "1.0", DeprecationLevel.Info); + Mod.DeprecationManager.MarkWarned($"{nameof(Mod)}.{nameof(Mod.PerSaveConfigFolder)}", "1.0"); // avoid redundant warnings return Constants.CurrentSavePathExists ? Path.Combine(this.PerSaveConfigFolder, Constants.SaveFolderName + ".json") : ""; } } @@ -70,6 +73,13 @@ namespace StardewModdingAPI /********* ** Public methods *********/ + /// <summary>Injects types required for backwards compatibility.</summary> + /// <param name="deprecationManager">Manages deprecation warnings.</param> + internal static void Shim(DeprecationManager deprecationManager) + { + Mod.DeprecationManager = deprecationManager; + } + /// <summary>The mod entry point, called after the mod is first loaded.</summary> [Obsolete("This overload is obsolete since SMAPI 1.0.")] public virtual void Entry(params object[] objects) { } @@ -86,8 +96,8 @@ namespace StardewModdingAPI [Obsolete] private string GetPerSaveConfigFolder() { - Program.DeprecationManager.Warn($"{nameof(Mod)}.{nameof(Mod.PerSaveConfigFolder)}", "1.0", DeprecationLevel.Notice); - Program.DeprecationManager.MarkWarned($"{nameof(Mod)}.{nameof(Mod.PathOnDisk)}", "1.0"); // avoid redundant warnings + Mod.DeprecationManager.Warn($"{nameof(Mod)}.{nameof(Mod.PerSaveConfigFolder)}", "1.0", DeprecationLevel.Notice); + Mod.DeprecationManager.MarkWarned($"{nameof(Mod)}.{nameof(Mod.PathOnDisk)}", "1.0"); // avoid redundant warnings if (!((Manifest)this.ModManifest).PerSaveConfigs) { diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index c3f8f8d8..0857d41b 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -28,7 +28,7 @@ namespace StardewModdingAPI ** Properties *********/ /// <summary>The target game platform.</summary> - private static readonly Platform TargetPlatform = + private readonly Platform TargetPlatform = #if SMAPI_FOR_WINDOWS Platform.Windows; #else @@ -36,47 +36,47 @@ namespace StardewModdingAPI #endif /// <summary>The full path to the Stardew Valley executable.</summary> - private static readonly string GameExecutablePath = Path.Combine(Constants.ExecutionPath, Program.TargetPlatform == Platform.Windows ? "Stardew Valley.exe" : "StardewValley.exe"); + private readonly string GameExecutablePath; /// <summary>The full path to the folder containing mods.</summary> - private static readonly string ModPath = Path.Combine(Constants.ExecutionPath, "Mods"); + private readonly string ModPath = Path.Combine(Constants.ExecutionPath, "Mods"); /// <summary>The log file to which to write messages.</summary> - private static readonly LogFileManager LogFile = new LogFileManager(Constants.LogPath); + private readonly LogFileManager LogFile = new LogFileManager(Constants.LogPath); /// <summary>Manages console output interception.</summary> - private static readonly ConsoleInterceptionManager ConsoleManager = new ConsoleInterceptionManager(); + private readonly ConsoleInterceptionManager ConsoleManager = new ConsoleInterceptionManager(); /// <summary>The core logger for SMAPI.</summary> - private static readonly Monitor Monitor = new Monitor("SMAPI", Program.ConsoleManager, Program.LogFile); + private readonly Monitor Monitor; /// <summary>The user settings for SMAPI.</summary> - private static UserSettings Settings; + private UserSettings Settings; /// <summary>Tracks whether the game should exit immediately and any pending initialisation should be cancelled.</summary> - private static readonly CancellationTokenSource CancellationTokenSource = new CancellationTokenSource(); + private readonly CancellationTokenSource CancellationTokenSource = new CancellationTokenSource(); /// <summary>Whether the game is currently running.</summary> - private static bool ready; + private bool IsGameRunning; /********* ** Accessors *********/ /// <summary>The underlying game instance.</summary> - internal static SGame GameInstance; + internal SGame GameInstance; /// <summary>The number of mods currently loaded by SMAPI.</summary> - internal static int ModsLoaded; + internal int ModsLoaded; /// <summary>Tracks the installed mods.</summary> - internal static readonly ModRegistry ModRegistry = new ModRegistry(); + internal readonly ModRegistry ModRegistry = new ModRegistry(); /// <summary>Manages deprecation warnings.</summary> - internal static readonly DeprecationManager DeprecationManager = new DeprecationManager(Program.Monitor, Program.ModRegistry); + internal readonly DeprecationManager DeprecationManager; /// <summary>Manages console commands.</summary> - internal static readonly CommandManager CommandManager = new CommandManager(); + internal readonly CommandManager CommandManager = new CommandManager(); /********* @@ -86,10 +86,35 @@ namespace StardewModdingAPI /// <param name="args">The command-line arguments.</param> private static void Main(string[] args) { + new Program(writeToConsole: !args.Contains("--no-terminal")) + .LaunchInteractively(); + } + + /// <summary>Construct an instance.</summary> + internal Program(bool writeToConsole) + { + this.GameExecutablePath = Path.Combine(Constants.ExecutionPath, this.TargetPlatform == Platform.Windows ? "Stardew Valley.exe" : "StardewValley.exe"); + this.Monitor = new Monitor("SMAPI", this.ConsoleManager, this.LogFile, this.ExitGameImmediately) { WriteToConsole = writeToConsole }; + this.DeprecationManager = new DeprecationManager(this.Monitor, this.ModRegistry); + } + + /// <summary>Launch SMAPI.</summary> + internal void LaunchInteractively() + { // initialise logging - Program.Monitor.WriteToConsole = !args.Contains("--no-terminal"); Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB"); // for consistent log formatting - Program.Monitor.Log($"SMAPI {Constants.ApiVersion} with Stardew Valley {Game1.version} on {Environment.OSVersion}", LogLevel.Info); + this.Monitor.Log($"SMAPI {Constants.ApiVersion} with Stardew Valley {Game1.version} on {Environment.OSVersion}", LogLevel.Info); + + // inject compatibility shims +#pragma warning disable 618 + Command.Shim(this.CommandManager, this.DeprecationManager, this.ModRegistry); + Config.Shim(this.DeprecationManager); + InternalExtensions.Shim(this.ModRegistry); + Log.Shim(this.DeprecationManager); + Mod.Shim(this.DeprecationManager); + PlayerEvents.Shim(this.DeprecationManager); + TimeEvents.Shim(this.DeprecationManager); +#pragma warning restore 618 // read config { @@ -97,39 +122,39 @@ namespace StardewModdingAPI if (File.Exists(settingsPath)) { string json = File.ReadAllText(settingsPath); - Program.Settings = JsonConvert.DeserializeObject<UserSettings>(json); + this.Settings = JsonConvert.DeserializeObject<UserSettings>(json); } else - Program.Settings = new UserSettings(); + this.Settings = new UserSettings(); - File.WriteAllText(settingsPath, JsonConvert.SerializeObject(Program.Settings, Formatting.Indented)); + File.WriteAllText(settingsPath, JsonConvert.SerializeObject(this.Settings, Formatting.Indented)); } // redirect direct console output { - Monitor monitor = Program.GetSecondaryMonitor("Console.Out"); + Monitor monitor = this.GetSecondaryMonitor("Console.Out"); monitor.WriteToFile = false; // not useful for troubleshooting mods per discussion if (monitor.WriteToConsole) - Program.ConsoleManager.OnLineIntercepted += line => monitor.Log(line, LogLevel.Trace); + this.ConsoleManager.OnLineIntercepted += line => monitor.Log(line, LogLevel.Trace); } // add warning headers - if (Program.Settings.DeveloperMode) + if (this.Settings.DeveloperMode) { - Program.Monitor.ShowTraceInConsole = true; - Program.Monitor.Log($"You configured SMAPI to run in developer mode. The console may be much more verbose. You can disable developer mode by installing the non-developer version of SMAPI, or by editing or deleting {Constants.ApiConfigPath}.", LogLevel.Warn); + this.Monitor.ShowTraceInConsole = true; + this.Monitor.Log($"You configured SMAPI to run in developer mode. The console may be much more verbose. You can disable developer mode by installing the non-developer version of SMAPI, or by editing or deleting {Constants.ApiConfigPath}.", LogLevel.Warn); } - if (!Program.Settings.CheckForUpdates) - Program.Monitor.Log($"You configured SMAPI to not check for updates. Running an old version of SMAPI is not recommended. You can enable update checks by editing or deleting {Constants.ApiConfigPath}.", LogLevel.Warn); - if (!Program.Monitor.WriteToConsole) - Program.Monitor.Log("Writing to the terminal is disabled because the --no-terminal argument was received. This usually means launching the terminal failed.", LogLevel.Warn); + if (!this.Settings.CheckForUpdates) + this.Monitor.Log($"You configured SMAPI to not check for updates. Running an old version of SMAPI is not recommended. You can enable update checks by editing or deleting {Constants.ApiConfigPath}.", LogLevel.Warn); + if (!this.Monitor.WriteToConsole) + this.Monitor.Log("Writing to the terminal is disabled because the --no-terminal argument was received. This usually means launching the terminal failed.", LogLevel.Warn); // print file paths - Program.Monitor.Log($"Mods go here: {Program.ModPath}"); + this.Monitor.Log($"Mods go here: {this.ModPath}"); // initialise legacy log - Log.Monitor = Program.GetSecondaryMonitor("legacy mod"); - Log.ModRegistry = Program.ModRegistry; + Log.Monitor = this.GetSecondaryMonitor("legacy mod"); + Log.ModRegistry = this.ModRegistry; // hook into & launch the game try @@ -137,56 +162,56 @@ namespace StardewModdingAPI // verify version if (String.Compare(Game1.version, Constants.MinimumGameVersion, StringComparison.InvariantCultureIgnoreCase) < 0) { - Program.Monitor.Log($"Oops! You're running Stardew Valley {Game1.version}, but the oldest supported version is {Constants.MinimumGameVersion}. Please update your game before using SMAPI. If you're on the Steam beta channel, note that the beta channel may not receive the latest updates.", LogLevel.Error); + this.Monitor.Log($"Oops! You're running Stardew Valley {Game1.version}, but the oldest supported version is {Constants.MinimumGameVersion}. Please update your game before using SMAPI. If you're on the Steam beta channel, note that the beta channel may not receive the latest updates.", LogLevel.Error); return; } // initialise - Program.Monitor.Log("Loading SMAPI..."); - Console.Title = Constants.ConsoleTitle; - Program.VerifyPath(Program.ModPath); - Program.VerifyPath(Constants.LogDir); - if (!File.Exists(Program.GameExecutablePath)) + this.Monitor.Log("Loading SMAPI..."); + Console.Title = $"Stardew Modding API Console - Version {Constants.ApiVersion}"; + this.VerifyPath(this.ModPath); + this.VerifyPath(Constants.LogDir); + if (!File.Exists(this.GameExecutablePath)) { - Program.Monitor.Log($"Couldn't find executable: {Program.GameExecutablePath}", LogLevel.Error); - Program.PressAnyKeyToExit(); + this.Monitor.Log($"Couldn't find executable: {this.GameExecutablePath}", LogLevel.Error); + this.PressAnyKeyToExit(); return; } // check for update when game loads - if (Program.Settings.CheckForUpdates) - GameEvents.GameLoaded += (sender, e) => Program.CheckForUpdateAsync(); + if (this.Settings.CheckForUpdates) + GameEvents.GameLoaded += (sender, e) => this.CheckForUpdateAsync(); // launch game - Program.StartGame(); + this.StartGame(); } catch (Exception ex) { - Program.Monitor.Log($"Critical error: {ex.GetLogSummary()}", LogLevel.Error); + this.Monitor.Log($"Critical error: {ex.GetLogSummary()}", LogLevel.Error); } - Program.PressAnyKeyToExit(); + this.PressAnyKeyToExit(); } /// <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="module">The module which requested an immediate exit.</param> /// <param name="reason">The reason provided for the shutdown.</param> - internal static void ExitGameImmediately(string module, string reason) + internal void ExitGameImmediately(string module, string reason) { - Program.Monitor.LogFatal($"{module} requested an immediate game shutdown: {reason}"); - Program.CancellationTokenSource.Cancel(); - if (Program.ready) + this.Monitor.LogFatal($"{module} requested an immediate game shutdown: {reason}"); + this.CancellationTokenSource.Cancel(); + if (this.IsGameRunning) { - Program.GameInstance.Exiting += (sender, e) => Program.PressAnyKeyToExit(); - Program.GameInstance.Exit(); + this.GameInstance.Exiting += (sender, e) => this.PressAnyKeyToExit(); + this.GameInstance.Exit(); } } /// <summary>Get a monitor for legacy code which doesn't have one passed in.</summary> [Obsolete("This method should only be used when needed for backwards compatibility.")] - internal static IMonitor GetLegacyMonitorForMod() + internal IMonitor GetLegacyMonitorForMod() { - string modName = Program.ModRegistry.GetModFromStack() ?? "unknown"; - return Program.GetSecondaryMonitor(modName); + string modName = this.ModRegistry.GetModFromStack() ?? "unknown"; + return this.GetSecondaryMonitor(modName); } @@ -194,7 +219,7 @@ namespace StardewModdingAPI ** Private methods *********/ /// <summary>Asynchronously check for a new version of SMAPI, and print a message to the console if an update is available.</summary> - private static void CheckForUpdateAsync() + private void CheckForUpdateAsync() { new Thread(() => { @@ -203,40 +228,40 @@ namespace StardewModdingAPI GitRelease release = UpdateHelper.GetLatestVersionAsync(Constants.GitHubRepository).Result; ISemanticVersion latestVersion = new SemanticVersion(release.Tag); if (latestVersion.IsNewerThan(Constants.ApiVersion)) - Program.Monitor.Log($"You can update SMAPI from version {Constants.ApiVersion} to {latestVersion}", LogLevel.Alert); + this.Monitor.Log($"You can update SMAPI from version {Constants.ApiVersion} to {latestVersion}", LogLevel.Alert); } catch (Exception ex) { - Program.Monitor.Log($"Couldn't check for a new version of SMAPI. This won't affect your game, but you may not be notified of new versions if this keeps happening.\n{ex.GetLogSummary()}"); + this.Monitor.Log($"Couldn't check for a new version of SMAPI. This won't affect your game, but you may not be notified of new versions if this keeps happening.\n{ex.GetLogSummary()}"); } }).Start(); } /// <summary>Hook into Stardew Valley and launch the game.</summary> - private static void StartGame() + private void StartGame() { try { // add error handlers #if SMAPI_FOR_WINDOWS - Application.ThreadException += (sender, e) => Program.Monitor.Log($"Critical thread exception: {e.Exception.GetLogSummary()}", LogLevel.Error); + Application.ThreadException += (sender, e) => this.Monitor.Log($"Critical thread exception: {e.Exception.GetLogSummary()}", LogLevel.Error); Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); #endif |
