From 54e7b5b846dfd542af3c8a904a57fc5ccc44ecb5 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 3 Feb 2021 20:24:25 -0500 Subject: enable aggressive memory optimizations by default (#757) The new approach should be safe, and no errors were reported so far by alpha testers. --- src/SMAPI.Mods.ErrorHandler/ModEntry.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI.Mods.ErrorHandler') diff --git a/src/SMAPI.Mods.ErrorHandler/ModEntry.cs b/src/SMAPI.Mods.ErrorHandler/ModEntry.cs index 2f6f1939..f543814e 100644 --- a/src/SMAPI.Mods.ErrorHandler/ModEntry.cs +++ b/src/SMAPI.Mods.ErrorHandler/ModEntry.cs @@ -30,7 +30,7 @@ namespace StardewModdingAPI.Mods.ErrorHandler LogManager logManager = core.GetType().GetField("LogManager", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(core) as LogManager; if (logManager == null) { - this.Monitor.Log($"Can't access SMAPI's internal log manager. Error-handling patches won't be applied.", LogLevel.Error); + this.Monitor.Log("Can't access SMAPI's internal log manager. Error-handling patches won't be applied.", LogLevel.Error); return; } -- cgit From 97d3501e20c9b97dc85cfca32ccea4f55c9d61ff Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 6 Feb 2021 20:47:04 -0500 Subject: improve ErrorHandler's error handling if it can't access log manager --- src/SMAPI.Mods.ErrorHandler/ModEntry.cs | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'src/SMAPI.Mods.ErrorHandler') diff --git a/src/SMAPI.Mods.ErrorHandler/ModEntry.cs b/src/SMAPI.Mods.ErrorHandler/ModEntry.cs index f543814e..e4bcc5bc 100644 --- a/src/SMAPI.Mods.ErrorHandler/ModEntry.cs +++ b/src/SMAPI.Mods.ErrorHandler/ModEntry.cs @@ -26,21 +26,15 @@ namespace StardewModdingAPI.Mods.ErrorHandler public override void Entry(IModHelper helper) { // get SMAPI core types - SCore core = SCore.Instance; - LogManager logManager = core.GetType().GetField("LogManager", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(core) as LogManager; - if (logManager == null) - { - this.Monitor.Log("Can't access SMAPI's internal log manager. Error-handling patches won't be applied.", LogLevel.Error); - return; - } + IMonitor monitorForGame = this.GetMonitorForGame(); // apply patches new GamePatcher(this.Monitor).Apply( - new EventErrorPatch(logManager.MonitorForGame), - new DialogueErrorPatch(logManager.MonitorForGame, this.Helper.Reflection), + new EventErrorPatch(monitorForGame), + new DialogueErrorPatch(monitorForGame, this.Helper.Reflection), new ObjectErrorPatch(), new LoadErrorPatch(this.Monitor, this.OnSaveContentRemoved), - new ScheduleErrorPatch(logManager.MonitorForGame), + new ScheduleErrorPatch(monitorForGame), new UtilityErrorPatches() ); @@ -61,7 +55,7 @@ namespace StardewModdingAPI.Mods.ErrorHandler /// The method invoked when a save is loaded. /// The event sender. /// The event arguments. - public void OnSaveLoaded(object sender, SaveLoadedEventArgs e) + private void OnSaveLoaded(object sender, SaveLoadedEventArgs e) { // show in-game warning for removed save content if (this.IsSaveContentRemoved) @@ -70,5 +64,16 @@ namespace StardewModdingAPI.Mods.ErrorHandler Game1.addHUDMessage(new HUDMessage(this.Helper.Translation.Get("warn.invalid-content-removed"), HUDMessage.error_type)); } } + + /// Get the monitor with which to log game errors. + private IMonitor GetMonitorForGame() + { + SCore core = SCore.Instance; + LogManager logManager = core.GetType().GetField("LogManager", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(core) as LogManager; + if (logManager == null) + this.Monitor.Log("Can't access SMAPI's internal log manager. Some game errors may be reported as being from Error Handler.", LogLevel.Error); + + return logManager?.MonitorForGame ?? this.Monitor; + } } } -- cgit From 67c52af72d6d0c4fddd3a07b159cb44b5c277599 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 6 Feb 2021 21:12:01 -0500 Subject: add early detection of disposed assets in error handler mod --- docs/release-notes.md | 3 ++ src/SMAPI.Mods.ErrorHandler/ModEntry.cs | 1 + .../Patches/SpriteBatchValidationPatches.cs | 63 ++++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 src/SMAPI.Mods.ErrorHandler/Patches/SpriteBatchValidationPatches.cs (limited to 'src/SMAPI.Mods.ErrorHandler') diff --git a/docs/release-notes.md b/docs/release-notes.md index cb54ee98..9d95dacb 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -16,6 +16,9 @@ * Fixed SMAPI toolkit defaulting the mod type incorrectly if a mod's `manifest.json` has neither `EntryDll` nor `ContentPackFor`. This only affects external tools, since SMAPI itself validates those fields separately. * Fixed edge case when playing in non-English where translatable assets loaded via `IAssetLoader` would no longer be applied after returning to the title screen unless manually invalidated from the cache. +* For the ErrorHandler mod: + * Added early detection of disposed textures so the crash stack trace shows the actual code which used them. + * For the web UI: * Updated the JSON validator/schema for Content Patcher 1.20. diff --git a/src/SMAPI.Mods.ErrorHandler/ModEntry.cs b/src/SMAPI.Mods.ErrorHandler/ModEntry.cs index e4bcc5bc..87f531fe 100644 --- a/src/SMAPI.Mods.ErrorHandler/ModEntry.cs +++ b/src/SMAPI.Mods.ErrorHandler/ModEntry.cs @@ -35,6 +35,7 @@ namespace StardewModdingAPI.Mods.ErrorHandler new ObjectErrorPatch(), new LoadErrorPatch(this.Monitor, this.OnSaveContentRemoved), new ScheduleErrorPatch(monitorForGame), + new SpriteBatchValidationPatches(), new UtilityErrorPatches() ); diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/SpriteBatchValidationPatches.cs b/src/SMAPI.Mods.ErrorHandler/Patches/SpriteBatchValidationPatches.cs new file mode 100644 index 00000000..0211cfb1 --- /dev/null +++ b/src/SMAPI.Mods.ErrorHandler/Patches/SpriteBatchValidationPatches.cs @@ -0,0 +1,63 @@ +#if HARMONY_2 +using HarmonyLib; +#else +using Harmony; +#endif +using System; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Xna.Framework.Graphics; +using StardewModdingAPI.Framework.Patching; + +namespace StardewModdingAPI.Mods.ErrorHandler.Patches +{ + /// Harmony patch for to validate textures earlier. + /// Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments. + [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] + [SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] + internal class SpriteBatchValidationPatches : IHarmonyPatch + { + /********* + ** Accessors + *********/ + /// + public string Name => nameof(SpriteBatchValidationPatches); + + + /********* + ** Public methods + *********/ + /// +#if HARMONY_2 + public void Apply(Harmony harmony) +#else + public void Apply(HarmonyInstance harmony) +#endif + { + harmony.Patch( +#if SMAPI_FOR_WINDOWS + original: AccessTools.Method(typeof(SpriteBatch), "InternalDraw"), +#else + original: AccessTools.Method(typeof(SpriteBatch), "CheckValid", new[] { typeof(Texture2D) }), +#endif + postfix: new HarmonyMethod(this.GetType(), nameof(SpriteBatchValidationPatches.After_SpriteBatch_CheckValid)) + ); + } + + + /********* + ** Private methods + *********/ +#if SMAPI_FOR_WINDOWS + /// The method to call instead of . + /// The texture to validate. +#else + /// The method to call instead of . + /// The texture to validate. +#endif + private static void After_SpriteBatch_CheckValid(Texture2D texture) + { + if (texture?.IsDisposed == true) + throw new ObjectDisposedException("Cannot draw this texture because it's disposed."); + } + } +} -- cgit From fa3305e1d8cb079fcfbccd87d2368627b4138ee4 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 8 Feb 2021 19:32:48 -0500 Subject: add error details when an event command fails --- docs/release-notes.md | 1 + src/SMAPI.Mods.ErrorHandler/ModEntry.cs | 3 +- .../Patches/EventErrorPatch.cs | 114 --------------------- .../Patches/EventPatches.cs | 67 ++++++++++++ .../Patches/GameLocationPatches.cs | 114 +++++++++++++++++++++ 5 files changed, 184 insertions(+), 115 deletions(-) delete mode 100644 src/SMAPI.Mods.ErrorHandler/Patches/EventErrorPatch.cs create mode 100644 src/SMAPI.Mods.ErrorHandler/Patches/EventPatches.cs create mode 100644 src/SMAPI.Mods.ErrorHandler/Patches/GameLocationPatches.cs (limited to 'src/SMAPI.Mods.ErrorHandler') diff --git a/docs/release-notes.md b/docs/release-notes.md index 7e2829d3..e5cac9e0 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -18,6 +18,7 @@ * For the ErrorHandler mod: * Added early detection of disposed textures so the crash stack trace shows the actual code which used them. + * Added error details when an event command fails. * For the web UI: * Updated the JSON validator/schema for Content Patcher 1.20. diff --git a/src/SMAPI.Mods.ErrorHandler/ModEntry.cs b/src/SMAPI.Mods.ErrorHandler/ModEntry.cs index 87f531fe..d9426d75 100644 --- a/src/SMAPI.Mods.ErrorHandler/ModEntry.cs +++ b/src/SMAPI.Mods.ErrorHandler/ModEntry.cs @@ -30,8 +30,9 @@ namespace StardewModdingAPI.Mods.ErrorHandler // apply patches new GamePatcher(this.Monitor).Apply( - new EventErrorPatch(monitorForGame), new DialogueErrorPatch(monitorForGame, this.Helper.Reflection), + new EventPatches(monitorForGame), + new GameLocationPatches(monitorForGame), new ObjectErrorPatch(), new LoadErrorPatch(this.Monitor, this.OnSaveContentRemoved), new ScheduleErrorPatch(monitorForGame), diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/EventErrorPatch.cs b/src/SMAPI.Mods.ErrorHandler/Patches/EventErrorPatch.cs deleted file mode 100644 index fabc6cad..00000000 --- a/src/SMAPI.Mods.ErrorHandler/Patches/EventErrorPatch.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -#if HARMONY_2 -using System; -using HarmonyLib; -#else -using System.Reflection; -using Harmony; -#endif -using StardewModdingAPI.Framework.Patching; -using StardewValley; - -namespace StardewModdingAPI.Mods.ErrorHandler.Patches -{ - /// A Harmony patch for which intercepts invalid preconditions and logs an error instead of crashing. - /// Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments. - [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] - [SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] - internal class EventErrorPatch : IHarmonyPatch - { - /********* - ** Fields - *********/ - /// Writes messages to the console and log file on behalf of the game. - private static IMonitor MonitorForGame; - - - /********* - ** Accessors - *********/ - /// - public string Name => nameof(EventErrorPatch); - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// Writes messages to the console and log file on behalf of the game. - public EventErrorPatch(IMonitor monitorForGame) - { - EventErrorPatch.MonitorForGame = monitorForGame; - } - - /// -#if HARMONY_2 - public void Apply(Harmony harmony) - { - harmony.Patch( - original: AccessTools.Method(typeof(GameLocation), "checkEventPrecondition"), - finalizer: new HarmonyMethod(this.GetType(), nameof(EventErrorPatch.Finalize_GameLocation_CheckEventPrecondition)) - ); - } -#else - public void Apply(HarmonyInstance harmony) - { - harmony.Patch( - original: AccessTools.Method(typeof(GameLocation), "checkEventPrecondition"), - prefix: new HarmonyMethod(this.GetType(), nameof(EventErrorPatch.Before_GameLocation_CheckEventPrecondition)) - ); - } -#endif - - - /********* - ** Private methods - *********/ -#if HARMONY_2 - /// The method to call instead of GameLocation.checkEventPrecondition. - /// The return value of the original method. - /// The precondition to be parsed. - /// The exception thrown by the wrapped method, if any. - /// Returns the exception to throw, if any. - private static Exception Finalize_GameLocation_CheckEventPrecondition(ref int __result, string precondition, Exception __exception) - { - if (__exception != null) - { - __result = -1; - EventErrorPatch.MonitorForGame.Log($"Failed parsing event precondition ({precondition}):\n{__exception.InnerException}", LogLevel.Error); - } - - return null; - } -#else - /// The method to call instead of GameLocation.checkEventPrecondition. - /// The instance being patched. - /// The return value of the original method. - /// The precondition to be parsed. - /// The method being wrapped. - /// Returns whether to execute the original method. - private static bool Before_GameLocation_CheckEventPrecondition(GameLocation __instance, ref int __result, string precondition, MethodInfo __originalMethod) - { - const string key = nameof(EventErrorPatch.Before_GameLocation_CheckEventPrecondition); - if (!PatchHelper.StartIntercept(key)) - return true; - - try - { - __result = (int)__originalMethod.Invoke(__instance, new object[] { precondition }); - return false; - } - catch (TargetInvocationException ex) - { - __result = -1; - EventErrorPatch.MonitorForGame.Log($"Failed parsing event precondition ({precondition}):\n{ex.InnerException}", LogLevel.Error); - return false; - } - finally - { - PatchHelper.StopIntercept(key); - } - } -#endif - } -} diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/EventPatches.cs b/src/SMAPI.Mods.ErrorHandler/Patches/EventPatches.cs new file mode 100644 index 00000000..a15c1d32 --- /dev/null +++ b/src/SMAPI.Mods.ErrorHandler/Patches/EventPatches.cs @@ -0,0 +1,67 @@ +using System; +using System.Diagnostics.CodeAnalysis; +#if HARMONY_2 +using HarmonyLib; +#else +using Harmony; +#endif +using StardewModdingAPI.Framework.Patching; +using StardewValley; + +namespace StardewModdingAPI.Mods.ErrorHandler.Patches +{ + /// Harmony patches for which intercept errors to log more details. + /// Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments. + [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] + [SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] + internal class EventPatches : IHarmonyPatch + { + /********* + ** Fields + *********/ + /// Writes messages to the console and log file on behalf of the game. + private static IMonitor MonitorForGame; + + + /********* + ** Accessors + *********/ + /// + public string Name => nameof(EventPatches); + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// Writes messages to the console and log file on behalf of the game. + public EventPatches(IMonitor monitorForGame) + { + EventPatches.MonitorForGame = monitorForGame; + } + + /// +#if HARMONY_2 + public void Apply(Harmony harmony) +#else + public void Apply(HarmonyInstance harmony) +#endif + { + harmony.Patch( + original: AccessTools.Method(typeof(Event), nameof(Event.LogErrorAndHalt)), + postfix: new HarmonyMethod(this.GetType(), nameof(EventPatches.After_Event_LogErrorAndHalt)) + ); + } + + + /********* + ** Private methods + *********/ + /// The method to call after . + /// The exception being logged. + private static void After_Event_LogErrorAndHalt(Exception e) + { + EventPatches.MonitorForGame.Log(e.ToString(), LogLevel.Error); + } + } +} diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/GameLocationPatches.cs b/src/SMAPI.Mods.ErrorHandler/Patches/GameLocationPatches.cs new file mode 100644 index 00000000..c10f2de7 --- /dev/null +++ b/src/SMAPI.Mods.ErrorHandler/Patches/GameLocationPatches.cs @@ -0,0 +1,114 @@ +using System.Diagnostics.CodeAnalysis; +#if HARMONY_2 +using System; +using HarmonyLib; +#else +using System.Reflection; +using Harmony; +#endif +using StardewModdingAPI.Framework.Patching; +using StardewValley; + +namespace StardewModdingAPI.Mods.ErrorHandler.Patches +{ + /// A Harmony patch for which intercepts invalid preconditions and logs an error instead of crashing. + /// Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments. + [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] + [SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] + internal class GameLocationPatches : IHarmonyPatch + { + /********* + ** Fields + *********/ + /// Writes messages to the console and log file on behalf of the game. + private static IMonitor MonitorForGame; + + + /********* + ** Accessors + *********/ + /// + public string Name => nameof(GameLocationPatches); + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// Writes messages to the console and log file on behalf of the game. + public GameLocationPatches(IMonitor monitorForGame) + { + GameLocationPatches.MonitorForGame = monitorForGame; + } + + /// +#if HARMONY_2 + public void Apply(Harmony harmony) + { + harmony.Patch( + original: AccessTools.Method(typeof(GameLocation), "checkEventPrecondition"), + finalizer: new HarmonyMethod(this.GetType(), nameof(EventErrorPatch.Finalize_GameLocation_CheckEventPrecondition)) + ); + } +#else + public void Apply(HarmonyInstance harmony) + { + harmony.Patch( + original: AccessTools.Method(typeof(GameLocation), "checkEventPrecondition"), + prefix: new HarmonyMethod(this.GetType(), nameof(GameLocationPatches.Before_GameLocation_CheckEventPrecondition)) + ); + } +#endif + + + /********* + ** Private methods + *********/ +#if HARMONY_2 + /// The method to call instead of GameLocation.checkEventPrecondition. + /// The return value of the original method. + /// The precondition to be parsed. + /// The exception thrown by the wrapped method, if any. + /// Returns the exception to throw, if any. + private static Exception Finalize_GameLocation_CheckEventPrecondition(ref int __result, string precondition, Exception __exception) + { + if (__exception != null) + { + __result = -1; + EventErrorPatch.MonitorForGame.Log($"Failed parsing event precondition ({precondition}):\n{__exception.InnerException}", LogLevel.Error); + } + + return null; + } +#else + /// The method to call instead of GameLocation.checkEventPrecondition. + /// The instance being patched. + /// The return value of the original method. + /// The precondition to be parsed. + /// The method being wrapped. + /// Returns whether to execute the original method. + private static bool Before_GameLocation_CheckEventPrecondition(GameLocation __instance, ref int __result, string precondition, MethodInfo __originalMethod) + { + const string key = nameof(GameLocationPatches.Before_GameLocation_CheckEventPrecondition); + if (!PatchHelper.StartIntercept(key)) + return true; + + try + { + __result = (int)__originalMethod.Invoke(__instance, new object[] { precondition }); + return false; + } + catch (TargetInvocationException ex) + { + __result = -1; + GameLocationPatches.MonitorForGame.Log($"Failed parsing event precondition ({precondition}):\n{ex.InnerException}", LogLevel.Error); + return false; + } + finally + { + PatchHelper.StopIntercept(key); + } + } +#endif + } +} -- cgit From 9c4c10d2d22cbf67ccadbd35fdf1ffced0541cc2 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 21 Feb 2021 21:58:37 -0500 Subject: prepare for release --- build/common.targets | 2 +- docs/release-notes.md | 14 ++++++++------ src/SMAPI.Mods.ConsoleCommands/manifest.json | 4 ++-- src/SMAPI.Mods.ErrorHandler/manifest.json | 4 ++-- src/SMAPI.Mods.SaveBackup/manifest.json | 4 ++-- src/SMAPI/Constants.cs | 2 +- 6 files changed, 16 insertions(+), 14 deletions(-) (limited to 'src/SMAPI.Mods.ErrorHandler') diff --git a/build/common.targets b/build/common.targets index a38f15a6..29acbb56 100644 --- a/build/common.targets +++ b/build/common.targets @@ -4,7 +4,7 @@ - 3.9.1 + 3.9.2 SMAPI latest diff --git a/docs/release-notes.md b/docs/release-notes.md index 09c941d6..fb67d8dc 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -7,21 +7,23 @@ * Migrated to Harmony 2.0 (see [_migrate to Harmony 2.0_](https://stardewvalleywiki.com/Modding:Migrate_to_Harmony_2.0) for more info). --> -## Upcoming release +## 3.9.2 +Released 21 February 2021 for Stardew Valley 1.5.4 or later. + * For players: - * Added more aggressive memory optimization which should reduce `OutOfMemoryException` errors with some mods. - * Added more detailed error when `Stardew Valley.exe` exists but can't be loaded. + * Added more aggressive memory optimization to reduce `OutOfMemoryException` errors with some mods. + * Improved error when `Stardew Valley.exe` exists but can't be loaded. * Fixed error running `install on Windows.bat` in very rare cases. - * Fixed outdoor ambient lighting not updated when you reverse time using the `world_settime` command _(in Console Commands)_. + * Fixed `world_settime` command not always updating outdoor ambient lighting _(in Console Commands)_. * For mod authors: - * Added early detection of disposed textures so the crash stack trace shows the actual code which used them _(in Error Handler)_. + * Added early detection of disposed textures so the error details are more relevant _(in Error Handler)_. * Added error details when an event command fails _(in Error Handler)_. * Fixed asset propagation for `TileSheets/ChairTiles` not changing existing map seats. * Fixed edge case when playing in non-English where translatable assets loaded via `IAssetLoader` would no longer be applied after returning to the title screen unless manually invalidated from the cache. * For the web UI: - * Updated for the new wiki. + * Updated compatibility list for the new wiki. * Updated the JSON validator/schema for Content Patcher 1.20. * Fixed mod compatibility list error if a mod has no name. diff --git a/src/SMAPI.Mods.ConsoleCommands/manifest.json b/src/SMAPI.Mods.ConsoleCommands/manifest.json index 10611e08..aa3d6ceb 100644 --- a/src/SMAPI.Mods.ConsoleCommands/manifest.json +++ b/src/SMAPI.Mods.ConsoleCommands/manifest.json @@ -1,9 +1,9 @@ { "Name": "Console Commands", "Author": "SMAPI", - "Version": "3.9.1", + "Version": "3.9.2", "Description": "Adds SMAPI console commands that let you manipulate the game.", "UniqueID": "SMAPI.ConsoleCommands", "EntryDll": "ConsoleCommands.dll", - "MinimumApiVersion": "3.9.1" + "MinimumApiVersion": "3.9.2" } diff --git a/src/SMAPI.Mods.ErrorHandler/manifest.json b/src/SMAPI.Mods.ErrorHandler/manifest.json index bb9942d1..b6df0f49 100644 --- a/src/SMAPI.Mods.ErrorHandler/manifest.json +++ b/src/SMAPI.Mods.ErrorHandler/manifest.json @@ -1,9 +1,9 @@ { "Name": "Error Handler", "Author": "SMAPI", - "Version": "3.9.1", + "Version": "3.9.2", "Description": "Handles some common vanilla errors to log more useful info or avoid breaking the game.", "UniqueID": "SMAPI.ErrorHandler", "EntryDll": "ErrorHandler.dll", - "MinimumApiVersion": "3.9.1" + "MinimumApiVersion": "3.9.2" } diff --git a/src/SMAPI.Mods.SaveBackup/manifest.json b/src/SMAPI.Mods.SaveBackup/manifest.json index 95ee5144..4d2003e2 100644 --- a/src/SMAPI.Mods.SaveBackup/manifest.json +++ b/src/SMAPI.Mods.SaveBackup/manifest.json @@ -1,9 +1,9 @@ { "Name": "Save Backup", "Author": "SMAPI", - "Version": "3.9.1", + "Version": "3.9.2", "Description": "Automatically backs up all your saves once per day into its folder.", "UniqueID": "SMAPI.SaveBackup", "EntryDll": "SaveBackup.dll", - "MinimumApiVersion": "3.9.1" + "MinimumApiVersion": "3.9.2" } diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index 57c40bbf..54fb54ab 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -54,7 +54,7 @@ namespace StardewModdingAPI ** Public ****/ /// SMAPI's current semantic version. - public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("3.9.1"); + public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("3.9.2"); /// The minimum supported version of Stardew Valley. public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.5.4"); -- cgit