From 8df578edb6d135796a48b219ecc7a7291c7ef460 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 13 Jul 2021 09:14:07 -0400 Subject: migrate to Harmony 2.1 (#711) --- docs/release-notes.md | 6 ++---- docs/technical/smapi.md | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index d0aa2fbf..50ed5f29 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,11 +1,9 @@ ← [README](README.md) # Release notes - + * Updated Harmony 1.2.0.1 to 2.1.0 (see [_migrate to Harmony 2.0_](https://stardewvalleywiki.com/Modding:Migrate_to_Harmony_2.0) for more info). ## 3.11.0 Released 09 July 2021 for Stardew Valley 1.5.4 or later. See [release highlights](https://www.patreon.com/posts/53514295). diff --git a/docs/technical/smapi.md b/docs/technical/smapi.md index b64239c1..586b17aa 100644 --- a/docs/technical/smapi.md +++ b/docs/technical/smapi.md @@ -59,7 +59,6 @@ flag | purpose `SMAPI_FOR_WINDOWS` | Whether SMAPI is being compiled for Windows; if not set, the code assumes Linux/macOS. Set automatically in `common.targets`. `SMAPI_FOR_WINDOWS_64BIT_HACK` | Whether SMAPI is being [compiled for Windows with a 64-bit Linux version of the game](https://github.com/Pathoschild/SMAPI/issues/767). This is highly specialized and shouldn't be used in most cases. False by default. `SMAPI_FOR_XNA` | Whether SMAPI is being compiled for XNA Framework; if not set, the code assumes MonoGame. Set automatically in `common.targets` with the same value as `SMAPI_FOR_WINDOWS` (unless `SMAPI_FOR_WINDOWS_64BIT_HACK` is set). -`HARMONY_2` | Whether to enable experimental Harmony 2.0 support and rewrite existing Harmony 1._x_ mods for compatibility. Note that you need to replace `build/0Harmony.dll` with a Harmony 2.0 build (or switch to a package reference) to use this flag. ## For SMAPI developers ### Compiling from source -- cgit From 735893c1d5549915c2874a9e17dc1d9844408710 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 17 Jul 2021 18:52:06 -0400 Subject: add error if player manually installs wrong SMAPI bitness --- docs/release-notes.md | 4 ++++ src/SMAPI.Installer/InteractiveInstaller.cs | 3 ++- src/SMAPI.Toolkit/Framework/LowLevelEnvironmentUtility.cs | 9 ++++++++- src/SMAPI/Program.cs | 13 ++++++++++++- 4 files changed, 26 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index d0aa2fbf..9727dd6a 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -7,6 +7,10 @@ * 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 +* For players: + * Added error message if you manually install the wrong SMAPI bitness (e.g. 32-bit SMAPI with 64-bit game). + ## 3.11.0 Released 09 July 2021 for Stardew Valley 1.5.4 or later. See [release highlights](https://www.patreon.com/posts/53514295). diff --git a/src/SMAPI.Installer/InteractiveInstaller.cs b/src/SMAPI.Installer/InteractiveInstaller.cs index 55e9c064..ab07c864 100644 --- a/src/SMAPI.Installer/InteractiveInstaller.cs +++ b/src/SMAPI.Installer/InteractiveInstaller.cs @@ -9,6 +9,7 @@ using StardewModdingApi.Installer.Enums; using StardewModdingAPI.Installer.Framework; using StardewModdingAPI.Internal.ConsoleWriting; using StardewModdingAPI.Toolkit; +using StardewModdingAPI.Toolkit.Framework; using StardewModdingAPI.Toolkit.Framework.ModScanning; using StardewModdingAPI.Toolkit.Utilities; @@ -571,7 +572,7 @@ namespace StardewModdingApi.Installer /// The absolute path to the executable file. private bool Is64Bit(string executablePath) { - return AssemblyName.GetAssemblyName(executablePath).ProcessorArchitecture != ProcessorArchitecture.X86; + return LowLevelEnvironmentUtility.Is64BitAssembly(executablePath); } /// Get the display text for a color scheme. diff --git a/src/SMAPI.Toolkit/Framework/LowLevelEnvironmentUtility.cs b/src/SMAPI.Toolkit/Framework/LowLevelEnvironmentUtility.cs index 8cbd8e51..be0c18ce 100644 --- a/src/SMAPI.Toolkit/Framework/LowLevelEnvironmentUtility.cs +++ b/src/SMAPI.Toolkit/Framework/LowLevelEnvironmentUtility.cs @@ -2,6 +2,7 @@ using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Reflection; #if SMAPI_FOR_WINDOWS using System.Management; #endif @@ -48,7 +49,6 @@ namespace StardewModdingAPI.Toolkit.Framework } } - /// Get the human-readable OS name and version. /// The current platform. [SuppressMessage("ReSharper", "EmptyGeneralCatchClause", Justification = "Error suppressed deliberately to fallback to default behaviour.")] @@ -89,6 +89,13 @@ namespace StardewModdingAPI.Toolkit.Framework : "StardewValley.exe"; } + /// Get whether an executable is 64-bit. + /// The absolute path to the executable file. + public static bool Is64BitAssembly(string executablePath) + { + return AssemblyName.GetAssemblyName(executablePath).ProcessorArchitecture != ProcessorArchitecture.X86; + } + /********* ** Private methods diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs index e830f799..0257a03e 100644 --- a/src/SMAPI/Program.cs +++ b/src/SMAPI/Program.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Reflection; using System.Threading; using StardewModdingAPI.Framework; +using StardewModdingAPI.Toolkit.Framework; namespace StardewModdingAPI { @@ -107,8 +108,18 @@ namespace StardewModdingAPI } // max version - else if (Constants.MaximumGameVersion != null && Constants.GameVersion.IsNewerThan(Constants.MaximumGameVersion)) + if (Constants.MaximumGameVersion != null && Constants.GameVersion.IsNewerThan(Constants.MaximumGameVersion)) Program.PrintErrorAndExit($"Oops! You're running Stardew Valley {Constants.GameVersion}, but this version of SMAPI is only compatible up to Stardew Valley {Constants.MaximumGameVersion}. Please check for a newer version of SMAPI: https://smapi.io."); + + // bitness + bool is64BitGame = LowLevelEnvironmentUtility.Is64BitAssembly(Path.Combine(EarlyConstants.ExecutionPath, $"{EarlyConstants.GameAssemblyName}.exe")); +#if SMAPI_FOR_WINDOWS_64BIT_HACK + if (!is64bit) + Program.PrintErrorAndExit("Oops! This is the 64-bit version of SMAPI, but you have the 32-bit version of Stardew Valley. You can reinstall SMAPI using its installer to automatically install the correct version of SMAPI."); +#elif SMAPI_FOR_WINDOWS + if (is64BitGame) + Program.PrintErrorAndExit("Oops! This is the 32-bit version of SMAPI, but you have the 64-bit version of Stardew Valley. You can reinstall SMAPI using its installer to automatically install the correct version of SMAPI."); +#endif } /// Initialize SMAPI and launch the game. -- cgit From defa1b9a95c6bcb680bef3506ab94a71ed6189d6 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 20 Jul 2021 18:43:56 -0400 Subject: fix concurrency issue in interface proxying --- docs/release-notes.md | 1 + .../Framework/Reflection/InterfaceProxyFactory.cs | 33 ++++++++++++---------- 2 files changed, 19 insertions(+), 15 deletions(-) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index 9727dd6a..bfea8bfb 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -10,6 +10,7 @@ ## Upcoming release * For players: * Added error message if you manually install the wrong SMAPI bitness (e.g. 32-bit SMAPI with 64-bit game). + * Fixed intermittent error if a mod fetches mod-provided APIs asynchronously. ## 3.11.0 Released 09 July 2021 for Stardew Valley 1.5.4 or later. See [release highlights](https://www.patreon.com/posts/53514295). diff --git a/src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs b/src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs index 464367b6..8d1b6034 100644 --- a/src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs +++ b/src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs @@ -36,23 +36,26 @@ namespace StardewModdingAPI.Framework.Reflection public TInterface CreateProxy(object instance, string sourceModID, string targetModID) where TInterface : class { - // validate - if (instance == null) - throw new InvalidOperationException("Can't proxy access to a null API."); - if (!typeof(TInterface).IsInterface) - throw new InvalidOperationException("The proxy type must be an interface, not a class."); - - // get proxy type - Type targetType = instance.GetType(); - string proxyTypeName = $"StardewModdingAPI.Proxies.From<{sourceModID}_{typeof(TInterface).FullName}>_To<{targetModID}_{targetType.FullName}>"; - if (!this.Builders.TryGetValue(proxyTypeName, out InterfaceProxyBuilder builder)) + lock (this.Builders) { - builder = new InterfaceProxyBuilder(proxyTypeName, this.ModuleBuilder, typeof(TInterface), targetType); - this.Builders[proxyTypeName] = builder; - } + // validate + if (instance == null) + throw new InvalidOperationException("Can't proxy access to a null API."); + if (!typeof(TInterface).IsInterface) + throw new InvalidOperationException("The proxy type must be an interface, not a class."); - // create instance - return (TInterface)builder.CreateInstance(instance); + // get proxy type + Type targetType = instance.GetType(); + string proxyTypeName = $"StardewModdingAPI.Proxies.From<{sourceModID}_{typeof(TInterface).FullName}>_To<{targetModID}_{targetType.FullName}>"; + if (!this.Builders.TryGetValue(proxyTypeName, out InterfaceProxyBuilder builder)) + { + builder = new InterfaceProxyBuilder(proxyTypeName, this.ModuleBuilder, typeof(TInterface), targetType); + this.Builders[proxyTypeName] = builder; + } + + // create instance + return (TInterface)builder.CreateInstance(instance); + } } } } -- cgit From c74702b027aeab927b4e038e440cbbb24d859cfd Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 20 Jul 2021 22:18:57 -0400 Subject: fix error loading .xnb files from the local mod folder since SMAPI 3.0 --- docs/release-notes.md | 3 +++ src/SMAPI/Framework/ContentManagers/ModContentManager.cs | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index bfea8bfb..fea93104 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -12,6 +12,9 @@ * Added error message if you manually install the wrong SMAPI bitness (e.g. 32-bit SMAPI with 64-bit game). * Fixed intermittent error if a mod fetches mod-provided APIs asynchronously. +* For mod authors: + * Fixed error loading `.xnb` files from the local mod folder since SMAPI 3.0. + ## 3.11.0 Released 09 July 2021 for Stardew Valley 1.5.4 or later. See [release highlights](https://www.patreon.com/posts/53514295). diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs index 4f6aa775..bc5a8b74 100644 --- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs @@ -77,6 +77,8 @@ namespace StardewModdingAPI.Framework.ContentManagers /// public override T Load(string assetName, LanguageCode language, bool useCache) { + // normalize key + bool isXnbFile = Path.GetExtension(assetName).ToLower() == ".xnb"; assetName = this.AssertAndNormalizeAssetName(assetName); // disable caching @@ -108,7 +110,7 @@ namespace StardewModdingAPI.Framework.ContentManagers try { // get file - FileInfo file = this.GetModFile(assetName); + FileInfo file = this.GetModFile(isXnbFile ? $"{assetName}.xnb" : assetName); // .xnb extension is stripped from asset names passed to the content manager if (!file.Exists) throw GetContentError("the specified path doesn't exist."); -- cgit From 7e5d77fb8c2606795af239717a596de460bc58f7 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 21 Jul 2021 00:43:43 -0400 Subject: add error if some SMAPI DLLs have mismatched versions --- docs/release-notes.md | 3 ++- src/SMAPI/Program.cs | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index fea93104..1614f169 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -9,7 +9,8 @@ ## Upcoming release * For players: - * Added error message if you manually install the wrong SMAPI bitness (e.g. 32-bit SMAPI with 64-bit game). + * Added error if the wrong SMAPI bitness is installed (e.g. 32-bit SMAPI with 64-bit game). + * Added error if some SMAPI files aren't updated correctly. * Fixed intermittent error if a mod fetches mod-provided APIs asynchronously. * For mod authors: diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs index 0257a03e..e6e51ac6 100644 --- a/src/SMAPI/Program.cs +++ b/src/SMAPI/Program.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Threading; using StardewModdingAPI.Framework; using StardewModdingAPI.Toolkit.Framework; +using StardewModdingAPI.Toolkit.Serialization.Models; namespace StardewModdingAPI { @@ -32,6 +33,7 @@ namespace StardewModdingAPI AppDomain.CurrentDomain.AssemblyResolve += Program.CurrentDomain_AssemblyResolve; Program.AssertGamePresent(); Program.AssertGameVersion(); + Program.AssertSmapiVersions(); Program.Start(args); } catch (BadImageFormatException ex) when (ex.FileName == "StardewValley" || ex.FileName == "Stardew Valley") // don't use EarlyConstants.GameAssemblyName, since we want to check both possible names @@ -122,6 +124,20 @@ namespace StardewModdingAPI #endif } + /// Assert that the versions of all SMAPI components are correct. + /// Players sometimes have mismatched versions (particularly when installed through Vortex), which can cause some very confusing bugs without this check. + private static void AssertSmapiVersions() + { + // SMAPI toolkit + foreach (var type in new[] { typeof(IManifest), typeof(Manifest) }) + { + Assembly assembly = type.Assembly; + var assemblyVersion = new SemanticVersion(assembly.GetName().Version); + if (!assemblyVersion.Equals(Constants.ApiVersion)) + Program.PrintErrorAndExit($"Oops! The 'smapi-internal/{assembly.GetName().Name}.dll' file is version {assemblyVersion} instead of the required {Constants.ApiVersion}. SMAPI doesn't seem to be installed correctly."); + } + } + /// Initialize SMAPI and launch the game. /// The command-line arguments. /// This method is separate from because that can't contain any references to assemblies loaded by (e.g. via ), or Mono will incorrectly show an assembly resolution error before assembly resolution is set up. -- cgit From 163511e68e3e94dcda6ffc8b7e32d91c1f6c0c17 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 21 Jul 2021 23:08:18 -0400 Subject: merge release note sections --- docs/release-notes.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index 4fdfa247..26188ff3 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,10 +1,6 @@ ← [README](README.md) # Release notes -## Upcoming release -* For mod authors: - * Updated Harmony 1.2.0.1 to 2.1.0 (see [_migrate to Harmony 2.0_](https://stardewvalleywiki.com/Modding:Migrate_to_Harmony_2.0) for more info). - ## Upcoming release * For players: * Added error if the wrong SMAPI bitness is installed (e.g. 32-bit SMAPI with 64-bit game). @@ -12,6 +8,7 @@ * Fixed intermittent error if a mod fetches mod-provided APIs asynchronously. * For mod authors: + * Updated Harmony 1.2.0.1 to 2.1.0 (see [_migrate to Harmony 2.0_](https://stardewvalleywiki.com/Modding:Migrate_to_Harmony_2.0) for more info). * Fixed error loading `.xnb` files from the local mod folder since SMAPI 3.0. ## 3.11.0 -- cgit From 428f0c5880fa8b133f601beda2e27c87dc7134af Mon Sep 17 00:00:00 2001 From: bladeoflight16 <1159076+bladeoflight16@users.noreply.github.com> Date: Mon, 26 Jul 2021 21:32:29 -0400 Subject: world_clear: Adding 'removeable' option that includes everything except permanent bushes --- docs/release-notes.md | 1 + .../Framework/Commands/World/ClearCommand.cs | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index 26188ff3..3072a0d6 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -5,6 +5,7 @@ * For players: * Added error if the wrong SMAPI bitness is installed (e.g. 32-bit SMAPI with 64-bit game). * Added error if some SMAPI files aren't updated correctly. + * Added `removeable` option to `world_clear` * Fixed intermittent error if a mod fetches mod-provided APIs asynchronously. * For mod authors: diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/ClearCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/ClearCommand.cs index 2f34d381..d7cd40ec 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/ClearCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/ClearCommand.cs @@ -15,7 +15,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World ** Fields *********/ /// The valid types that can be cleared. - private readonly string[] ValidTypes = { "crops", "debris", "fruit-trees", "furniture", "grass", "trees", "everything" }; + private readonly string[] ValidTypes = { "crops", "debris", "fruit-trees", "furniture", "grass", "trees", "removeable", "everything" }; /// The resource clump IDs to consider debris. private readonly int[] DebrisClumps = { ResourceClump.stumpIndex, ResourceClump.hollowLogIndex, ResourceClump.meteoriteIndex, ResourceClump.boulderIndex }; @@ -30,8 +30,8 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World name: "world_clear", description: "Clears in-game entities in a given location.\n\n" + "Usage: world_clear \n" - + " - object type: the type of object clear. You can specify 'crops', 'debris' (stones/twigs/weeds and dead crops), 'furniture', 'grass', and 'trees' / 'fruit-trees'. You can also specify 'everything', which includes things not removed by the other types (like resource clumps)." + " - location: the location name for which to clear objects (like Farm), or 'current' for the current location.\n" + + " - object type: the type of object clear. You can specify 'crops', 'debris' (stones/twigs/weeds and dead crops), 'furniture', 'grass', and 'trees' / 'fruit-trees'. You can also specify 'removeable', which includes everything that can be removed or destroyed during normal game play, or 'everything', which includes permanent bushes." ) { } @@ -133,6 +133,18 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World break; } + case "removeable": + { + int removed = + this.RemoveFurniture(location, p => true) + + this.RemoveObjects(location, p => true) + + this.RemoveTerrainFeatures(location, p => true) + + this.RemoveLargeTerrainFeatures(location, p => !(p is Bush) || ((Bush)p).isDestroyable(location, p.currentTileLocation)) + + this.RemoveResourceClumps(location, p => true); + monitor.Log($"Done! Removed {removed} entities from {location.Name}.", LogLevel.Info); + break; + } + case "everything": { int removed = -- cgit From e3010f7c41028c3420df06e025f9af594b866c2b Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 28 Jul 2021 00:36:34 -0400 Subject: refactor new code a bit --- docs/release-notes.md | 2 +- .../Framework/Commands/World/ClearCommand.cs | 20 +++++--------------- src/SMAPI.sln.DotSettings | 1 + 3 files changed, 7 insertions(+), 16 deletions(-) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index 3072a0d6..fab3f25c 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -5,7 +5,7 @@ * For players: * Added error if the wrong SMAPI bitness is installed (e.g. 32-bit SMAPI with 64-bit game). * Added error if some SMAPI files aren't updated correctly. - * Added `removeable` option to `world_clear` + * Added `removable` option to the `world_clear` console command (thanks to bladeoflight16!). * Fixed intermittent error if a mod fetches mod-provided APIs asynchronously. * For mod authors: diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/ClearCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/ClearCommand.cs index d7cd40ec..44adc4c9 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/ClearCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/ClearCommand.cs @@ -15,7 +15,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World ** Fields *********/ /// The valid types that can be cleared. - private readonly string[] ValidTypes = { "crops", "debris", "fruit-trees", "furniture", "grass", "trees", "removeable", "everything" }; + private readonly string[] ValidTypes = { "crops", "debris", "fruit-trees", "furniture", "grass", "trees", "removable", "everything" }; /// The resource clump IDs to consider debris. private readonly int[] DebrisClumps = { ResourceClump.stumpIndex, ResourceClump.hollowLogIndex, ResourceClump.meteoriteIndex, ResourceClump.boulderIndex }; @@ -31,7 +31,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World description: "Clears in-game entities in a given location.\n\n" + "Usage: world_clear \n" + " - location: the location name for which to clear objects (like Farm), or 'current' for the current location.\n" - + " - object type: the type of object clear. You can specify 'crops', 'debris' (stones/twigs/weeds and dead crops), 'furniture', 'grass', and 'trees' / 'fruit-trees'. You can also specify 'removeable', which includes everything that can be removed or destroyed during normal game play, or 'everything', which includes permanent bushes." + + " - object type: the type of object clear. You can specify 'crops', 'debris' (stones/twigs/weeds and dead crops), 'furniture', 'grass', and 'trees' / 'fruit-trees'. You can also specify 'removable' (remove everything that can be removed or destroyed during normal gameplay) or 'everything' (remove everything including permanent bushes)." ) { } @@ -133,25 +133,15 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World break; } - case "removeable": - { - int removed = - this.RemoveFurniture(location, p => true) - + this.RemoveObjects(location, p => true) - + this.RemoveTerrainFeatures(location, p => true) - + this.RemoveLargeTerrainFeatures(location, p => !(p is Bush) || ((Bush)p).isDestroyable(location, p.currentTileLocation)) - + this.RemoveResourceClumps(location, p => true); - monitor.Log($"Done! Removed {removed} entities from {location.Name}.", LogLevel.Info); - break; - } - + case "removable": case "everything": { + bool everything = type == "everything"; int removed = this.RemoveFurniture(location, p => true) + this.RemoveObjects(location, p => true) + this.RemoveTerrainFeatures(location, p => true) - + this.RemoveLargeTerrainFeatures(location, p => true) + + this.RemoveLargeTerrainFeatures(location, p => everything || p is not Bush bush || bush.isDestroyable(location, p.currentTileLocation)) + this.RemoveResourceClumps(location, p => true); monitor.Log($"Done! Removed {removed} entities from {location.Name}.", LogLevel.Info); break; diff --git a/src/SMAPI.sln.DotSettings b/src/SMAPI.sln.DotSettings index 29d4ade5..305b1c7d 100644 --- a/src/SMAPI.sln.DotSettings +++ b/src/SMAPI.sln.DotSettings @@ -36,6 +36,7 @@ True True True + True True True True -- cgit From 6a6c484b9867524d2eaa617da4dde36fec8c3110 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 28 Jul 2021 00:49:54 -0400 Subject: add accessed key to dictionary KeyNotFoundException message --- docs/release-notes.md | 1 + src/SMAPI.Mods.ErrorHandler/ModEntry.cs | 1 + .../Patches/DictionaryPatches.cs | 81 ++++++++++++++++++++++ .../SMAPI.Mods.ErrorHandler.csproj | 1 + 4 files changed, 84 insertions(+) create mode 100644 src/SMAPI.Mods.ErrorHandler/Patches/DictionaryPatches.cs (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index fab3f25c..782d64bb 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -10,6 +10,7 @@ * For mod authors: * Updated Harmony 1.2.0.1 to 2.1.0 (see [_migrate to Harmony 2.0_](https://stardewvalleywiki.com/Modding:Migrate_to_Harmony_2.0) for more info). + * SMAPI now intercepts `KeyNotFoundException` dictionary errors and adds the key to the error message to simplify troubleshooting. (Due to Harmony limitations, this only works for the dictionary types used by the game.) * Fixed error loading `.xnb` files from the local mod folder since SMAPI 3.0. ## 3.11.0 diff --git a/src/SMAPI.Mods.ErrorHandler/ModEntry.cs b/src/SMAPI.Mods.ErrorHandler/ModEntry.cs index d9426d75..719eddab 100644 --- a/src/SMAPI.Mods.ErrorHandler/ModEntry.cs +++ b/src/SMAPI.Mods.ErrorHandler/ModEntry.cs @@ -31,6 +31,7 @@ namespace StardewModdingAPI.Mods.ErrorHandler // apply patches new GamePatcher(this.Monitor).Apply( new DialogueErrorPatch(monitorForGame, this.Helper.Reflection), + new DictionaryPatches(this.Helper.Reflection), new EventPatches(monitorForGame), new GameLocationPatches(monitorForGame), new ObjectErrorPatch(), diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/DictionaryPatches.cs b/src/SMAPI.Mods.ErrorHandler/Patches/DictionaryPatches.cs new file mode 100644 index 00000000..ce88999d --- /dev/null +++ b/src/SMAPI.Mods.ErrorHandler/Patches/DictionaryPatches.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using HarmonyLib; +using StardewModdingAPI.Framework.Patching; +using StardewValley.GameData; +using StardewValley.GameData.HomeRenovations; +using StardewValley.GameData.Movies; + +namespace StardewModdingAPI.Mods.ErrorHandler.Patches +{ + /// A Harmony patch for which adds the accessed key to exceptions. + /// 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 DictionaryPatches : IHarmonyPatch + { + /********* + ** Fields + *********/ + /// Simplifies access to private code. + private static IReflectionHelper Reflection; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// Simplifies access to private code. + public DictionaryPatches(IReflectionHelper reflector) + { + DictionaryPatches.Reflection = reflector; + } + + /// + public void Apply(Harmony harmony) + { + Type[] keyTypes = { typeof(int), typeof(string) }; + Type[] valueTypes = { typeof(int), typeof(string), typeof(HomeRenovation), typeof(MovieData), typeof(SpecialOrderData) }; + + foreach (Type keyType in keyTypes) + { + foreach (Type valueType in valueTypes) + { + Type dictionaryType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType); + + harmony.Patch( + original: AccessTools.Method(dictionaryType, "get_Item"), + finalizer: new HarmonyMethod(this.GetType(), nameof(DictionaryPatches.Finalize_GetItem)) + ); + } + } + } + + + /********* + ** Private methods + *********/ + /// The method to call after the dictionary indexer throws an exception. + /// The dictionary key being fetched. + /// The exception thrown by the wrapped method, if any. + /// Returns the exception to throw, if any. + private static Exception Finalize_GetItem(object key, Exception __exception) + { + if (__exception is KeyNotFoundException) + AddKeyTo(__exception, key?.ToString()); + + return __exception; + } + + /// Add the accessed key to an exception message. + /// The exception to modify. + /// The dictionary key. + private static void AddKeyTo(Exception exception, string key) + { + DictionaryPatches.Reflection + .GetField(exception, "_message") + .SetValue($"{exception.Message}\nkey: '{key}'"); + } + } +} diff --git a/src/SMAPI.Mods.ErrorHandler/SMAPI.Mods.ErrorHandler.csproj b/src/SMAPI.Mods.ErrorHandler/SMAPI.Mods.ErrorHandler.csproj index 006a09ca..531d3699 100644 --- a/src/SMAPI.Mods.ErrorHandler/SMAPI.Mods.ErrorHandler.csproj +++ b/src/SMAPI.Mods.ErrorHandler/SMAPI.Mods.ErrorHandler.csproj @@ -15,6 +15,7 @@ + -- cgit From 880cd7b8bacfcee2cc6a8e15b6b8ea5e05e9467c Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 28 Jul 2021 21:20:44 -0400 Subject: fix handling of Unicode characters in console --- docs/release-notes.md | 1 + src/SMAPI/Framework/Logging/LogManager.cs | 5 +++++ 2 files changed, 6 insertions(+) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index 782d64bb..0f144bf5 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -6,6 +6,7 @@ * Added error if the wrong SMAPI bitness is installed (e.g. 32-bit SMAPI with 64-bit game). * Added error if some SMAPI files aren't updated correctly. * Added `removable` option to the `world_clear` console command (thanks to bladeoflight16!). + * Fixed handling of Unicode characters in console commands. * Fixed intermittent error if a mod fetches mod-provided APIs asynchronously. * For mod authors: diff --git a/src/SMAPI/Framework/Logging/LogManager.cs b/src/SMAPI/Framework/Logging/LogManager.cs index 2cd512e0..e16b5c0d 100644 --- a/src/SMAPI/Framework/Logging/LogManager.cs +++ b/src/SMAPI/Framework/Logging/LogManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; +using System.Text; using System.Text.RegularExpressions; using System.Threading; using StardewModdingAPI.Framework.Commands; @@ -106,6 +107,10 @@ namespace StardewModdingAPI.Framework.Logging if (writeToConsole) output.OnMessageIntercepted += message => this.HandleConsoleMessage(this.MonitorForGame, message); Console.SetOut(output); + + // enable Unicode handling + Console.InputEncoding = Encoding.Unicode; + Console.OutputEncoding = Encoding.Unicode; } /// Get a monitor instance derived from SMAPI's current settings. -- cgit From dc78d944e8663c02f305bbadff1c13e8c63eb42f Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 30 Jul 2021 01:48:22 -0400 Subject: recover save when mods leave null objects in the world --- docs/release-notes.md | 1 + src/SMAPI.Mods.ErrorHandler/Patches/SaveGamePatcher.cs | 13 +++++++++++++ 2 files changed, 14 insertions(+) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index 0f144bf5..44807dcb 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -3,6 +3,7 @@ # Release notes ## Upcoming release * For players: + * Added automatic save recovery when custom content mods leave null objects in the save. * Added error if the wrong SMAPI bitness is installed (e.g. 32-bit SMAPI with 64-bit game). * Added error if some SMAPI files aren't updated correctly. * Added `removable` option to the `world_clear` console command (thanks to bladeoflight16!). diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/SaveGamePatcher.cs b/src/SMAPI.Mods.ErrorHandler/Patches/SaveGamePatcher.cs index 635a01c1..2a43cb10 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/SaveGamePatcher.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/SaveGamePatcher.cs @@ -8,6 +8,7 @@ using StardewModdingAPI.Internal.Patching; using StardewValley; using StardewValley.Buildings; using StardewValley.Locations; +using SObject = StardewValley.Object; namespace StardewModdingAPI.Mods.ErrorHandler.Patches { @@ -126,6 +127,18 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches } } + // check objects + foreach (var pair in location.objects.Pairs.ToArray()) + { + // SpaceCore can leave null values when removing its custom content + if (pair.Value == null) + { + location.Objects.Remove(pair.Key); + SaveGamePatcher.Monitor.Log($"Removed invalid null object in {location.Name} ({pair.Key}) to avoid a crash when loading save '{Constants.SaveFolderName}'. (Did you remove a custom item mod?)", LogLevel.Warn); + removedAny = true; + } + } + return removedAny; } } -- cgit From 80d5672cdb04e8cba40b085b32ffcaf1fea78552 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 31 Jul 2021 01:50:31 -0400 Subject: fix crash when farm name contains invalid-in-file-path characters (#791) --- docs/release-notes.md | 1 + src/SMAPI/Constants.cs | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index 44807dcb..9e26a974 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -9,6 +9,7 @@ * Added `removable` option to the `world_clear` console command (thanks to bladeoflight16!). * Fixed handling of Unicode characters in console commands. * Fixed intermittent error if a mod fetches mod-provided APIs asynchronously. + * Fixed crash when creating a farm name containing characters that aren't allowed in a folder path. * For mod authors: * Updated Harmony 1.2.0.1 to 2.1.0 (see [_migrate to Harmony 2.0_](https://stardewvalleywiki.com/Modding:Migrate_to_Harmony_2.0) for more info). diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index 9e93551c..6fb796de 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -351,9 +351,16 @@ namespace StardewModdingAPI DirectoryInfo folder = null; foreach (string saveName in new[] { rawSaveName, new string(rawSaveName.Where(char.IsLetterOrDigit).ToArray()) }) { - folder = new DirectoryInfo(Path.Combine(Constants.SavesPath, $"{saveName}_{saveID}")); - if (folder.Exists) - return folder; + 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 -- cgit From c15d43049a08e73090d77cc150ac48476011a68c Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 31 Jul 2021 19:22:14 -0400 Subject: fix map reload not correctly reloading interior doors --- docs/release-notes.md | 1 + src/SMAPI.sln.DotSettings | 1 + src/SMAPI/Metadata/CoreAssetPropagator.cs | 16 ++++++++-------- 3 files changed, 10 insertions(+), 8 deletions(-) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index 9e26a974..4f874e38 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -15,6 +15,7 @@ * Updated Harmony 1.2.0.1 to 2.1.0 (see [_migrate to Harmony 2.0_](https://stardewvalleywiki.com/Modding:Migrate_to_Harmony_2.0) for more info). * SMAPI now intercepts `KeyNotFoundException` dictionary errors and adds the key to the error message to simplify troubleshooting. (Due to Harmony limitations, this only works for the dictionary types used by the game.) * Fixed error loading `.xnb` files from the local mod folder since SMAPI 3.0. + * Fixed reloading a map not correctly reapplying interior doors. ## 3.11.0 Released 09 July 2021 for Stardew Valley 1.5.4 or later. See [release highlights](https://www.patreon.com/posts/53514295). diff --git a/src/SMAPI.sln.DotSettings b/src/SMAPI.sln.DotSettings index 305b1c7d..9a6cad37 100644 --- a/src/SMAPI.sln.DotSettings +++ b/src/SMAPI.sln.DotSettings @@ -49,6 +49,7 @@ True True True + True True True True diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 9273864e..a8686ca4 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -5,7 +5,6 @@ using System.IO; using System.Linq; using Microsoft.Xna.Framework.Graphics; using Netcode; -using StardewModdingAPI.Framework; using StardewModdingAPI.Framework.ContentManagers; using StardewModdingAPI.Framework.Reflection; using StardewModdingAPI.Internal; @@ -939,16 +938,17 @@ namespace StardewModdingAPI.Metadata // reload map location.interiorDoors.Clear(); // prevent errors when doors try to update tiles which no longer exist location.reloadMap(); - location.updateWarps(); - location.MakeMapModifications(force: true); - // update interior doors + // reload interior doors location.interiorDoors.Clear(); - foreach (var entry in new InteriorDoorDictionary(location)) - location.interiorDoors.Add(entry); + location.interiorDoors.ResetSharedState(); // load doors from map properties + location.interiorDoors.ResetLocalState(); // reapply door tiles - // update doors - location.doors.Clear(); + // reapply map changes (after reloading doors so they apply theirs too) + location.MakeMapModifications(force: true); + + // update for changes + location.updateWarps(); location.updateDoors(); } -- cgit From d688cdf8c3c852d4b11cdd046d67c4b35443cc95 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 1 Aug 2021 13:11:27 -0400 Subject: prepare for release --- build/common.targets | 2 +- docs/release-notes.md | 16 +++++++++------- 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, 17 insertions(+), 15 deletions(-) (limited to 'docs') diff --git a/build/common.targets b/build/common.targets index aed619da..d526a2bb 100644 --- a/build/common.targets +++ b/build/common.targets @@ -1,7 +1,7 @@ - 3.11.0 + 3.12.0 SMAPI latest $(AssemblySearchPaths);{GAC} diff --git a/docs/release-notes.md b/docs/release-notes.md index 4f874e38..36f07129 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,20 +1,22 @@ ← [README](README.md) # Release notes -## Upcoming release +## 3.12.0 +01 August 2021 for Stardew Valley 1.5.4 or later. See [release highlights](https://www.patreon.com/posts/54388616). + * For players: - * Added automatic save recovery when custom content mods leave null objects in the save. + * Added save recovery when content mods leave null objects in the save (in _Error Handler_). * Added error if the wrong SMAPI bitness is installed (e.g. 32-bit SMAPI with 64-bit game). * Added error if some SMAPI files aren't updated correctly. - * Added `removable` option to the `world_clear` console command (thanks to bladeoflight16!). + * Added `removable` option to the `world_clear` console command (in _Console Commands_, thanks to bladeoflight16!). * Fixed handling of Unicode characters in console commands. - * Fixed intermittent error if a mod fetches mod-provided APIs asynchronously. + * Fixed intermittent error if a mod gets mod-provided APIs asynchronously. * Fixed crash when creating a farm name containing characters that aren't allowed in a folder path. * For mod authors: - * Updated Harmony 1.2.0.1 to 2.1.0 (see [_migrate to Harmony 2.0_](https://stardewvalleywiki.com/Modding:Migrate_to_Harmony_2.0) for more info). - * SMAPI now intercepts `KeyNotFoundException` dictionary errors and adds the key to the error message to simplify troubleshooting. (Due to Harmony limitations, this only works for the dictionary types used by the game.) - * Fixed error loading `.xnb` files from the local mod folder since SMAPI 3.0. + * **Updated Harmony 1.2.0.1 to 2.1.0 (see [_migrate to Harmony 2.0_](https://stardewvalleywiki.com/Modding:Migrate_to_Harmony_2.0) for more info).** + * SMAPI now intercepts `KeyNotFoundException` errors and adds the key to the error message to simplify troubleshooting. (Due to Harmony limitations, this only works for the dictionary types used by the game.) + * Fixed error loading `.xnb` files from the local mod folder. * Fixed reloading a map not correctly reapplying interior doors. ## 3.11.0 diff --git a/src/SMAPI.Mods.ConsoleCommands/manifest.json b/src/SMAPI.Mods.ConsoleCommands/manifest.json index 1781c40d..09684f32 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.11.0", + "Version": "3.12.0", "Description": "Adds SMAPI console commands that let you manipulate the game.", "UniqueID": "SMAPI.ConsoleCommands", "EntryDll": "ConsoleCommands.dll", - "MinimumApiVersion": "3.11.0" + "MinimumApiVersion": "3.12.0" } diff --git a/src/SMAPI.Mods.ErrorHandler/manifest.json b/src/SMAPI.Mods.ErrorHandler/manifest.json index 82e6152d..c83ca3d0 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.11.0", + "Version": "3.12.0", "Description": "Handles some common vanilla errors to log more useful info or avoid breaking the game.", "UniqueID": "SMAPI.ErrorHandler", "EntryDll": "ErrorHandler.dll", - "MinimumApiVersion": "3.11.0" + "MinimumApiVersion": "3.12.0" } diff --git a/src/SMAPI.Mods.SaveBackup/manifest.json b/src/SMAPI.Mods.SaveBackup/manifest.json index 6042dee4..42f1af59 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.11.0", + "Version": "3.12.0", "Description": "Automatically backs up all your saves once per day into its folder.", "UniqueID": "SMAPI.SaveBackup", "EntryDll": "SaveBackup.dll", - "MinimumApiVersion": "3.11.0" + "MinimumApiVersion": "3.12.0" } diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index 6fb796de..3877e17a 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -61,7 +61,7 @@ namespace StardewModdingAPI internal static int? LogScreenId { get; set; } /// SMAPI's current raw semantic version. - internal static string RawApiVersion = "3.11.0"; + internal static string RawApiVersion = "3.12.0"; } /// Contains SMAPI's constants and assumptions. -- cgit