diff --git a/build/common.targets b/build/common.targets index f2614998..498ec7af 100644 --- a/build/common.targets +++ b/build/common.targets @@ -1,7 +1,7 @@ - 3.12.1 + 3.12.2 SMAPI latest $(AssemblySearchPaths);{GAC} diff --git a/docs/release-notes.md b/docs/release-notes.md index 16744b24..4e9dacbf 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,6 +1,17 @@ ← [README](README.md) # Release notes +## 3.12.2 +Released 04 August 2021 for Stardew Valley 1.5.4 or later. + +* For players: + * Fixed error creating a new save or joining a multiplayer world in 3.12.1. + +* For mod authors: + * Reverted the `Constants.Save*` fix in SMAPI 3.12.1. + _The change caused a number of other issues, and is only needed for rare cases where the save folder was invalid. This may be revisited in a future version instead._ + * Fixed `NullReferenceException` in SMAPI's error-handling when trying to handle an invalid `ReflectionTypeLoadException`. + ## 3.12.1 Released 03 August 2021 for Stardew Valley 1.5.4 or later. diff --git a/src/SMAPI.Internal/ExceptionExtensions.cs b/src/SMAPI.Internal/ExceptionExtensions.cs index d7a2252b..5f1ee1fa 100644 --- a/src/SMAPI.Internal/ExceptionExtensions.cs +++ b/src/SMAPI.Internal/ExceptionExtensions.cs @@ -19,9 +19,9 @@ namespace StardewModdingAPI.Internal return $"Failed loading type '{ex.TypeName}': {exception}"; case ReflectionTypeLoadException ex: - string summary = exception.ToString(); - foreach (Exception childEx in ex.LoaderExceptions) - summary += $"\n\n{childEx.GetLogSummary()}"; + string summary = ex.ToString(); + foreach (Exception childEx in ex.LoaderExceptions ?? new Exception[0]) + summary += $"\n\n{childEx?.GetLogSummary()}"; return summary; default: diff --git a/src/SMAPI.Mods.ConsoleCommands/manifest.json b/src/SMAPI.Mods.ConsoleCommands/manifest.json index 7023180b..6b49cd5f 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.12.1", + "Version": "3.12.2", "Description": "Adds SMAPI console commands that let you manipulate the game.", "UniqueID": "SMAPI.ConsoleCommands", "EntryDll": "ConsoleCommands.dll", - "MinimumApiVersion": "3.12.1" + "MinimumApiVersion": "3.12.2" } diff --git a/src/SMAPI.Mods.ErrorHandler/manifest.json b/src/SMAPI.Mods.ErrorHandler/manifest.json index 8aa2a6a4..7759d1d5 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.12.1", + "Version": "3.12.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.12.1" + "MinimumApiVersion": "3.12.2" } diff --git a/src/SMAPI.Mods.SaveBackup/manifest.json b/src/SMAPI.Mods.SaveBackup/manifest.json index dbd65cbe..1e5b8b97 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.12.1", + "Version": "3.12.2", "Description": "Automatically backs up all your saves once per day into its folder.", "UniqueID": "SMAPI.SaveBackup", "EntryDll": "SaveBackup.dll", - "MinimumApiVersion": "3.12.1" + "MinimumApiVersion": "3.12.2" } diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index 05800970..6cbdeb8e 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Reflection; using StardewModdingAPI.Enums; using StardewModdingAPI.Framework; @@ -60,7 +61,7 @@ namespace StardewModdingAPI internal static int? LogScreenId { get; set; } /// SMAPI's current raw semantic version. - internal static string RawApiVersion = "3.12.1"; + internal static string RawApiVersion = "3.12.2"; } /// Contains SMAPI's constants and assumptions. @@ -164,9 +165,6 @@ namespace StardewModdingAPI /// The language code for non-translated mod assets. internal static LocalizedContentManager.LanguageCode DefaultLanguage { get; } = LocalizedContentManager.LanguageCode.en; - /// The name of the last save file loaded by the game. - internal static string LastRawSaveFileName { get; set; } - /********* ** Internal methods @@ -343,9 +341,30 @@ namespace StardewModdingAPI if (Context.LoadStage == LoadStage.None) return null; - // get save - string rawSaveName = Constants.LastRawSaveFileName; - return new DirectoryInfo(Path.Combine(Constants.SavesPath, rawSaveName)); + // get basic info + string rawSaveName = Game1.GetSaveGameName(set_value: false); + ulong saveID = Context.LoadStage == LoadStage.SaveParsed + ? SaveGame.loaded.uniqueIDForThisGame + : Game1.uniqueIDForThisGame; + + // get best match (accounting for rare case where folder name isn't sanitized) + DirectoryInfo folder = null; + foreach (string saveName in new[] { rawSaveName, new string(rawSaveName.Where(char.IsLetterOrDigit).ToArray()) }) + { + try + { + folder = new DirectoryInfo(Path.Combine(Constants.SavesPath, $"{saveName}_{saveID}")); + if (folder.Exists) + return folder; + } + catch (ArgumentException) + { + // ignore invalid path + } + } + + // if save doesn't exist yet, return the default one we expect to be created + return folder; } } } diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 3f97bd4e..5fb4aa03 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -257,7 +257,6 @@ namespace StardewModdingAPI.Framework MiniMonoModHotfix.Apply(); HarmonyPatcher.Apply("SMAPI", this.Monitor, new Game1Patcher(this.Reflection, this.OnLoadStageChanged), - new SaveGamePatcher(this.OnSaveFileReading), new TitleMenuPatcher(this.OnLoadStageChanged) ); @@ -1102,13 +1101,6 @@ namespace StardewModdingAPI.Framework this.EventManager.ReturnedToTitle.RaiseEmpty(); } - /// Raised before the game begins reading a save file. - /// The save folder name. - internal void OnSaveFileReading(string fileName) - { - Constants.LastRawSaveFileName = fileName; - } - /// Apply fixes to the save after it's loaded. private void ApplySaveFixes() { diff --git a/src/SMAPI/Patches/SaveGamePatcher.cs b/src/SMAPI/Patches/SaveGamePatcher.cs deleted file mode 100644 index 969c514e..00000000 --- a/src/SMAPI/Patches/SaveGamePatcher.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using HarmonyLib; -using StardewModdingAPI.Internal.Patching; -using StardewValley; -using StardewValley.Menus; - -namespace StardewModdingAPI.Patches -{ - /// Harmony patches for which track the last loaded save ID. - /// 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 SaveGamePatcher : BasePatcher - { - /********* - ** Fields - *********/ - /// A callback to invoke when a save file is being loaded. - private static Action OnSaveFileReading; - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// A callback to invoke when a save file is being loaded. - public SaveGamePatcher(Action onSaveFileReading) - { - SaveGamePatcher.OnSaveFileReading = onSaveFileReading; - } - - /// - public override void Apply(Harmony harmony, IMonitor monitor) - { - harmony.Patch( - original: this.RequireMethod(nameof(SaveGame.getLoadEnumerator)), - prefix: this.GetHarmonyMethod(nameof(SaveGamePatcher.Before_GetLoadEnumerator)) - ); - } - - - /********* - ** Private methods - *********/ - /// The method to call before . - /// Returns whether to execute the original method. - /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments. - private static bool Before_GetLoadEnumerator(string file) - { - SaveGamePatcher.OnSaveFileReading(file); - return true; - } - } -}