diff options
| author | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2021-08-25 21:54:00 -0400 |
|---|---|---|
| committer | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2021-08-25 21:54:00 -0400 |
| commit | 211f89821e34bb55a6266384d9bac68ec0c64744 (patch) | |
| tree | aa0d9915b01aad436ed6b1a2028602c048666457 | |
| parent | 80d3dd1f786f7e5846f9adb7f7a4d82e5b9b92fd (diff) | |
| parent | 31ac964a8b19623b0472931403a33d51db6fb271 (diff) | |
| download | SMAPI-211f89821e34bb55a6266384d9bac68ec0c64744.tar.gz SMAPI-211f89821e34bb55a6266384d9bac68ec0c64744.tar.bz2 SMAPI-211f89821e34bb55a6266384d9bac68ec0c64744.zip | |
Merge branch 'develop' into stable
30 files changed, 484 insertions, 108 deletions
diff --git a/build/common.targets b/build/common.targets index 498ec7af..06e0a245 100644 --- a/build/common.targets +++ b/build/common.targets @@ -1,7 +1,7 @@ <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <!--set general build properties --> - <Version>3.12.2</Version> + <Version>3.12.3</Version> <Product>SMAPI</Product> <LangVersion>latest</LangVersion> <AssemblySearchPaths>$(AssemblySearchPaths);{GAC}</AssemblySearchPaths> diff --git a/docs/release-notes.md b/docs/release-notes.md index 4e9dacbf..07eb6c03 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,8 +1,27 @@ ← [README](README.md) # Release notes +## 3.12.3 +Released 25 August 2021 for Stardew Valley 1.5.4 or later. + +* For players: + * Added friendly error in 64-bit mode when a mod is 32-bit only. + * Fixed console encoding issues on Linux/macOS. + * Fixed some installer errors not showing info header. + +* For mod authors: + * Added `helper.Translation.GetInAllLocales` to get a translation in every available locale. + * Fixed Visual Studio debugger crash when any mods are rewritten for compatibility (thanks to spacechase0!). + * Fixed `helper.Data.WriteJsonFile` not deleting the file if the model is null, unlike the other `Write*` methods. + * Fixed error-handling for `StackOverflowException` thrown on Linux/macOS. + * Internal changes to prepare for Stardew Valley 1.5.5. + +* For the web API: + * Fixed update checks not shown for prerelease mod versions when you have a SMAPI beta. + * Fixed update checks shown for prerelease mod versions if you have a working non-prerelease version. + ## 3.12.2 -Released 04 August 2021 for Stardew Valley 1.5.4 or later. +Released 05 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. diff --git a/docs/technical/mod-package.md b/docs/technical/mod-package.md index 91da971b..7eefc7a4 100644 --- a/docs/technical/mod-package.md +++ b/docs/technical/mod-package.md @@ -365,7 +365,10 @@ The NuGet package is generated automatically in `StardewModdingAPI.ModBuildConfi when you compile it. ## Release notes -## 3.3 +## Upcoming release +* Improved analyzer performance by enabling parallel execution. + +## 3.3.0 Released 30 March 2021. * Added a build warning when the mod isn't compiled for `Any CPU`. @@ -385,19 +388,19 @@ Released 11 September 2020. * Added more detailed logging. * Fixed _path's format is not supported_ error when using default `Mods` path in 3.2. -### 3.2 +### 3.2.0 Released 07 September 2020. * Added option to change `Mods` folder path. * Rewrote documentation to make it easier to read. -### 3.1 +### 3.1.0 Released 01 February 2020. * Added support for semantic versioning 2.0. * `0Harmony.dll` is now ignored if the mod references Harmony directly (it's bundled with SMAPI). -### 3.0 +### 3.0.0 Released 26 November 2019. * Updated for SMAPI 3.0 and Stardew Valley 1.4. @@ -412,14 +415,14 @@ Released 26 November 2019. * Dropped support for older versions of SMAPI and Visual Studio. * Migrated package icon to NuGet's new format. -### 2.2 +### 2.2.0 Released 28 October 2018. * Added support for SMAPI 2.8+ (still compatible with earlier versions). * Added default game paths for 32-bit Windows. * Fixed valid manifests marked invalid in some cases. -### 2.1 +### 2.1.0 Released 27 July 2018. * Added support for Stardew Valley 1.3. @@ -439,7 +442,7 @@ Released 11 October 2017. * Fixed mod deploy failing to create subfolders if they don't already exist. -### 2.0 +### 2.0.0 Released 11 October 2017. * Added: mods are now copied into the `Mods` folder automatically (configurable). @@ -457,7 +460,7 @@ Released 28 July 2017. * The manifest/i18n files in the project now take precedence over those in the build output if both are present. -### 1.7 +### 1.7.0 Released 28 July 2017. * Added option to create release zips on build. @@ -474,19 +477,19 @@ Released 09 July 2017. * Improved crossplatform game path detection. -### 1.6 +### 1.6.0 Released 05 June 2017. * Added support for deploying mod files into `Mods` automatically. * Added a build error if a game folder is found, but doesn't contain Stardew Valley or SMAPI. -### 1.5 +### 1.5.0 Released 23 January 2017. * Added support for setting a custom game path globally. * Added default GOG path on macOS. -### 1.4 +### 1.4.0 Released 11 January 2017. * Fixed detection of non-default game paths on 32-bit Windows. @@ -494,22 +497,22 @@ Released 11 January 2017. * Removed support for overriding the target platform (no longer needed since SMAPI crossplatforms mods automatically). -### 1.3 +### 1.3.0 Released 31 December 2016. * Added support for non-default game paths on Windows. -### 1.2 +### 1.2.0 Released 24 October 2016. * Exclude game binaries from mod build output. -### 1.1 +### 1.1.0 Released 21 October 2016. * Added support for overriding the target platform. -### 1.0 +### 1.0.0 Released 21 October 2016. * Initial release. diff --git a/src/SMAPI.Installer/InteractiveInstaller.cs b/src/SMAPI.Installer/InteractiveInstaller.cs index ab07c864..b91d0dd3 100644 --- a/src/SMAPI.Installer/InteractiveInstaller.cs +++ b/src/SMAPI.Installer/InteractiveInstaller.cs @@ -272,7 +272,6 @@ namespace StardewModdingApi.Installer DirectoryInfo bundleDir = new DirectoryInfo(this.BundlePath); paths = new InstallerPaths(bundleDir, installDir, context.ExecutableName); } - Console.Clear(); /********* @@ -309,6 +308,7 @@ namespace StardewModdingApi.Installer return; } } + Console.Clear(); /********* diff --git a/src/SMAPI.Internal/ExceptionExtensions.cs b/src/SMAPI.Internal/ExceptionExtensions.cs index 5f1ee1fa..d8189048 100644 --- a/src/SMAPI.Internal/ExceptionExtensions.cs +++ b/src/SMAPI.Internal/ExceptionExtensions.cs @@ -13,19 +13,26 @@ namespace StardewModdingAPI.Internal /// <param name="exception">The error to summarize.</param> public static string GetLogSummary(this Exception exception) { - switch (exception) + try { - case TypeLoadException ex: - return $"Failed loading type '{ex.TypeName}': {exception}"; + switch (exception) + { + case TypeLoadException ex: + return $"Failed loading type '{ex.TypeName}': {exception}"; - case ReflectionTypeLoadException ex: - string summary = ex.ToString(); - foreach (Exception childEx in ex.LoaderExceptions ?? new Exception[0]) - summary += $"\n\n{childEx?.GetLogSummary()}"; - return summary; + case ReflectionTypeLoadException ex: + string summary = ex.ToString(); + foreach (Exception childEx in ex.LoaderExceptions ?? new Exception[0]) + summary += $"\n\n{childEx?.GetLogSummary()}"; + return summary; - default: - return exception.ToString(); + default: + return exception?.ToString() ?? $"<null exception>\n{Environment.StackTrace}"; + } + } + catch (Exception ex) + { + throw new InvalidOperationException($"Failed handling {exception?.GetType().FullName} (original message: {exception?.Message})", ex); } } diff --git a/src/SMAPI.ModBuildConfig.Analyzer/NetFieldAnalyzer.cs b/src/SMAPI.ModBuildConfig.Analyzer/NetFieldAnalyzer.cs index a9b981bd..1efc1616 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer/NetFieldAnalyzer.cs +++ b/src/SMAPI.ModBuildConfig.Analyzer/NetFieldAnalyzer.cs @@ -174,6 +174,9 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer /// <param name="context">The analysis context.</param> public override void Initialize(AnalysisContext context) { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); + context.EnableConcurrentExecution(); + context.RegisterSyntaxNodeAction( this.AnalyzeMemberAccess, SyntaxKind.SimpleMemberAccessExpression, diff --git a/src/SMAPI.ModBuildConfig.Analyzer/ObsoleteFieldAnalyzer.cs b/src/SMAPI.ModBuildConfig.Analyzer/ObsoleteFieldAnalyzer.cs index d071f0c1..722d5227 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer/ObsoleteFieldAnalyzer.cs +++ b/src/SMAPI.ModBuildConfig.Analyzer/ObsoleteFieldAnalyzer.cs @@ -56,6 +56,9 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer /// <param name="context">The analysis context.</param> public override void Initialize(AnalysisContext context) { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); + context.EnableConcurrentExecution(); + context.RegisterSyntaxNodeAction( this.AnalyzeObsoleteFields, SyntaxKind.SimpleMemberAccessExpression, diff --git a/src/SMAPI.Mods.ConsoleCommands/manifest.json b/src/SMAPI.Mods.ConsoleCommands/manifest.json index 6b49cd5f..e04d3497 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.2", + "Version": "3.12.3", "Description": "Adds SMAPI console commands that let you manipulate the game.", "UniqueID": "SMAPI.ConsoleCommands", "EntryDll": "ConsoleCommands.dll", - "MinimumApiVersion": "3.12.2" + "MinimumApiVersion": "3.12.3" } diff --git a/src/SMAPI.Mods.ErrorHandler/manifest.json b/src/SMAPI.Mods.ErrorHandler/manifest.json index 7759d1d5..54758a36 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.2", + "Version": "3.12.3", "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.2" + "MinimumApiVersion": "3.12.3" } diff --git a/src/SMAPI.Mods.SaveBackup/manifest.json b/src/SMAPI.Mods.SaveBackup/manifest.json index 1e5b8b97..f23f0958 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.2", + "Version": "3.12.3", "Description": "Automatically backs up all your saves once per day into its folder.", "UniqueID": "SMAPI.SaveBackup", "EntryDll": "SaveBackup.dll", - "MinimumApiVersion": "3.12.2" + "MinimumApiVersion": "3.12.3" } diff --git a/src/SMAPI.Toolkit/Framework/LowLevelEnvironmentUtility.cs b/src/SMAPI.Toolkit/Framework/LowLevelEnvironmentUtility.cs index be0c18ce..2636aae0 100644 --- a/src/SMAPI.Toolkit/Framework/LowLevelEnvironmentUtility.cs +++ b/src/SMAPI.Toolkit/Framework/LowLevelEnvironmentUtility.cs @@ -90,10 +90,10 @@ namespace StardewModdingAPI.Toolkit.Framework } /// <summary>Get whether an executable is 64-bit.</summary> - /// <param name="executablePath">The absolute path to the executable file.</param> - public static bool Is64BitAssembly(string executablePath) + /// <param name="path">The absolute path to the assembly file.</param> + public static bool Is64BitAssembly(string path) { - return AssemblyName.GetAssemblyName(executablePath).ProcessorArchitecture != ProcessorArchitecture.X86; + return AssemblyName.GetAssemblyName(path).ProcessorArchitecture != ProcessorArchitecture.X86; } diff --git a/src/SMAPI.Toolkit/SemanticVersionComparer.cs b/src/SMAPI.Toolkit/SemanticVersionComparer.cs new file mode 100644 index 00000000..9f6b57a2 --- /dev/null +++ b/src/SMAPI.Toolkit/SemanticVersionComparer.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; + +namespace StardewModdingAPI.Toolkit +{ + /// <summary>A comparer for semantic versions based on the <see cref="SemanticVersion.CompareTo(ISemanticVersion)"/> field.</summary> + public class SemanticVersionComparer : IComparer<ISemanticVersion> + { + /********* + ** Accessors + *********/ + /// <summary>A singleton instance of the comparer.</summary> + public static SemanticVersionComparer Instance { get; } = new SemanticVersionComparer(); + + + /********* + ** Public methods + *********/ + /// <inheritdoc /> + public int Compare(ISemanticVersion x, ISemanticVersion y) + { + if (object.ReferenceEquals(x, y)) + return 0; + + if (x is null) + return -1; + if (y is null) + return 1; + + return x.CompareTo(y); + } + } +} diff --git a/src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs b/src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs index 62bd13cd..6de79a85 100644 --- a/src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs +++ b/src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs @@ -46,5 +46,12 @@ namespace StardewModdingAPI.Toolkit.Utilities { return LowLevelEnvironmentUtility.GetExecutableName(platform.ToString()); } + + /// <summary>Get whether an executable is 64-bit.</summary> + /// <param name="path">The absolute path to the assembly file.</param> + public static bool Is64BitAssembly(string path) + { + return LowLevelEnvironmentUtility.Is64BitAssembly(path); + } } } diff --git a/src/SMAPI.Web/Controllers/ModsApiController.cs b/src/SMAPI.Web/Controllers/ModsApiController.cs index 1956bf29..c6e9a713 100644 --- a/src/SMAPI.Web/Controllers/ModsApiController.cs +++ b/src/SMAPI.Web/Controllers/ModsApiController.cs @@ -123,6 +123,10 @@ namespace StardewModdingAPI.Web.Controllers ModOverrideConfig overrides = this.Config.Value.ModOverrides.FirstOrDefault(p => p.ID.Equals(search.ID?.Trim(), StringComparison.OrdinalIgnoreCase)); bool allowNonStandardVersions = overrides?.AllowNonStandardVersions ?? false; + // SMAPI versions with a '-beta' tag indicate major changes that may need beta mod versions. + // This doesn't apply to normal prerelease versions which have an '-alpha' tag. + bool isSmapiBeta = apiVersion.IsPrerelease() && apiVersion.PrereleaseTag.StartsWith("beta"); + // get latest versions ModEntryModel result = new ModEntryModel { ID = search.ID }; IList<string> errors = new List<string>(); @@ -198,7 +202,7 @@ namespace StardewModdingAPI.Web.Controllers List<ModEntryVersionModel> updates = new List<ModEntryVersionModel>(); if (this.IsRecommendedUpdate(installedVersion, main?.Version, useBetaChannel: true)) updates.Add(main); - if (this.IsRecommendedUpdate(installedVersion, optional?.Version, useBetaChannel: installedVersion.IsPrerelease() || search.IsBroken)) + if (this.IsRecommendedUpdate(installedVersion, optional?.Version, useBetaChannel: isSmapiBeta || installedVersion.IsPrerelease() || search.IsBroken)) updates.Add(optional); if (this.IsRecommendedUpdate(installedVersion, unofficial?.Version, useBetaChannel: true)) updates.Add(unofficial); diff --git a/src/SMAPI.Web/Framework/ModSiteManager.cs b/src/SMAPI.Web/Framework/ModSiteManager.cs index 68b4c6ac..8f21d2f5 100644 --- a/src/SMAPI.Web/Framework/ModSiteManager.cs +++ b/src/SMAPI.Web/Framework/ModSiteManager.cs @@ -110,41 +110,70 @@ namespace StardewModdingAPI.Web.Framework main = null; preview = null; - ISemanticVersion ParseVersion(string raw) + // parse all versions from the mod page + IEnumerable<(string name, string description, ISemanticVersion version)> GetAllVersions() { - raw = this.NormalizeVersion(raw); - return this.GetMappedVersion(raw, mapRemoteVersions, allowNonStandardVersions); + if (mod != null) + { + ISemanticVersion ParseAndMapVersion(string raw) + { + raw = this.NormalizeVersion(raw); + return this.GetMappedVersion(raw, mapRemoteVersions, allowNonStandardVersions); + } + + // get mod version + ISemanticVersion modVersion = ParseAndMapVersion(mod.Version); + if (modVersion != null) + yield return (name: null, description: null, version: ParseAndMapVersion(mod.Version)); + + // get file versions + foreach (IModDownload download in mod.Downloads) + { + ISemanticVersion cur = ParseAndMapVersion(download.Version); + if (cur != null) + yield return (download.Name, download.Description, cur); + } + } } + var versions = GetAllVersions() + .OrderByDescending(p => p.version, SemanticVersionComparer.Instance) + .ToArray(); - if (mod != null) + // get main + preview versions + void TryGetVersions(out ISemanticVersion mainVersion, out ISemanticVersion previewVersion, Func<(string name, string description, ISemanticVersion version), bool> filter = null) { - // get mod version - if (subkey == null) - main = ParseVersion(mod.Version); + mainVersion = null; + previewVersion = null; - // get file versions - foreach (IModDownload download in mod.Downloads) + // get latest main + preview version + foreach (var entry in versions) { - // check for subkey if specified - if (subkey != null && download.Name?.Contains(subkey, StringComparison.OrdinalIgnoreCase) != true && download.Description?.Contains(subkey, StringComparison.OrdinalIgnoreCase) != true) + if (filter?.Invoke(entry) == false) continue; - // parse version - ISemanticVersion cur = ParseVersion(download.Version); - if (cur == null) - continue; + if (entry.version.IsPrerelease()) + previewVersion ??= entry.version; + else + mainVersion ??= entry.version; - // track highest versions - if (main == null || cur.IsNewerThan(main)) - main = cur; - if (cur.IsPrerelease() && (preview == null || cur.IsNewerThan(preview))) - preview = cur; + if (mainVersion != null) + break; // any other values will be older } - if (preview != null && !preview.IsNewerThan(main)) - preview = null; + // normalize values + if (previewVersion is not null) + { + mainVersion ??= previewVersion; // if every version is prerelease, latest one is the main version + if (!previewVersion.IsNewerThan(mainVersion)) + previewVersion = null; + } } + if (subkey is not null) + TryGetVersions(out main, out preview, entry => entry.name?.Contains(subkey, StringComparison.OrdinalIgnoreCase) == true || entry.description?.Contains(subkey, StringComparison.OrdinalIgnoreCase) == true); + if (main is null) + TryGetVersions(out main, out preview); + return main != null; } diff --git a/src/SMAPI.Web/SMAPI.Web.csproj b/src/SMAPI.Web/SMAPI.Web.csproj index e9d209ec..4c8465a6 100644 --- a/src/SMAPI.Web/SMAPI.Web.csproj +++ b/src/SMAPI.Web/SMAPI.Web.csproj @@ -2,7 +2,7 @@ <PropertyGroup> <AssemblyName>SMAPI.Web</AssemblyName> <RootNamespace>StardewModdingAPI.Web</RootNamespace> - <TargetFramework>netcoreapp3.1</TargetFramework> + <TargetFramework>net5.0</TargetFramework> <LangVersion>latest</LangVersion> </PropertyGroup> diff --git a/src/SMAPI.Web/Views/Mods/Index.cshtml b/src/SMAPI.Web/Views/Mods/Index.cshtml index fa77c220..7dcd0718 100644 --- a/src/SMAPI.Web/Views/Mods/Index.cshtml +++ b/src/SMAPI.Web/Views/Mods/Index.cshtml @@ -9,7 +9,7 @@ TimeSpan staleAge = DateTimeOffset.UtcNow - Model.LastUpdated; bool hasBeta = Model.BetaVersion != null; - string betaLabel = "SDV @Model.BetaVersion only"; + string betaLabel = $"SDV {Model.BetaVersion} only"; } @section Head { <link rel="stylesheet" href="~/Content/css/mods.css?r=20200218" /> diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index 6cbdeb8e..cce267ba 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; +using Mono.Cecil; using StardewModdingAPI.Enums; using StardewModdingAPI.Framework; using StardewModdingAPI.Framework.ModLoading; @@ -61,7 +62,7 @@ namespace StardewModdingAPI internal static int? LogScreenId { get; set; } /// <summary>SMAPI's current raw semantic version.</summary> - internal static string RawApiVersion = "3.12.2"; + internal static string RawApiVersion = "3.12.3"; } /// <summary>Contains SMAPI's constants and assumptions.</summary> @@ -229,6 +230,32 @@ namespace StardewModdingAPI } } + /// <summary>Configure the Mono.Cecil assembly resolver.</summary> + /// <param name="resolver">The assembly resolver.</param> + internal static void ConfigureAssemblyResolver(AssemblyDefinitionResolver resolver) + { + // add search paths + resolver.AddSearchDirectory(Constants.ExecutionPath); + resolver.AddSearchDirectory(Constants.InternalFilesPath); + + // add SMAPI explicitly + // Normally this would be handled automatically by the search paths, but for some reason there's a specific + // case involving unofficial 64-bit Stardew Valley when launched through Steam (for some players only) + // where Mono.Cecil can't resolve references to SMAPI. + resolver.Add(AssemblyDefinition.ReadAssembly(typeof(SGame).Assembly.Location)); + + // make sure game assembly names can be resolved + // The game assembly can have one of three names depending how the mod was compiled: + // - 'StardewValley': assembly name on Linux/macOS; + // - 'Stardew Valley': assembly name on Windows; + // - 'Netcode': an assembly that's separate on Windows only. + resolver.Add(AssemblyDefinition.ReadAssembly(typeof(Game1).Assembly.Location), "StardewValley", "Stardew Valley" +#if !SMAPI_FOR_WINDOWS + , "Netcode" +#endif + ); + } + /// <summary>Get metadata for mapping assemblies to the current platform.</summary> /// <param name="targetPlatform">The target game platform.</param> /// <param name="framework">The game framework running the game.</param> diff --git a/src/SMAPI/Framework/Logging/LogManager.cs b/src/SMAPI/Framework/Logging/LogManager.cs index a3d4f23d..c6faa90d 100644 --- a/src/SMAPI/Framework/Logging/LogManager.cs +++ b/src/SMAPI/Framework/Logging/LogManager.cs @@ -109,9 +109,12 @@ namespace StardewModdingAPI.Framework.Logging output.OnMessageIntercepted += message => this.HandleConsoleMessage(this.MonitorForGame, message); Console.SetOut(output); - // enable Unicode handling + // enable Unicode handling on Windows + // (the terminal defaults to UTF-8 on Linux/macOS) +#if SMAPI_FOR_WINDOWS Console.InputEncoding = Encoding.Unicode; Console.OutputEncoding = Encoding.Unicode; +#endif } /// <summary>Get a monitor instance derived from SMAPI's current settings.</summary> @@ -162,8 +165,6 @@ namespace StardewModdingAPI.Framework.Logging // keep console thread alive while the game is running while (continueWhile()) Thread.Sleep(1000 / 10); - if (inputThread.ThreadState == ThreadState.Running) - inputThread.Abort(); } /// <summary>Show a 'press any key to exit' message, and exit when they press a key.</summary> diff --git a/src/SMAPI/Framework/ModHelpers/DataHelper.cs b/src/SMAPI/Framework/ModHelpers/DataHelper.cs index 0fe3209f..4cbfd73f 100644 --- a/src/SMAPI/Framework/ModHelpers/DataHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/DataHelper.cs @@ -58,7 +58,11 @@ namespace StardewModdingAPI.Framework.ModHelpers throw new InvalidOperationException($"You must call {nameof(IMod.Helper)}.{nameof(IModHelper.Data)}.{nameof(this.WriteJsonFile)} with a relative path (without directory climbing)."); path = Path.Combine(this.ModFolderPath, PathUtilities.NormalizePath(path)); - this.JsonHelper.WriteJsonFile(path, data); + + if (data != null) + this.JsonHelper.WriteJsonFile(path, data); + else + File.Delete(path); } /**** diff --git a/src/SMAPI/Framework/ModHelpers/TranslationHelper.cs b/src/SMAPI/Framework/ModHelpers/TranslationHelper.cs index a88ca9c9..869664fe 100644 --- a/src/SMAPI/Framework/ModHelpers/TranslationHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/TranslationHelper.cs @@ -55,6 +55,12 @@ namespace StardewModdingAPI.Framework.ModHelpers return this.Translator.Get(key, tokens); } + /// <inheritdoc /> + public IDictionary<string, Translation> GetInAllLocales(string key, bool withFallback = false) + { + return this.Translator.GetInAllLocales(key, withFallback); + } + /// <summary>Set the translations to use.</summary> /// <param name="translations">The translations to use.</param> internal TranslationHelper SetTranslations(IDictionary<string, IDictionary<string, string>> translations) diff --git a/src/SMAPI/Framework/Mod |
