From 4e17716fa26161016e5e59f12b52feef3fd0f8f9 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 9 Dec 2021 19:56:46 -0500 Subject: fix log parser handling when multiple mods have the exact same name --- src/SMAPI.Web/Framework/LogParsing/LogParser.cs | 35 ++++++++++++++++--------- 1 file changed, 22 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/SMAPI.Web/Framework/LogParsing/LogParser.cs b/src/SMAPI.Web/Framework/LogParsing/LogParser.cs index 84013ccc..887d0105 100644 --- a/src/SMAPI.Web/Framework/LogParsing/LogParser.cs +++ b/src/SMAPI.Web/Framework/LogParsing/LogParser.cs @@ -79,7 +79,7 @@ namespace StardewModdingAPI.Web.Framework.LogParsing // parse log messages LogModInfo smapiMod = new LogModInfo { Name = "SMAPI", Author = "Pathoschild", Description = "", Loaded = true }; LogModInfo gameMod = new LogModInfo { Name = "game", Author = "", Description = "", Loaded = true }; - IDictionary mods = new Dictionary(); + IDictionary> mods = new Dictionary>(); bool inModList = false; bool inContentPackList = false; bool inModUpdateList = false; @@ -99,8 +99,11 @@ namespace StardewModdingAPI.Web.Framework.LogParsing break; default: - if (mods.ContainsKey(message.Mod)) - mods[message.Mod].Errors++; + if (mods.TryGetValue(message.Mod, out var entries)) + { + foreach (var entry in entries) + entry.Errors++; + } break; } } @@ -127,7 +130,10 @@ namespace StardewModdingAPI.Web.Framework.LogParsing string version = match.Groups["version"].Value; string author = match.Groups["author"].Value; string description = match.Groups["description"].Value; - mods[name] = new LogModInfo { Name = name, Author = author, Version = version, Description = description, Loaded = true }; + + if (!mods.TryGetValue(name, out List entries)) + mods[name] = entries = new List(); + entries.Add(new LogModInfo { Name = name, Author = author, Version = version, Description = description, Loaded = true }); message.Section = LogSection.ModsList; } @@ -147,7 +153,10 @@ namespace StardewModdingAPI.Web.Framework.LogParsing string author = match.Groups["author"].Value; string description = match.Groups["description"].Value; string forMod = match.Groups["for"].Value; - mods[name] = new LogModInfo { Name = name, Author = author, Version = version, Description = description, ContentPackFor = forMod, Loaded = true }; + + if (!mods.TryGetValue(name, out List entries)) + mods[name] = entries = new List(); + entries.Add(new LogModInfo { Name = name, Author = author, Version = version, Description = description, ContentPackFor = forMod, Loaded = true }); message.Section = LogSection.ContentPackList; } @@ -165,14 +174,14 @@ namespace StardewModdingAPI.Web.Framework.LogParsing string name = match.Groups["name"].Value; string version = match.Groups["version"].Value; string link = match.Groups["link"].Value; - if (mods.ContainsKey(name)) - { - mods[name].UpdateLink = link; - mods[name].UpdateVersion = version; - } - else + + if (mods.TryGetValue(name, out var entries)) { - mods[name] = new LogModInfo { Name = name, UpdateVersion = version, UpdateLink = link, Loaded = false }; + foreach (var entry in entries) + { + entry.UpdateLink = link; + entry.UpdateVersion = version; + } } message.Section = LogSection.ModUpdateList; @@ -219,7 +228,7 @@ namespace StardewModdingAPI.Web.Framework.LogParsing // finalize log gameMod.Version = log.GameVersion; - log.Mods = new[] { gameMod, smapiMod }.Concat(mods.Values.OrderBy(p => p.Name)).ToArray(); + log.Mods = new[] { gameMod, smapiMod }.Concat(mods.Values.SelectMany(p => p).OrderBy(p => p.Name)).ToArray(); return log; } catch (LogParseException ex) -- cgit From aa5d1d4a20c30c9f8fbd30a4d7e8e38e234f17ca Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 9 Dec 2021 19:57:57 -0500 Subject: update compatibility list --- docs/release-notes.md | 3 +++ src/SMAPI.Web/wwwroot/SMAPI.metadata.json | 7 +++++++ 2 files changed, 10 insertions(+) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index 421378e4..41c22085 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,9 @@ # Release notes ## Upcoming release +* For players: + * Updated compatibility list. + * For the web UI: * Fixed log parser not correctly handling multiple mods having the exact same name. diff --git a/src/SMAPI.Web/wwwroot/SMAPI.metadata.json b/src/SMAPI.Web/wwwroot/SMAPI.metadata.json index eb76b29a..75a3f8c7 100644 --- a/src/SMAPI.Web/wwwroot/SMAPI.metadata.json +++ b/src/SMAPI.Web/wwwroot/SMAPI.metadata.json @@ -481,6 +481,13 @@ "~1.2.2 | StatusReasonDetails": "references the deleted Content/Mine asset" }, + "Critical Crow": { + "ID": "leonary.CRCROWS", + "Default | UpdateKey": "Nexus:2663", + "~1.2.2 | Status": "AssumeBroken", + "~1.2.2 | StatusReasonDetails": "removes newer content from the TileSheets/Craftables asset" + }, + "Green Pastures Farm": { "ID": "bugbuddy.GreenPasturesFarm", "Default | UpdateKey": "Nexus:2326", -- cgit From e0abac8dfb52fb28d296d6df7483094570f68708 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 18 Dec 2021 00:48:55 -0500 Subject: update compatibility list --- src/SMAPI.Web/wwwroot/SMAPI.metadata.json | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/SMAPI.Web/wwwroot/SMAPI.metadata.json b/src/SMAPI.Web/wwwroot/SMAPI.metadata.json index 75a3f8c7..53c68636 100644 --- a/src/SMAPI.Web/wwwroot/SMAPI.metadata.json +++ b/src/SMAPI.Web/wwwroot/SMAPI.metadata.json @@ -283,6 +283,11 @@ /********* ** Broke in SDV 1.5 (Content Patcher packs) *********/ + "Empty Spouse Room": { + "ID": "Lerura.EmptySpouseRoom", + "~1.0.0 | Status": "AssumeBroken", + "~1.0.0 | StatusReasonDetails": "prevents loading married saves due to a missing tilesheet in the spouse room map" + }, "mi.Mermaids": { "ID": "mi.Mermaids", "~1.0.0 | Status": "AssumeBroken", -- cgit From beb1acd4f823d64d125f5749b2edad06e5731407 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 18 Dec 2021 22:21:31 -0500 Subject: update Steam error message --- docs/release-notes.md | 1 + src/SMAPI/Framework/Logging/LogManager.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index 41c22085..b54aeb15 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -3,6 +3,7 @@ # Release notes ## Upcoming release * For players: + * Fixed outdated instructions in Steam error message. * Updated compatibility list. * For the web UI: diff --git a/src/SMAPI/Framework/Logging/LogManager.cs b/src/SMAPI/Framework/Logging/LogManager.cs index 5a291d0a..ef89c751 100644 --- a/src/SMAPI/Framework/Logging/LogManager.cs +++ b/src/SMAPI/Framework/Logging/LogManager.cs @@ -49,7 +49,7 @@ namespace StardewModdingAPI.Framework.Logging search: new Regex(@"^System\.InvalidOperationException: Steamworks is not initialized\.[\s\S]+$", RegexOptions.Compiled | RegexOptions.CultureInvariant), replacement: #if SMAPI_FOR_WINDOWS - "Oops! Steam achievements won't work because Steam isn't loaded. See 'Launch SMAPI through Steam or GOG Galaxy' in the install guide for more info: https://smapi.io/install.", + "Oops! Steam achievements won't work because Steam isn't loaded. See 'Configure your game client' in the install guide for more info: https://smapi.io/install.", #else "Oops! Steam achievements won't work because Steam isn't loaded. You can launch the game through Steam to fix that.", #endif -- cgit From 95f658014ebd2aadce1bc72d1d7e763efd7782ba Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 18 Dec 2021 23:07:33 -0500 Subject: simplify running SMAPI without a terminal on Linux/macOS --- docs/release-notes.md | 1 + src/SMAPI.Installer/assets/unix-launcher.sh | 122 +++++++++++++++------------- 2 files changed, 67 insertions(+), 56 deletions(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index b54aeb15..e0c6977d 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -4,6 +4,7 @@ ## Upcoming release * For players: * Fixed outdated instructions in Steam error message. + * Simplified [running without a terminal on Linux/macOS](https://stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting#SMAPI_doesn.27t_recognize_controller_.28Steam_only.29) when needed. * Updated compatibility list. * For the web UI: diff --git a/src/SMAPI.Installer/assets/unix-launcher.sh b/src/SMAPI.Installer/assets/unix-launcher.sh index e8b9ae62..713597e2 100644 --- a/src/SMAPI.Installer/assets/unix-launcher.sh +++ b/src/SMAPI.Installer/assets/unix-launcher.sh @@ -6,6 +6,10 @@ # move to script's directory cd "$(dirname "$0")" || exit $? +# change to true to skip opening a terminal +# This isn't recommended since you won't see errors, warnings, and update alerts. +SKIP_TERMINAL=false + ########## ## Open terminal if needed @@ -16,7 +20,6 @@ cd "$(dirname "$0")" || exit $? if [ "$(uname)" == "Darwin" ]; then if [ ! -t 1 ]; then # https://stackoverflow.com/q/911168/262123 # sanity check to make sure we don't have an infinite loop of opening windows - SKIP_TERMINAL=false for argument in "$@"; do if [ "$argument" == "--no-reopen-terminal" ]; then SKIP_TERMINAL=true @@ -63,64 +66,71 @@ else LAUNCH_FILE="./StardewModdingAPI" export LAUNCH_FILE - # select terminal (prefer xterm for best compatibility, then known supported terminals) - for terminal in xterm gnome-terminal kitty terminator xfce4-terminal konsole terminal termite alacritty mate-terminal x-terminal-emulator; do - if command -v "$terminal" 2>/dev/null; then - export TERMINAL_NAME=$terminal - break; + # run in terminal + if [ "$SKIP_TERMINAL" == "false" ]; then + # select terminal (prefer xterm for best compatibility, then known supported terminals) + for terminal in xterm gnome-terminal kitty terminator xfce4-terminal konsole terminal termite alacritty mate-terminal x-terminal-emulator; do + if command -v "$terminal" 2>/dev/null; then + export TERMINAL_NAME=$terminal + break; + fi + done + + # find the true shell behind x-terminal-emulator + if [ "$TERMINAL_NAME" = "x-terminal-emulator" ]; then + export TERMINAL_NAME="$(basename "$(readlink -f $(command -v x-terminal-emulator))")" fi - done - # find the true shell behind x-terminal-emulator - if [ "$TERMINAL_NAME" = "x-terminal-emulator" ]; then - export TERMINAL_NAME="$(basename "$(readlink -f $(command -v x-terminal-emulator))")" - fi + # run in selected terminal and account for quirks + export TERMINAL_PATH="$(command -v $TERMINAL_NAME)" + if [ -x $TERMINAL_PATH ]; then + case $TERMINAL_NAME in + terminal|termite) + # consumes only one argument after -e + # options containing space characters are unsupported + exec $TERMINAL_NAME -e "env TERM=xterm $LAUNCH_FILE $@" + ;; + + xterm|konsole|alacritty) + # consumes all arguments after -e + exec $TERMINAL_NAME -e env TERM=xterm $LAUNCH_FILE "$@" + ;; + + terminator|xfce4-terminal|mate-terminal) + # consumes all arguments after -x + exec $TERMINAL_NAME -x env TERM=xterm $LAUNCH_FILE "$@" + ;; + + gnome-terminal) + # consumes all arguments after -- + exec $TERMINAL_NAME -- env TERM=xterm $LAUNCH_FILE "$@" + ;; + + kitty) + # consumes all trailing arguments + exec $TERMINAL_NAME env TERM=xterm $LAUNCH_FILE "$@" + ;; + + *) + # If we don't know the terminal, just try to run it in the current shell. + # If THAT fails, launch with no output. + env TERM=xterm $LAUNCH_FILE "$@" + if [ $? -eq 127 ]; then + exec $LAUNCH_FILE --no-terminal "$@" + fi + esac + + ## terminal isn't executable; fallback to current shell or no terminal + else + echo "The '$TERMINAL_NAME' terminal isn't executable. SMAPI might be running in a sandbox or the system might be misconfigured? Falling back to current shell." + env TERM=xterm $LAUNCH_FILE "$@" + if [ $? -eq 127 ]; then + exec $LAUNCH_FILE --no-terminal "$@" + fi + fi - # run in selected terminal and account for quirks - export TERMINAL_PATH="$(command -v $TERMINAL_NAME)" - if [ -x $TERMINAL_PATH ]; then - case $TERMINAL_NAME in - terminal|termite) - # consumes only one argument after -e - # options containing space characters are unsupported - exec $TERMINAL_NAME -e "env TERM=xterm $LAUNCH_FILE $@" - ;; - - xterm|konsole|alacritty) - # consumes all arguments after -e - exec $TERMINAL_NAME -e env TERM=xterm $LAUNCH_FILE "$@" - ;; - - terminator|xfce4-terminal|mate-terminal) - # consumes all arguments after -x - exec $TERMINAL_NAME -x env TERM=xterm $LAUNCH_FILE "$@" - ;; - - gnome-terminal) - # consumes all arguments after -- - exec $TERMINAL_NAME -- env TERM=xterm $LAUNCH_FILE "$@" - ;; - - kitty) - # consumes all trailing arguments - exec $TERMINAL_NAME env TERM=xterm $LAUNCH_FILE "$@" - ;; - - *) - # If we don't know the terminal, just try to run it in the current shell. - # If THAT fails, launch with no output. - env TERM=xterm $LAUNCH_FILE "$@" - if [ $? -eq 127 ]; then - exec $LAUNCH_FILE --no-terminal "$@" - fi - esac - - ## terminal isn't executable; fallback to current shell or no terminal + # explicitly run without terminal else - echo "The '$TERMINAL_NAME' terminal isn't executable. SMAPI might be running in a sandbox or the system might be misconfigured? Falling back to current shell." - env TERM=xterm $LAUNCH_FILE "$@" - if [ $? -eq 127 ]; then - exec $LAUNCH_FILE --no-terminal "$@" - fi + exec $LAUNCH_FILE --no-terminal "$@" fi fi -- cgit From 0d7d4476004d33b395d6df81386e4159d8898027 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 20 Dec 2021 22:18:09 -0500 Subject: auto-fix maps broken due to missing vanilla tilesheet --- docs/release-notes.md | 1 + src/SMAPI.sln.DotSettings | 1 + src/SMAPI/Framework/Content/TilesheetReference.cs | 15 ++++++++- src/SMAPI/Framework/ContentCoordinator.cs | 4 +-- .../ContentManagers/GameContentManager.cs | 39 +++++++++------------- 5 files changed, 33 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index e0c6977d..caa5cc68 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -3,6 +3,7 @@ # Release notes ## Upcoming release * For players: + * SMAPI now auto-fixes maps loaded without a required tilesheet to prevent errors. * Fixed outdated instructions in Steam error message. * Simplified [running without a terminal on Linux/macOS](https://stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting#SMAPI_doesn.27t_recognize_controller_.28Steam_only.29) when needed. * Updated compatibility list. diff --git a/src/SMAPI.sln.DotSettings b/src/SMAPI.sln.DotSettings index 9a6cad37..71cd7b82 100644 --- a/src/SMAPI.sln.DotSettings +++ b/src/SMAPI.sln.DotSettings @@ -70,6 +70,7 @@ True True True + True True True \ No newline at end of file diff --git a/src/SMAPI/Framework/Content/TilesheetReference.cs b/src/SMAPI/Framework/Content/TilesheetReference.cs index 2ea38430..0919bb44 100644 --- a/src/SMAPI/Framework/Content/TilesheetReference.cs +++ b/src/SMAPI/Framework/Content/TilesheetReference.cs @@ -1,3 +1,6 @@ +using System.Numerics; +using xTile.Dimensions; + namespace StardewModdingAPI.Framework.Content { /// Basic metadata about a vanilla tilesheet. @@ -15,6 +18,12 @@ namespace StardewModdingAPI.Framework.Content /// The asset path for the tilesheet texture. public readonly string ImageSource; + /// The number of tiles in the tilesheet. + public readonly Size SheetSize; + + /// The size of each tile in pixels. + public readonly Size TileSize; + /********* ** Public methods @@ -23,11 +32,15 @@ namespace StardewModdingAPI.Framework.Content /// The tilesheet's index in the list. /// The tilesheet's unique ID in the map. /// The asset path for the tilesheet texture. - public TilesheetReference(int index, string id, string imageSource) + /// The number of tiles in the tilesheet. + /// The size of each tile in pixels. + public TilesheetReference(int index, string id, string imageSource, Size sheetSize, Size tileSize) { this.Index = index; this.Id = id; this.ImageSource = imageSource; + this.SheetSize = sheetSize; + this.TileSize = tileSize; } } } diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs index b6f1669a..99091f3e 100644 --- a/src/SMAPI/Framework/ContentCoordinator.cs +++ b/src/SMAPI/Framework/ContentCoordinator.cs @@ -406,14 +406,14 @@ namespace StardewModdingAPI.Framework if (!this.VanillaTilesheets.TryGetValue(assetName, out TilesheetReference[] tilesheets)) { tilesheets = this.TryLoadVanillaAsset(assetName, out Map map) - ? map.TileSheets.Select((sheet, index) => new TilesheetReference(index, sheet.Id, sheet.ImageSource)).ToArray() + ? map.TileSheets.Select((sheet, index) => new TilesheetReference(index, sheet.Id, sheet.ImageSource, sheet.SheetSize, sheet.TileSize)).ToArray() : null; this.VanillaTilesheets[assetName] = tilesheets; this.VanillaContentManager.Unload(); } - return tilesheets ?? new TilesheetReference[0]; + return tilesheets ?? Array.Empty(); } /// Get the language enum which corresponds to a locale code (e.g. given fr-FR). diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs index 7a49dd36..ab198076 100644 --- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs @@ -13,6 +13,7 @@ using StardewModdingAPI.Framework.Utilities; using StardewModdingAPI.Internal; using StardewValley; using xTile; +using xTile.Tiles; namespace StardewModdingAPI.Framework.ContentManagers { @@ -308,7 +309,7 @@ namespace StardewModdingAPI.Framework.ContentManagers } // return matched asset - return this.TryValidateLoadedAsset(info, data, mod) + return this.TryFixAndValidateLoadedAsset(info, data, mod) ? new AssetDataForObject(info, data, this.AssertAndNormalizeAssetName) : null; } @@ -381,12 +382,13 @@ namespace StardewModdingAPI.Framework.ContentManagers return asset; } - /// Validate that an asset loaded by a mod is valid and won't cause issues. + /// Validate that an asset loaded by a mod is valid and won't cause issues, and fix issues if possible. /// The asset type. /// The basic asset metadata. /// The loaded asset data. /// The mod which loaded the asset. - private bool TryValidateLoadedAsset(IAssetInfo info, T data, IModMetadata mod) + /// Returns whether the asset passed validation checks (after any fixes were applied). + private bool TryFixAndValidateLoadedAsset(IAssetInfo info, T data, IModMetadata mod) { // can't load a null asset if (data == null) @@ -401,20 +403,23 @@ namespace StardewModdingAPI.Framework.ContentManagers TilesheetReference[] vanillaTilesheetRefs = this.Coordinator.GetVanillaTilesheetIds(info.AssetName); foreach (TilesheetReference vanillaSheet in vanillaTilesheetRefs) { - // skip if match - if (loadedMap.TileSheets.Count > vanillaSheet.Index && loadedMap.TileSheets[vanillaSheet.Index].Id == vanillaSheet.Id) - continue; + // add missing tilesheet + if (loadedMap.GetTileSheet(vanillaSheet.Id) == null) + { + mod.Monitor.LogOnce("SMAPI fixed maps loaded by this mod to prevent errors. See the log file for details.", LogLevel.Warn); + this.Monitor.Log($"Fixed broken map replacement: {mod.DisplayName} loaded '{info.AssetName}' without a required tilesheet (id: {vanillaSheet.Id}, source: {vanillaSheet.ImageSource})."); + + loadedMap.AddTileSheet(new TileSheet(vanillaSheet.Id, loadedMap, vanillaSheet.ImageSource, vanillaSheet.SheetSize, vanillaSheet.TileSize)); + } // handle mismatch + if (loadedMap.TileSheets.Count <= vanillaSheet.Index || loadedMap.TileSheets[vanillaSheet.Index].Id != vanillaSheet.Id) { // only show warning if not farm map // This is temporary: mods shouldn't do this for any vanilla map, but these are the ones we know will crash. Showing a warning for others instead gives modders time to update their mods, while still simplifying troubleshooting. bool isFarmMap = info.AssetNameEquals("Maps/Farm") || info.AssetNameEquals("Maps/Farm_Combat") || info.AssetNameEquals("Maps/Farm_Fishing") || info.AssetNameEquals("Maps/Farm_Foraging") || info.AssetNameEquals("Maps/Farm_FourCorners") || info.AssetNameEquals("Maps/Farm_Island") || info.AssetNameEquals("Maps/Farm_Mining"); - int loadedIndex = this.TryFindTilesheet(loadedMap, vanillaSheet.Id); - string reason = loadedIndex != -1 - ? $"mod reordered the original tilesheets, which {(isFarmMap ? "would cause a crash" : "often causes crashes")}.\nTechnical details for mod author: Expected order: {string.Join(", ", vanillaTilesheetRefs.Select(p => p.Id))}. See https://stardewvalleywiki.com/Modding:Maps#Tilesheet_order for help." - : $"mod has no tilesheet with ID '{vanillaSheet.Id}'. Map replacements must keep the original tilesheets to avoid errors or crashes."; + string reason = $"mod reordered the original tilesheets, which {(isFarmMap ? "would cause a crash" : "often causes crashes")}.\nTechnical details for mod author: Expected order: {string.Join(", ", vanillaTilesheetRefs.Select(p => p.Id))}. See https://stardewvalleywiki.com/Modding:Maps#Tilesheet_order for help."; SCore.DeprecationManager.PlaceholderWarn("3.8.2", DeprecationLevel.PendingRemoval); if (isFarmMap) @@ -429,19 +434,5 @@ namespace StardewModdingAPI.Framework.ContentManagers return true; } - - /// Find a map tilesheet by ID. - /// The map whose tilesheets to search. - /// The tilesheet ID to match. - private int TryFindTilesheet(Map map, string id) - { - for (int i = 0; i < map.TileSheets.Count; i++) - { - if (map.TileSheets[i].Id == id) - return i; - } - - return -1; - } } } -- cgit From 52f4df3f301ecde85a76e10ea9ddd607ab7a1b79 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 21 Dec 2021 20:33:08 -0500 Subject: add new game build number to the SMAPI log --- docs/release-notes.md | 1 + src/SMAPI/Constants.cs | 11 +++++++++++ src/SMAPI/Framework/Logging/LogManager.cs | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index caa5cc68..a98cfd8e 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -4,6 +4,7 @@ ## Upcoming release * For players: * SMAPI now auto-fixes maps loaded without a required tilesheet to prevent errors. + * Added the new game build number to the SMAPI console + log. * Fixed outdated instructions in Steam error message. * Simplified [running without a terminal on Linux/macOS](https://stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting#SMAPI_doesn.27t_recognize_controller_.28Steam_only.29) when needed. * Updated compatibility list. diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index 5de28f84..c86acd0a 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -340,5 +340,16 @@ namespace StardewModdingAPI // if save doesn't exist yet, return the default one we expect to be created return folder; } + + /// Get a display label for the game's build number. + internal static string GetBuildVersionLabel() + { + string version = typeof(Game1).Assembly.GetName().Version?.ToString() ?? "unknown"; + + if (version.StartsWith($"{Game1.version}.")) + version = version.Substring(Game1.version.Length + 1); + + return version; + } } } diff --git a/src/SMAPI/Framework/Logging/LogManager.cs b/src/SMAPI/Framework/Logging/LogManager.cs index ef89c751..90433c37 100644 --- a/src/SMAPI/Framework/Logging/LogManager.cs +++ b/src/SMAPI/Framework/Logging/LogManager.cs @@ -262,7 +262,7 @@ namespace StardewModdingAPI.Framework.Logging public void LogIntro(string modsPath, IDictionary customSettings) { // log platform - this.Monitor.Log($"SMAPI {Constants.ApiVersion} with Stardew Valley {Constants.GameVersion} on {EnvironmentUtility.GetFriendlyPlatformName(Constants.Platform)}", LogLevel.Info); + this.Monitor.Log($"SMAPI {Constants.ApiVersion} with Stardew Valley {Constants.GameVersion} (build {Constants.GetBuildVersionLabel()}) on {EnvironmentUtility.GetFriendlyPlatformName(Constants.Platform)}", LogLevel.Info); // log basic info this.Monitor.Log($"Mods go here: {modsPath}", LogLevel.Info); -- cgit From 571211687935ce3a12bf4905f056d9be1d6b147f Mon Sep 17 00:00:00 2001 From: bruce2409 Date: Wed, 22 Dec 2021 17:41:11 +0000 Subject: Added shell shebang to MacOS Launcher code --- src/SMAPI.Installer/assets/unix-launcher.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/SMAPI.Installer/assets/unix-launcher.sh b/src/SMAPI.Installer/assets/unix-launcher.sh index 713597e2..7cf39f0e 100644 --- a/src/SMAPI.Installer/assets/unix-launcher.sh +++ b/src/SMAPI.Installer/assets/unix-launcher.sh @@ -31,7 +31,8 @@ if [ "$(uname)" == "Darwin" ]; then # https://stackoverflow.com/a/29511052/262123 if [ "$SKIP_TERMINAL" == "false" ]; then echo "Reopening in the Terminal app..." - echo "\"$0\" $@ --no-reopen-terminal" > /tmp/open-smapi-terminal.sh + echo '#!/bin/sh" > /tmp/open-smapi-terminal.sh + echo "\"$0\" $@ --no-reopen-terminal" >> /tmp/open-smapi-terminal.sh chmod +x /tmp/open-smapi-terminal.sh cat /tmp/open-smapi-terminal.sh open -W -a Terminal /tmp/open-smapi-terminal.sh -- cgit From 02831503ddae7d3cd977c21cdd056fc218594ad1 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 23 Dec 2021 18:59:14 -0500 Subject: remove content pack from compatibility blacklist It's no longer broken with the auto-fixes in the upcoming SMAPI update. --- src/SMAPI.Web/wwwroot/SMAPI.metadata.json | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src') diff --git a/src/SMAPI.Web/wwwroot/SMAPI.metadata.json b/src/SMAPI.Web/wwwroot/SMAPI.metadata.json index 53c68636..75a3f8c7 100644 --- a/src/SMAPI.Web/wwwroot/SMAPI.metadata.json +++ b/src/SMAPI.Web/wwwroot/SMAPI.metadata.json @@ -283,11 +283,6 @@ /********* ** Broke in SDV 1.5 (Content Patcher packs) *********/ - "Empty Spouse Room": { - "ID": "Lerura.EmptySpouseRoom", - "~1.0.0 | Status": "AssumeBroken", - "~1.0.0 | StatusReasonDetails": "prevents loading married saves due to a missing tilesheet in the spouse room map" - }, "mi.Mermaids": { "ID": "mi.Mermaids", "~1.0.0 | Status": "AssumeBroken", -- cgit From aad77242f02c0a851b5d6ad11c258d9b74d90c5b Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 23 Dec 2021 23:08:49 -0500 Subject: fix uninstaller not removing StardewModdingAPI.deps.json file --- docs/release-notes.md | 1 + src/SMAPI.Installer/InteractiveInstaller.cs | 1 + 2 files changed, 2 insertions(+) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index a98cfd8e..0be39c13 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -6,6 +6,7 @@ * SMAPI now auto-fixes maps loaded without a required tilesheet to prevent errors. * Added the new game build number to the SMAPI console + log. * Fixed outdated instructions in Steam error message. + * Fixed uninstaller not removing `StardewModdingAPI.deps.json` file. * Simplified [running without a terminal on Linux/macOS](https://stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting#SMAPI_doesn.27t_recognize_controller_.28Steam_only.29) when needed. * Updated compatibility list. diff --git a/src/SMAPI.Installer/InteractiveInstaller.cs b/src/SMAPI.Installer/InteractiveInstaller.cs index 1257f12b..b3bba883 100644 --- a/src/SMAPI.Installer/InteractiveInstaller.cs +++ b/src/SMAPI.Installer/InteractiveInstaller.cs @@ -41,6 +41,7 @@ namespace StardewModdingApi.Installer // current files yield return GetInstallPath("StardewModdingAPI"); // Linux/macOS only + yield return GetInstallPath("StardewModdingAPI.deps.json"); yield return GetInstallPath("StardewModdingAPI.dll"); yield return GetInstallPath("StardewModdingAPI.exe"); yield return GetInstallPath("StardewModdingAPI.exe.config"); -- cgit From 92f35837ad771090d96a759feb0d5d6d8c273b0e Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 2 Jan 2022 13:48:53 -0500 Subject: fix syntax, update release notes --- docs/release-notes.md | 1 + src/SMAPI.Installer/assets/unix-launcher.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index 0be39c13..3eac227f 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -7,6 +7,7 @@ * Added the new game build number to the SMAPI console + log. * Fixed outdated instructions in Steam error message. * Fixed uninstaller not removing `StardewModdingAPI.deps.json` file. + * Fixed launch issue on macOS when using some terminals (thanks to bruce2409!). * Simplified [running without a terminal on Linux/macOS](https://stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting#SMAPI_doesn.27t_recognize_controller_.28Steam_only.29) when needed. * Updated compatibility list. diff --git a/src/SMAPI.Installer/assets/unix-launcher.sh b/src/SMAPI.Installer/assets/unix-launcher.sh index 7cf39f0e..47937f95 100644 --- a/src/SMAPI.Installer/assets/unix-launcher.sh +++ b/src/SMAPI.Installer/assets/unix-launcher.sh @@ -31,7 +31,7 @@ if [ "$(uname)" == "Darwin" ]; then # https://stackoverflow.com/a/29511052/262123 if [ "$SKIP_TERMINAL" == "false" ]; then echo "Reopening in the Terminal app..." - echo '#!/bin/sh" > /tmp/open-smapi-terminal.sh + echo '#!/bin/sh' > /tmp/open-smapi-terminal.sh echo "\"$0\" $@ --no-reopen-terminal" >> /tmp/open-smapi-terminal.sh chmod +x /tmp/open-smapi-terminal.sh cat /tmp/open-smapi-terminal.sh -- cgit From 1fab386ab1ba6ae92ff934c3869f31a1660cf3b3 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 2 Jan 2022 13:57:14 -0500 Subject: add Ukrainian translations (#823) --- docs/README.md | 38 +++++++++++++++++--------------- docs/release-notes.md | 1 + src/SMAPI.Mods.ErrorHandler/i18n/uk.json | 4 ++++ src/SMAPI/i18n/uk.json | 6 +++++ 4 files changed, 31 insertions(+), 18 deletions(-) create mode 100644 src/SMAPI.Mods.ErrorHandler/i18n/uk.json create mode 100644 src/SMAPI/i18n/uk.json (limited to 'src') diff --git a/docs/README.md b/docs/README.md index ecfa6f2b..d3aaae64 100644 --- a/docs/README.md +++ b/docs/README.md @@ -56,22 +56,24 @@ SMAPI rarely shows text in-game, so it only has a few translations. Contribution [Modding:Translations](https://stardewvalleywiki.com/Modding:Translations) on the wiki for help contributing translations. -locale | status ----------- | :---------------- -default | ✓ [fully translated](../src/SMAPI/i18n/default.json) -Chinese | ✓ [fully translated](../src/SMAPI/i18n/zh.json) -French | ✓ [fully translated](../src/SMAPI/i18n/fr.json) -German | ✓ [fully translated](../src/SMAPI/i18n/de.json) -Hungarian | ✓ [fully translated](../src/SMAPI/i18n/hu.json) -Italian | ✓ [fully translated](../src/SMAPI/i18n/it.json) -Japanese | ✓ [fully translated](../src/SMAPI/i18n/ja.json) -Korean | ✓ [fully translated](../src/SMAPI/i18n/ko.json) -Polish¹ | ✓ [fully translated](../src/SMAPI/i18n/pl.json) -Portuguese | ✓ [fully translated](../src/SMAPI/i18n/pt.json) -Russian | ✓ [fully translated](../src/SMAPI/i18n/ru.json) -Spanish | ✓ [fully translated](../src/SMAPI/i18n/es.json) -Thai¹ | ✓ [fully translated](../src/SMAPI/i18n/th.json) -Turkish | ✓ [fully translated](../src/SMAPI/i18n/tr.json) +locale | status +----------- | :---------------- +default | ✓ [fully translated](../src/SMAPI/i18n/default.json) +Chinese | ✓ [fully translated](../src/SMAPI/i18n/zh.json) +French | ✓ [fully translated](../src/SMAPI/i18n/fr.json) +German | ✓ [fully translated](../src/SMAPI/i18n/de.json) +Hungarian | ✓ [fully translated](../src/SMAPI/i18n/hu.json) +Italian | ✓ [fully translated](../src/SMAPI/i18n/it.json) +Japanese | ✓ [fully translated](../src/SMAPI/i18n/ja.json) +Korean | ✓ [fully translated](../src/SMAPI/i18n/ko.json) +[Polish] | ✓ [fully translated](../src/SMAPI/i18n/pl.json) +Portuguese | ✓ [fully translated](../src/SMAPI/i18n/pt.json) +Russian | ✓ [fully translated](../src/SMAPI/i18n/ru.json) +Spanish | ✓ [fully translated](../src/SMAPI/i18n/es.json) +[Thai] | ✓ [fully translated](../src/SMAPI/i18n/th.json) +Turkish | ✓ [fully translated](../src/SMAPI/i18n/tr.json) +[Ukrainian] | ✓ [fully translated](../src/SMAPI/i18n/uk.json) -¹ This is a custom language provided by a mod (see [Polish](https://www.nexusmods.com/stardewvalley/mods/3616) -and [Thai](https://www.nexusmods.com/stardewvalley/mods/7052)). +[Polish]: https://www.nexusmods.com/stardewvalley/mods/3616 +[Thai]: https://www.nexusmods.com/stardewvalley/mods/7052 +[Ukrainian]: https://www.nexusmods.com/stardewvalley/mods/8427 diff --git a/docs/release-notes.md b/docs/release-notes.md index 3eac227f..8ca2e884 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -10,6 +10,7 @@ * Fixed launch issue on macOS when using some terminals (thanks to bruce2409!). * Simplified [running without a terminal on Linux/macOS](https://stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting#SMAPI_doesn.27t_recognize_controller_.28Steam_only.29) when needed. * Updated compatibility list. + * Improved translations. Thanks to ChulkyBow (added Ukrainian)! * For the web UI: * Fixed log parser not correctly handling multiple mods having the exact same name. diff --git a/src/SMAPI.Mods.ErrorHandler/i18n/uk.json b/src/SMAPI.Mods.ErrorHandler/i18n/uk.json new file mode 100644 index 00000000..a58102ab --- /dev/null +++ b/src/SMAPI.Mods.ErrorHandler/i18n/uk.json @@ -0,0 +1,4 @@ +{ + // warning messages + "warn.invalid-content-removed": "Недійсний вміст видалено, щоб запобігти аварійному завершенню роботи (Додаткову інформацію див. на консолі SMAPI)." +} diff --git a/src/SMAPI/i18n/uk.json b/src/SMAPI/i18n/uk.json new file mode 100644 index 00000000..d84aabcf --- /dev/null +++ b/src/SMAPI/i18n/uk.json @@ -0,0 +1,6 @@ +{ + // short date format for SDate + // tokens: {{day}} (like 15), {{season}} (like Spring), {{seasonLowercase}} (like spring), {{year}} (like 2) + "generic.date": "{{season}} День {{day}}", + "generic.date-with-year": "{{season}} День {{day}}, Рік {{year}}" +} -- cgit From e30e42762871af3900c47886b57e8c43287b290a Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 2 Jan 2022 19:59:38 -0500 Subject: add download option to log view --- docs/release-notes.md | 1 + src/SMAPI.Web/Controllers/LogParserController.cs | 33 +++++++++++++++++++----- src/SMAPI.Web/ViewModels/LogViewFormat.cs | 15 +++++++++++ src/SMAPI.Web/Views/LogParser/Index.cshtml | 17 +++++++++--- 4 files changed, 56 insertions(+), 10 deletions(-) create mode 100644 src/SMAPI.Web/ViewModels/LogViewFormat.cs (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index 8ca2e884..1df0af0e 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -13,6 +13,7 @@ * Improved translations. Thanks to ChulkyBow (added Ukrainian)! * For the web UI: + * Added log download option. * Fixed log parser not correctly handling multiple mods having the exact same name. ## 3.13.2 diff --git a/src/SMAPI.Web/Controllers/LogParserController.cs b/src/SMAPI.Web/Controllers/LogParserController.cs index 39de4b5d..db53d942 100644 --- a/src/SMAPI.Web/Controllers/LogParserController.cs +++ b/src/SMAPI.Web/Controllers/LogParserController.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using StardewModdingAPI.Toolkit.Utilities; @@ -39,24 +40,42 @@ namespace StardewModdingAPI.Web.Controllers ***/ /// Render the log parser UI. /// The stored file ID. - /// Whether to display the raw unparsed log. + /// How to render the log view. /// Whether to reset the log expiry. [HttpGet] [Route("log")] [Route("log/{id}")] - public async Task Index(string id = null, bool raw = false, bool renew = false) + public async Task Index(string id = null, LogViewFormat format = LogViewFormat.Default, bool renew = false) { // fresh page if (string.IsNullOrWhiteSpace(id)) return this.View("Index", this.GetModel(id)); - // log page + // fetch log StoredFileInfo file = await this.Storage.GetAsync(id, renew); - ParsedLog log = file.Success - ? new LogParser().Parse(file.Content) - : new ParsedLog { IsValid = false, Error = file.Error }; - return this.View("Index", this.GetModel(id, uploadWarning: file.Warning, expiry: file.Expiry).SetResult(log, raw)); + // render view + switch (format) + { + case LogViewFormat.Default: + case LogViewFormat.RawView: + { + ParsedLog log = file.Success + ? new LogParser().Parse(file.Content) + : new ParsedLog { IsValid = false, Error = file.Error }; + + return this.View("Index", this.GetModel(id, uploadWarning: file.Warning, expiry: file.Expiry).SetResult(log, showRaw: format == LogViewFormat.RawView)); + } + + case LogViewFormat.RawDownload: + { + string content = file.Error ?? file.Content; + return this.File(Encoding.UTF8.GetBytes(content), "plain/text", $"SMAPI log ({id}).txt"); + } + + default: + throw new InvalidOperationException($"Unknown log view format '{format}'."); + } } /*** diff --git a/src/SMAPI.Web/ViewModels/LogViewFormat.cs b/src/SMAPI.Web/ViewModels/LogViewFormat.cs new file mode 100644 index 00000000..7ef79319 --- /dev/null +++ b/src/SMAPI.Web/ViewModels/LogViewFormat.cs @@ -0,0 +1,15 @@ +namespace StardewModdingAPI.Web.ViewModels +{ + /// How a log file should be displayed. + public enum LogViewFormat + { + /// Render a parsed log and metadata. + Default, + + /// Render a raw log with parsed metadata. + RawView, + + /// Render directly as a text file. + RawDownload + } +} diff --git a/src/SMAPI.Web/Views/LogParser/Index.cshtml b/src/SMAPI.Web/Views/LogParser/Index.cshtml index 06d46c9e..eeff776c 100644 --- a/src/SMAPI.Web/Views/LogParser/Index.cshtml +++ b/src/SMAPI.Web/Views/LogParser/Index.cshtml @@ -2,6 +2,7 @@ @using StardewModdingAPI.Toolkit.Utilities @using StardewModdingAPI.Web.Framework @using StardewModdingAPI.Web.Framework.LogParsing.Models +@using StardewModdingAPI.Web.ViewModels @model StardewModdingAPI.Web.ViewModels.LogParserModel @{ @@ -338,14 +339,24 @@ else if (Model.ParsedLog?.IsValid == true) } } - - view raw log } else {
@Model.ParsedLog.RawText
- view parsed log } + + + @if (Model.ShowRaw) + { + view parsed log + } + else + { + view raw log + } + + | download + } else if (Model.ParsedLog?.IsValid == false) -- cgit From a8985e122e9ebd3cb1545971474b95d34058f896 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 15 Jan 2022 12:21:22 -0500 Subject: fix suppressed console output not suppressing newlines --- docs/release-notes.md | 1 + .../Framework/Logging/InterceptingTextWriter.cs | 12 +++++++++++- src/SMAPI/Framework/Logging/LogManager.cs | 20 ++++++++++++++++---- 3 files changed, 28 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index 1df0af0e..735c7c12 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -5,6 +5,7 @@ * For players: * SMAPI now auto-fixes maps loaded without a required tilesheet to prevent errors. * Added the new game build number to the SMAPI console + log. + * Fixed extra newlines shown in the console in non-developer mode. * Fixed outdated instructions in Steam error message. * Fixed uninstaller not removing `StardewModdingAPI.deps.json` file. * Fixed launch issue on macOS when using some terminals (thanks to bruce2409!). diff --git a/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs b/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs index d99f1dd2..41a3abcb 100644 --- a/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs +++ b/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs @@ -26,6 +26,10 @@ namespace StardewModdingAPI.Framework.Logging /// The event raised when a message is written to the console directly. public event Action OnMessageIntercepted; + /// Whether the text writer should ignore the next input if it's a newline. + /// This is used when log output is suppressed from the console, since Console.WriteLine writes the trailing newline as a separate call. + public bool IgnoreNextIfNewline { get; set; } + /********* ** Public methods @@ -42,12 +46,18 @@ namespace StardewModdingAPI.Framework.Logging /// public override void Write(char[] buffer, int index, int count) { + bool ignoreIfNewline = this.IgnoreNextIfNewline; + this.IgnoreNextIfNewline = false; + if (buffer.Length == 0) this.Out.Write(buffer, index, count); else if (buffer[0] == this.IgnoreChar) this.Out.Write(buffer, index + 1, count - 1); else if (this.IsEmptyOrNewline(buffer)) - this.Out.Write(buffer, index, count); + { + if (!ignoreIfNewline) + this.Out.Write(buffer, index, count); + } else this.OnMessageIntercepted?.Invoke(new string(buffer, index, count).TrimEnd('\r', '\n')); } diff --git a/src/SMAPI/Framework/Logging/LogManager.cs b/src/SMAPI/Framework/Logging/LogManager.cs index 90433c37..acd2c617 100644 --- a/src/SMAPI/Framework/Logging/LogManager.cs +++ b/src/SMAPI/Framework/Logging/LogManager.cs @@ -22,9 +22,15 @@ namespace StardewModdingAPI.Framework.Logging /********* ** Fields *********/ + /// Whether to show trace messages in the console. + private readonly bool ShowTraceInConsole; + /// The log file to which to write messages. private readonly LogFileManager LogFile; + /// The text writer which intercepts console output. + private readonly InterceptingTextWriter ConsoleInterceptor; + /// Prefixing a low-level message with this character indicates that the console interceptor should write the string without intercepting it. (The character itself is not written.) private readonly char IgnoreChar = '\u200B'; @@ -91,10 +97,11 @@ namespace StardewModdingAPI.Framework.Logging public LogManager(string logPath, ColorSchemeConfig colorConfig, bool writeToConsole, bool isVerbose, bool isDeveloperMode, Func getScreenIdForLog) { // init construction logic + this.ShowTraceInConsole = isDeveloperMode; this.GetMonitorImpl = name => new Monitor(name, this.IgnoreChar, this.LogFile, colorConfig, isVerbose, getScreenIdForLog) { WriteToConsole = writeToConsole, - ShowTraceInConsole = isDeveloperMode, + ShowTraceInConsole = this.ShowTraceInConsole, ShowFullStampInConsole = isDeveloperMode }; @@ -104,10 +111,10 @@ namespace StardewModdingAPI.Framework.Logging this.MonitorForGame = this.GetMonitor("game"); // redirect direct console output - var output = new InterceptingTextWriter(Console.Out, this.IgnoreChar); + this.ConsoleInterceptor = new InterceptingTextWriter(Console.Out, this.IgnoreChar); if (writeToConsole) - output.OnMessageIntercepted += message => this.HandleConsoleMessage(this.MonitorForGame, message); - Console.SetOut(output); + this.ConsoleInterceptor.OnMessageIntercepted += message => this.HandleConsoleMessage(this.MonitorForGame, message); + Console.SetOut(this.ConsoleInterceptor); // enable Unicode handling on Windows // (the terminal defaults to UTF-8 on Linux/macOS) @@ -363,7 +370,10 @@ namespace StardewModdingAPI.Framework.Logging // ignore suppressed message if (level != LogLevel.Error && this.SuppressConsolePatterns.Any(p => p.IsMatch(message))) + { + this.ConsoleInterceptor.IgnoreNextIfNewline = true; return; + } // show friendly error if applicable foreach (ReplaceLogPattern entry in this.ReplaceConsolePatterns) @@ -383,6 +393,8 @@ namespace StardewModdingAPI.Framework.Logging // forward to monitor gameMonitor.Log(message, level); + if (level == LogLevel.Trace && !this.ShowTraceInConsole) + this.ConsoleInterceptor.IgnoreNextIfNewline = true; } /// Write a summary of mod warnings to the console and log. -- cgit From 8ebb9ce8d4c554b077e1e6286531c101d64c019d Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 15 Jan 2022 13:27:23 -0500 Subject: fix backspaces ignored on Linux/macOS in SDV 1.5.5+ --- docs/release-notes.md | 5 +++-- src/SMAPI/Framework/Logging/InterceptingTextWriter.cs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index 735c7c12..06d75b15 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -3,12 +3,13 @@ # Release notes ## Upcoming release * For players: - * SMAPI now auto-fixes maps loaded without a required tilesheet to prevent errors. + * Added auto-fix for custom maps which don't have a required tilesheet. * Added the new game build number to the SMAPI console + log. * Fixed extra newlines shown in the console in non-developer mode. + * Fixed macOS launch issue when using some terminals (thanks to bruce2409!). + * Fixed Linux/macOS terminal ignoring backspace in Stardew Valley 1.5.5+. * Fixed outdated instructions in Steam error message. * Fixed uninstaller not removing `StardewModdingAPI.deps.json` file. - * Fixed launch issue on macOS when using some terminals (thanks to bruce2409!). * Simplified [running without a terminal on Linux/macOS](https://stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting#SMAPI_doesn.27t_recognize_controller_.28Steam_only.29) when needed. * Updated compatibility list. * Improved translations. Thanks to ChulkyBow (added Ukrainian)! diff --git a/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs b/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs index 41a3abcb..36f81d22 100644 --- a/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs +++ b/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs @@ -51,7 +51,7 @@ namespace StardewModdingAPI.Framework.Logging if (buffer.Length == 0) this.Out.Write(buffer, index, count); - else if (buffer[0] == this.IgnoreChar) + else if (buffer[0] == this.IgnoreChar || char.IsControl(buffer[0])) // ignore control characters like backspace this.Out.Write(buffer, index + 1, count - 1); else if (this.IsEmptyOrNewline(buffer)) { -- cgit From 4cffd6c2c092b18940f2dd1041e418f60573a87e Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 15 Jan 2022 17:21:11 -0500 Subject: add save recovery for missing custom farm type --- docs/release-notes.md | 3 ++- .../Patches/SaveGamePatcher.cs | 30 ++++++++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index 06d75b15..aea4dbab 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -3,7 +3,8 @@ # Release notes ## Upcoming release * For players: - * Added auto-fix for custom maps which don't have a required tilesheet. + * Added automatic fix for custom maps which don't have a required tilesheet. + * Added automatic save recovery when the custom farm type isn't available anymore. * Added the new game build number to the SMAPI console + log. * Fixed extra newlines shown in the console in non-developer mode. * Fixed macOS launch issue when using some terminals (thanks to bruce2409!). diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/SaveGamePatcher.cs b/src/SMAPI.Mods.ErrorHandler/Patches/SaveGamePatcher.cs index 2a43cb10..0a7ed212 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/SaveGamePatcher.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/SaveGamePatcher.cs @@ -4,11 +4,11 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using HarmonyLib; using Microsoft.Xna.Framework.Content; +using StardewModdingAPI.Internal; using StardewModdingAPI.Internal.Patching; using StardewValley; using StardewValley.Buildings; using StardewValley.Locations; -using SObject = StardewValley.Object; namespace StardewModdingAPI.Mods.ErrorHandler.Patches { @@ -47,6 +47,11 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches original: this.RequireMethod(nameof(SaveGame.loadDataToLocations)), prefix: this.GetHarmonyMethod(nameof(SaveGamePatcher.Before_LoadDataToLocations)) ); + + harmony.Patch( + original: this.RequireMethod(nameof(SaveGame.LoadFarmType)), + finalizer: this.GetHarmonyMethod(nameof(SaveGamePatcher.Finalize_LoadFarmType)) + ); } @@ -58,14 +63,35 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches /// Returns whether to execute the original method. private static bool Before_LoadDataToLocations(List gamelocations) { + // missing locations/NPCs IDictionary npcs = Game1.content.Load>("Data\\NPCDispositions"); - if (SaveGamePatcher.RemoveBrokenContent(gamelocations, npcs)) SaveGamePatcher.OnContentRemoved(); return true; } + /// The method to call after throws an exception. + /// The exception thrown by the wrapped method, if any. + /// Returns the exception to throw, if any. + private static Exception Finalize_LoadFarmType(Exception __exception) + { + // missing custom farm type + if (__exception?.Message?.Contains("not a valid farm type") == true && !int.TryParse(SaveGame.loaded.whichFarm, out _)) + { + SaveGamePatcher.Monitor.Log(__exception.GetLogSummary(), LogLevel.Error); + SaveGamePatcher.Monitor.Log($"Removed invalid custom farm type '{SaveGame.loaded.whichFarm}' to avoid a crash when loading save '{Constants.SaveFolderName}'. (Did you remove a custom farm type mod?)", LogLevel.Warn); + + SaveGame.loaded.whichFarm = Farm.default_layout.ToString(); + SaveGame.LoadFarmType(); + SaveGamePatcher.OnContentRemoved(); + + __exception = null; + } + + return __exception; + } + /// Remove content which no longer exists in the game data. /// The current game locations. /// The NPC data. -- cgit From d029dd652fcb7390d756d92803da2dbc91f8b0de Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 15 Jan 2022 18:04:33 -0500 Subject: fix JSON validator not recognizing manifest update subkeys --- docs/release-notes.md | 1 + src/SMAPI.Web/wwwroot/schemas/manifest.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index aea4dbab..3be90208 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -18,6 +18,7 @@ * For the web UI: * Added log download option. * Fixed log parser not correctly handling multiple mods having the exact same name. + * Fixed JSON validator not recognizing manifest [update subkeys](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Update_checks#Update_subkeys). ## 3.13.2 Released 05 December 2021 for Stardew Valley 1.5.5 or later. diff --git a/src/SMAPI.Web/wwwroot/schemas/manifest.json b/src/SMAPI.Web/wwwroot/schemas/manifest.json index 05698ba2..b6722347 100644 --- a/src/SMAPI.Web/wwwroot/schemas/manifest.json +++ b/src/SMAPI.Web/wwwroot/schemas/manifest.json @@ -103,7 +103,7 @@ "type": "array", "items": { "type": "string", - "pattern": "^(?i)(Chucklefish:\\d+|Nexus:\\d+|GitHub:[A-Za-z0-9_\\-]+/[A-Za-z0-9_\\-]+|ModDrop:\\d+)$", + "pattern": "^(?i)(Chucklefish:\\d+|Nexus:\\d+|GitHub:[A-Za-z0-9_\\-]+/[A-Za-z0-9_\\-]+|ModDrop:\\d+)(?: *@ *[a-zA-Z0-9_]+ *)$", "@errorMessages": { "pattern": "Invalid update key; see https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Manifest#Update_checks for more info." } -- cgit From 6f05580191e27bdf876d75a967a3238947d5a091 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 15 Jan 2022 20:39:32 -0500 Subject: add detection for Xbox app game folders --- build/find-game-folder.targets | 22 +++++++++++++++++++--- docs/release-notes.md | 1 + docs/technical/mod-package.md | 3 +++ .../Framework/GameScanning/GameScanner.cs | 11 ++++++++++- 4 files changed, 33 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/build/find-game-folder.targets b/build/find-game-folder.targets index 3164b071..ba7cb26c 100644 --- a/build/find-game-folder.targets +++ b/build/find-game-folder.targets @@ -28,15 +28,31 @@ <_SteamLibraryPath>$([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Valve\Steam', 'SteamPath', null, RegistryView.Registry32)) $(_SteamLibraryPath)\steamapps\common\Stardew Valley - + C:\Program Files\GalaxyClient\Games\Stardew Valley C:\Program Files\GOG Galaxy\Games\Stardew Valley C:\Program Files\GOG Games\Stardew Valley - C:\Program Files\Steam\steamapps\common\Stardew Valley - C:\Program Files (x86)\GalaxyClient\Games\Stardew Valley C:\Program Files (x86)\GOG Galaxy\Games\Stardew Valley C:\Program Files (x86)\GOG Games\Stardew Valley + + + + C:\Program Files\ModifiableWindowsApps\Stardew Valley + D:\Program Files\ModifiableWindowsApps\Stardew Valley + E:\Program Files\ModifiableWindowsApps\Stardew Valley + F:\Program Files\ModifiableWindowsApps\Stardew Valley + G:\Program Files\ModifiableWindowsApps\Stardew Valley + H:\Program Files\ModifiableWindowsApps\Stardew Valley + + + C:\Program Files\Steam\steamapps\common\Stardew Valley C:\Program Files (x86)\Steam\steamapps\common\Stardew Valley diff --git a/docs/release-notes.md b/docs/release-notes.md index 3be90208..f37b35f5 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -6,6 +6,7 @@ * Added automatic fix for custom maps which don't have a required tilesheet. * Added automatic save recovery when the custom farm type isn't available anymore. * Added the new game build number to the SMAPI console + log. + * The installer now detects Xbox app game folders. * Fixed extra newlines shown in the console in non-developer mode. * Fixed macOS launch issue when using some terminals (thanks to bruce2409!). * Fixed Linux/macOS terminal ignoring backspace in Stardew Valley 1.5.5+. diff --git a/docs/technical/mod-package.md b/docs/technical/mod-package.md index 41f808a5..5e408168 100644 --- a/docs/technical/mod-package.md +++ b/docs/technical/mod-package.md @@ -412,6 +412,9 @@ The NuGet package is generated automatically in `StardewModdingAPI.ModBuildConfi when you compile it. ## Release notes +## Upcoming release +* Added detection for Xbox app game folders. + ## 4.0.0 Released 30 November 2021. diff --git a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs index 37e4f263..8d4198de 100644 --- a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs +++ b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs @@ -157,7 +157,7 @@ namespace StardewModdingAPI.Toolkit.Framework.GameScanning yield return Path.Combine(steamPath.Replace('/', '\\'), @"steamapps\common\Stardew Valley"); #endif - // default paths + // default GOG/Steam paths foreach (string programFiles in new[] { @"C:\Program Files", @"C:\Program Files (x86)" }) { yield return $@"{programFiles}\GalaxyClient\Games\Stardew Valley"; @@ -165,6 +165,15 @@ namespace StardewModdingAPI.Toolkit.Framework.GameScanning yield return $@"{programFiles}\GOG Games\Stardew Valley"; yield return $@"{programFiles}\Steam\steamapps\common\Stardew Valley"; } + + // default Xbox app paths + // The Xbox app saves the install path to the registry, but we can't use it + // here since it saves the internal readonly path (like C:\Program Files\WindowsApps\Mutable\) + // instead of the mods-enabled path(like C:\Program Files\ModifiableWindowsApps\Stardew Valley). + // Fortunately we can cheat a bit: players can customize the install drive, but they can't + // change the install path on the drive. + for (char driveLetter = 'C'; driveLetter <= 'H'; driveLetter++) + yield return $@"{driveLetter}:\Program Files\ModifiableWindowsApps\Stardew Valley"; } break; -- cgit From 7e8d11ca3aff9a7e741127cd5fd35d073c381ec9 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 15 Jan 2022 23:41:01 -0500 Subject: add Xbox app log instructions, redesign UI to fit --- docs/release-notes.md | 2 + src/SMAPI.Web/Views/LogParser/Index.cshtml | 118 +++++++++++++---------- src/SMAPI.Web/wwwroot/Content/css/log-parser.css | 26 ++++- src/SMAPI.Web/wwwroot/Content/js/log-parser.js | 11 --- 4 files changed, 91 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index f37b35f5..50eb416b 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -17,7 +17,9 @@ * Improved translations. Thanks to ChulkyBow (added Ukrainian)! * For the web UI: + * Added log instructions for Xbox app on Windows. * Added log download option. + * Redesigned log instruction UI. * Fixed log parser not correctly handling multiple mods having the exact same name. * Fixed JSON validator not recognizing manifest [update subkeys](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Update_checks#Update_subkeys). diff --git a/src/SMAPI.Web/Views/LogParser/Index.cshtml b/src/SMAPI.Web/Views/LogParser/Index.cshtml index eeff776c..91fc3535 100644 --- a/src/SMAPI.Web/Views/LogParser/Index.cshtml +++ b/src/SMAPI.Web/Views/LogParser/Index.cshtml @@ -23,13 +23,15 @@ { } - - + + + + - - + + } @@ -91,51 +95,65 @@ else if (Model.ParsedLog?.IsValid == true) @if (Model.ParsedLog == null) {

Where do I find my SMAPI log?

-
What system do you use?
-
    - @foreach (Platform platform in new[] { Platform.Android, Platform.Linux, Platform.Mac, Platform.Windows }) - { -
  • - - -
  • - } -
-
- On Android: -
    -
  1. Open a file app (like My Files or MT Manager).
  2. -
  3. Find the StardewValley folder on your internal storage.
  4. -
  5. Open the ErrorLogs subfolder.
  6. -
  7. The log file is SMAPI-crash.txt if it exists, otherwise SMAPI-latest.txt.
  8. -
-
-
- On Linux: -
    -
  1. Open the Files app.
  2. -
  3. Click the options menu (might be labeled Go or ).
  4. -
  5. Choose Enter Location.
  6. -
  7. Enter this exact text:
    ~/.config/StardewValley/ErrorLogs
  8. -
  9. The log file is SMAPI-crash.txt if it exists, otherwise SMAPI-latest.txt.
  10. -
-
-
- On macOS: -
    -
  1. Open the Finder app.
  2. -
  3. Click Go at the top, then Go to Folder.
  4. -
  5. Enter this exact text:
    ~/.config/StardewValley/ErrorLogs
  6. -
  7. The log file is SMAPI-crash.txt if it exists, otherwise SMAPI-latest.txt.
  8. -
-
-
- On Windows: -
    -
  1. Press the Windows and R buttons at the same time.
  2. -
  3. In the 'run' box that appears, enter this exact text:
    %appdata%\StardewValley\ErrorLogs
  4. -
  5. The log file is SMAPI-crash.txt if it exists, otherwise SMAPI-latest.txt.
  6. -
+
+
+ +
+
+
+
    +
  1. Open a file app (like My Files or MT Manager).
  2. +
  3. Find the StardewValley folder on your internal storage.
  4. +
  5. Open the ErrorLogs subfolder.
  6. +
  7. The log file is SMAPI-crash.txt if it exists, otherwise SMAPI-latest.txt.
  8. +
+
+
+
    +
  1. Open the Files app.
  2. +
  3. Click the options menu (might be labeled Go or ).
  4. +
  5. Choose Enter Location.
  6. +
  7. Enter this exact text:
    ~/.config/StardewValley/ErrorLogs
  8. +
  9. The log file is SMAPI-crash.txt if it exists, otherwise SMAPI-latest.txt.
  10. +
+
+
+
    +
  1. Open the Finder app.
  2. +
  3. Click Go at the top, then Go to Folder.
  4. +
  5. Enter this exact text:
    ~/.config/StardewValley/ErrorLogs
  6. +
  7. The log file is SMAPI-crash.txt if it exists, otherwise SMAPI-latest.txt.
  8. +
+
+
+
    +
  1. Press the Windows and R buttons at the same time.
  2. +
  3. In the 'run' box that appears, enter this exact text:
    %appdata%\StardewValley\ErrorLogs
  4. +
  5. The log file is SMAPI-crash.txt if it exists, otherwise SMAPI-latest.txt.
  6. +
+
+
+
    +
  1. Press the Windows and R buttons at the same time.
  2. +
  3. In the 'run' box that appears, enter this exact text:
    %localappdata%\Packages\ConcernedApe.StardewValleyPC_0c8vynj4cqe4e\LocalCache\Roaming\StardewValley\ErrorLogs
  4. +
  5. If you get an error with the title "Location is not available", try the "with Steam or GOG" instructions above.
  6. +
  7. Otherwise the log file is SMAPI-crash.txt if it exists, otherwise SMAPI-latest.txt.
  8. +
+
+

How do I share my log?

@@ -354,7 +372,7 @@ else if (Model.ParsedLog?.IsValid == true) { view raw log } - + | download
diff --git a/src/SMAPI.Web/wwwroot/Content/css/log-parser.css b/src/SMAPI.Web/wwwroot/Content/css/log-parser.css index bfbc8982..8c3acceb 100644 --- a/src/SMAPI.Web/wwwroot/Content/css/log-parser.css +++ b/src/SMAPI.Web/wwwroot/Content/css/log-parser.css @@ -291,13 +291,29 @@ table caption { /********* -** Upload form +** OS instructions *********/ -#os-list { - list-style: none; +#os-instructions { + display: grid; + grid-template-columns: minmax(16em, auto) 30em; } -div[data-os] { - display: none; +#os-instructions [role="tablist"] { + border: 0; +} + +#os-instructions [role="tab"] { + display: block; + border: 0; + position: relative; } +#os-instructions [role="tab"][aria-selected="true"] { + font-weight: bold; + border-radius: 0 10px 10px 0; +} + +[role="tab"][aria-selected="true"]::after { + content: "▶"; + padding-left: 0.5em; +} diff --git a/src/SMAPI.Web/wwwroot/Content/js/log-parser.js b/src/SMAPI.Web/wwwroot/Content/js/log-parser.js index 6ae1707e..90715375 100644 --- a/src/SMAPI.Web/wwwroot/Content/js/log-parser.js +++ b/src/SMAPI.Web/wwwroot/Content/js/log-parser.js @@ -115,17 +115,6 @@ smapi.logParser = function (data, sectionUrl) { *********/ var input = $("#input"); if (input.length) { - // instructions per OS - var systemOptions = $("input[name='os']"); - var systemInstructions = $("div[data-os]"); - - var chooseSystem = function () { - systemInstructions.hide(); - systemInstructions.filter("[data-os='" + $("input[name='os']:checked").val() + "']").show(); - }; - systemOptions.on("click", chooseSystem); - chooseSystem(); - // file upload smapi.fileUpload({ chooseFileLink: $("#choose-file-link"), -- cgit From 00bd9d19a183635813376bd194333ea2b97ecfb3 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 16 Jan 2022 00:15:03 -0500 Subject: bump min game version to 1.5.6 That avoids error reports on mods when pirated players have an older 1.5.5 build that break mods, and ensures that the new build number shown in the SMAPI log is available. --- docs/release-notes.md | 1 + src/SMAPI/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index 50eb416b..1a6f4078 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -3,6 +3,7 @@ # Release notes ## Upcoming release * For players: + * **Increased minimum game version to Stardew Valley 1.5.6.** * Added automatic fix for custom maps which don't have a required tilesheet. * Added automatic save recovery when the custom farm type isn't available anymore. * Added the new game build number to the SMAPI console + log. diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index c86acd0a..9e0ba79f 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -65,7 +65,7 @@ namespace StardewModdingAPI public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion(EarlyConstants.RawApiVersion); /// The minimum supported version of Stardew Valley. - public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.5.5"); + public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.5.6"); /// The maximum supported version of Stardew Valley. public static ISemanticVersion MaximumGameVersion { get; } = null; -- cgit From 1ea8d752356b313d200810235463a322a47f9425 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 16 Jan 2022 14:05:02 -0500 Subject: improve console interception logic --- .../Framework/Logging/InterceptingTextWriter.cs | 28 ++++++++++--------- src/SMAPI/Framework/Logging/LogManager.cs | 31 +++++++++------------- src/SMAPI/Framework/Monitor.cs | 2 +- 3 files changed, 30 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs b/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs index 36f81d22..bad69a2a 100644 --- a/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs +++ b/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs @@ -8,15 +8,11 @@ namespace StardewModdingAPI.Framework.Logging internal class InterceptingTextWriter : TextWriter { /********* - ** Fields + ** Accessors *********/ /// Prefixing a message with this character indicates that the console interceptor should write the string without intercepting it. (The character itself is not written.) - private readonly char IgnoreChar; - + public const char IgnoreChar = '\u200B'; - /********* - ** Accessors - *********/ /// The underlying console output. public TextWriter Out { get; } @@ -36,30 +32,38 @@ namespace StardewModdingAPI.Framework.Logging *********/ /// Construct an instance. /// The underlying output writer. - /// Prefixing a message with this character indicates that the console interceptor should write the string without intercepting it. (The character itself is not written.) - public InterceptingTextWriter(TextWriter output, char ignoreChar) + public InterceptingTextWriter(TextWriter output) { this.Out = output; - this.IgnoreChar = ignoreChar; } /// public override void Write(char[] buffer, int index, int count) { + // track newline skip bool ignoreIfNewline = this.IgnoreNextIfNewline; this.IgnoreNextIfNewline = false; - if (buffer.Length == 0) + // get first character if valid + if (count == 0 || index < 0 || index >= buffer.Length) + { this.Out.Write(buffer, index, count); - else if (buffer[0] == this.IgnoreChar || char.IsControl(buffer[0])) // ignore control characters like backspace + return; + } + char firstChar = buffer[index]; + + // handle output + if (firstChar == InterceptingTextWriter.IgnoreChar) this.Out.Write(buffer, index + 1, count - 1); + else if (char.IsControl(firstChar) && firstChar is not ('\r' or '\n')) + this.Out.Write(buffer, index, count); else if (this.IsEmptyOrNewline(buffer)) { if (!ignoreIfNewline) this.Out.Write(buffer, index, count); } else - this.OnMessageIntercepted?.Invoke(new string(buffer, index, count).TrimEnd('\r', '\n')); + this.OnMessageIntercepted?.Invoke(new string(buffer, index, count)); } /// diff --git a/src/SMAPI/Framework/Logging/LogManager.cs b/src/SMAPI/Framework/Logging/LogManager.cs index acd2c617..a8a8b6ee 100644 --- a/src/SMAPI/Framework/Logging/LogManager.cs +++ b/src/SMAPI/Framework/Logging/LogManager.cs @@ -22,9 +22,6 @@ namespace StardewModdingAPI.Framework.Logging /********* ** Fields *********/ - /// Whether to show trace messages in the console. - private readonly bool ShowTraceInConsole; - /// The log file to which to write messages. private readonly LogFileManager LogFile; @@ -32,7 +29,7 @@ namespace StardewModdingAPI.Framework.Logging private readonly InterceptingTextWriter ConsoleInterceptor; /// Prefixing a low-level message with this character indicates that the console interceptor should write the string without intercepting it. (The character itself is not written.) - private readonly char IgnoreChar = '\u200B'; + private const char IgnoreChar = InterceptingTextWriter.IgnoreChar; /// Get a named monitor instance. private readonly Func GetMonitorImpl; @@ -40,18 +37,18 @@ namespace StardewModdingAPI.Framework.Logging /// Regex patterns which match console non-error messages to suppress from the console and log. private readonly Regex[] SuppressConsolePatterns = { - new Regex(@"^TextBox\.Selected is now '(?:True|False)'\.$", RegexOptions.Compiled | RegexOptions.CultureInvariant), - new Regex(@"^loadPreferences\(\); begin", RegexOptions.Compiled | RegexOptions.CultureInvariant), - new Regex(@"^savePreferences\(\); async=", RegexOptions.Compiled | RegexOptions.CultureInvariant), - new Regex(@"^DebugOutput:\s+(?:added cricket|dismount tile|Ping|playerPos)", RegexOptions.Compiled | RegexOptions.CultureInvariant), - new Regex(@"^Ignoring keys: ", RegexOptions.Compiled | RegexOptions.CultureInvariant) + new(@"^TextBox\.Selected is now '(?:True|False)'\.$", RegexOptions.Compiled | RegexOptions.CultureInvariant), + new(@"^loadPreferences\(\); begin", RegexOptions.Compiled | RegexOptions.CultureInvariant), + new(@"^savePreferences\(\); async=", RegexOptions.Compiled | RegexOptions.CultureInvariant), + new(@"^DebugOutput:\s+(?:added cricket|dismount tile|Ping|playerPos)", RegexOptions.Compiled | RegexOptions.CultureInvariant), + new(@"^Ignoring keys: ", RegexOptions.Compiled | RegexOptions.CultureInvariant) }; /// Regex patterns which match console messages to show a more friendly error for. private readonly ReplaceLogPattern[] ReplaceConsolePatterns = { // Steam not loaded - new ReplaceLogPattern( + new( search: new Regex(@"^System\.InvalidOperationException: Steamworks is not initialized\.[\s\S]+$", RegexOptions.Compiled | RegexOptions.CultureInvariant), replacement: #if SMAPI_FOR_WINDOWS @@ -63,7 +60,7 @@ namespace StardewModdingAPI.Framework.Logging ), // save file not found error - new ReplaceLogPattern( + new( search: new Regex(@"^System\.IO\.FileNotFoundException: [^\n]+\n[^:]+: '[^\n]+[/\\]Saves[/\\]([^'\r\n]+)[/\\]([^'\r\n]+)'[\s\S]+LoadGameMenu\.FindSaveGames[\s\S]+$", RegexOptions.Compiled | RegexOptions.CultureInvariant), replacement: "The game can't find the '$2' file for your '$1' save. See https://stardewvalleywiki.com/Saves#Troubleshooting for help.", logLevel: LogLevel.Error @@ -97,11 +94,10 @@ namespace StardewModdingAPI.Framework.Logging public LogManager(string logPath, ColorSchemeConfig colorConfig, bool writeToConsole, bool isVerbose, bool isDeveloperMode, Func getScreenIdForLog) { // init construction logic - this.ShowTraceInConsole = isDeveloperMode; - this.GetMonitorImpl = name => new Monitor(name, this.IgnoreChar, this.LogFile, colorConfig, isVerbose, getScreenIdForLog) + this.GetMonitorImpl = name => new Monitor(name, LogManager.IgnoreChar, this.LogFile, colorConfig, isVerbose, getScreenIdForLog) { WriteToConsole = writeToConsole, - ShowTraceInConsole = this.ShowTraceInConsole, + ShowTraceInConsole = isDeveloperMode, ShowFullStampInConsole = isDeveloperMode }; @@ -111,7 +107,7 @@ namespace StardewModdingAPI.Framework.Logging this.MonitorForGame = this.GetMonitor("game"); // redirect direct console output - this.ConsoleInterceptor = new InterceptingTextWriter(Console.Out, this.IgnoreChar); + this.ConsoleInterceptor = new InterceptingTextWriter(Console.Out); if (writeToConsole) this.ConsoleInterceptor.OnMessageIntercepted += message => this.HandleConsoleMessage(this.MonitorForGame, message); Console.SetOut(this.ConsoleInterceptor); @@ -153,7 +149,7 @@ namespace StardewModdingAPI.Framework.Logging .Add(new ReloadI18nCommand(reloadTranslations), this.Monitor); // start handling command line input - Thread inputThread = new Thread(() => + Thread inputThread = new(() => { while (true) { @@ -393,8 +389,7 @@ namespace StardewModdingAPI.Framework.Logging // forward to monitor gameMonitor.Log(message, level); - if (level == LogLevel.Trace && !this.ShowTraceInConsole) - this.ConsoleInterceptor.IgnoreNextIfNewline = true; + this.ConsoleInterceptor.IgnoreNextIfNewline = true; } /// Write a summary of mod warnings to the console and log. diff --git a/src/SMAPI/Framework/Monitor.cs b/src/SMAPI/Framework/Monitor.cs index 04e67d68..ab76e7c0 100644 --- a/src/SMAPI/Framework/Monitor.cs +++ b/src/SMAPI/Framework/Monitor.cs @@ -28,7 +28,7 @@ namespace StardewModdingAPI.Framework private static readonly int MaxLevelLength = (from level in Enum.GetValues(typeof(LogLevel)).Cast() select level.ToString().Length).Max(); /// A cache of messages that should only be logged once. - private readonly HashSet LogOnceCache = new HashSet(); + private readonly HashSet LogOnceCache = new(); /// Get the screen ID that should be logged to distinguish between players in split-screen mode, if any. private readonly Func GetScreenIdForLog; -- cgit From 230f1192056a5b49147bc45a8328b6132069f8c7 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 16 Jan 2022 17:08:08 -0500 Subject: merge field rewriters to reduce rewrite iterations --- docs/release-notes.md | 1 + .../ModLoading/Framework/RewriteHelper.cs | 24 +--------- .../ModLoading/Rewriters/FieldReplaceRewriter.cs | 54 +++++++++++----------- src/SMAPI/Metadata/InstructionMetadata.cs | 9 ++-- 4 files changed, 35 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/docs/release-notes.md b/docs/release-notes.md index 1a6f4078..56564953 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -8,6 +8,7 @@ * Added automatic save recovery when the custom farm type isn't available anymore. * Added the new game build number to the SMAPI console + log. * The installer now detects Xbox app game folders. + * Reduced mod loading time a bit. * Fixed extra newlines shown in the console in non-developer mode. * Fixed macOS launch issue when using some terminals (thanks to bruce2409!). * Fixed Linux/macOS terminal ignoring backspace in Stardew Valley 1.5.5+. diff --git a/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs b/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs index 60bbd2c7..d7cb2471 100644 --- a/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs +++ b/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs @@ -13,7 +13,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework ** Fields *********/ /// The comparer which heuristically compares type definitions. - private static readonly TypeReferenceComparer TypeDefinitionComparer = new TypeReferenceComparer(); + private static readonly TypeReferenceComparer TypeDefinitionComparer = new(); /********* @@ -28,28 +28,6 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework : null; } - /// Get whether the field is a reference to the expected type and field. - /// The IL instruction. - /// The full type name containing the expected field. - /// The name of the expected field. - public static bool IsFieldReferenceTo(Instruction instruction, string fullTypeName, string fieldName) - { - FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction); - return RewriteHelper.IsFieldReferenceTo(fieldRef, fullTypeName, fieldName); - } - - /// Get whether the field is a reference to the expected type and field. - /// The field reference to check. - /// The full type name containing the expected field. - /// The name of the expected field. - public static bool IsFieldReferenceTo(FieldReference fieldRef, string fullTypeName, string fieldName) - { - return - fieldRef != null - && fieldRef.DeclaringType.FullName == fullTypeName - && fieldRef.Name == fieldName; - } - /// Get the method reference from an instruction if it matches. /// The IL instruction. public static MethodReference AsMethodReference(Instruction instruction) diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs index 0b679e9d..857a2230 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Reflection; using Mono.Cecil; using Mono.Cecil.Cil; @@ -12,54 +13,55 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters /********* ** Fields *********/ - /// The type containing the field to which references should be rewritten. - private readonly Type Type; - - /// The field name to which references should be rewritten. - private readonly string FromFieldName; - - /// The new field to reference. - private readonly FieldInfo ToField; + /// The new fields to reference indexed by the old field/type names. + private readonly Dictionary> FieldMaps = new(); /********* ** Public methods *********/ /// Construct an instance. + public FieldReplaceRewriter() + : base(defaultPhrase: "field replacement") { } // will be overridden when a field is replaced + + /// Add a field to replace. /// The type whose field to rewrite. /// The field name to rewrite. /// The new type which will have the field. /// The new field name to reference. - public FieldReplaceRewriter(Type fromType, string fromFieldName, Type toType, string toFieldName) - : base(defaultPhrase: $"{fromType.FullName}.{fromFieldName} field") + public FieldReplaceRewriter AddField(Type fromType, string fromFieldName, Type toType, string toFieldName) { - this.Type = fromType; - this.FromFieldName = fromFieldName; - this.ToField = toType.GetField(toFieldName); - if (this.ToField == null) + // get full type name + string fromTypeName = fromType?.FullName; + if (fromTypeName == null) + throw new InvalidOperationException($"Can't replace field for invalid type reference {toType}."); + + // get target field + FieldInfo toField = toType.GetField(toFieldName); + if (toField == null) throw new InvalidOperationException($"The {toType.FullName} class doesn't have a {toFieldName} field."); - } - /// Construct an instance. - /// The type whose field to rewrite. - /// The field name to rewrite. - /// The new field name to reference. - public FieldReplaceRewriter(Type type, string fromFieldName, string toFieldName) - : this(type, fromFieldName, type, toFieldName) - { + // add mapping + if (!this.FieldMaps.TryGetValue(fromTypeName, out var fieldMap)) + this.FieldMaps[fromTypeName] = fieldMap = new(); + fieldMap[fromFieldName] = toField; + + return this; } /// public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction) { - // get field reference FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction); - if (!RewriteHelper.IsFieldReferenceTo(fieldRef, this.Type.FullName, this.FromFieldName)) + string declaringType = fieldRef?.DeclaringType?.FullName; + + // get mapped field + if (declaringType == null || !this.FieldMaps.TryGetValue(declaringType, out var fieldMap) || !fieldMap.TryGetValue(fieldRef.Name, out FieldInfo toField)) return false; // replace with new field - instruction.Operand = module.ImportReference(this.ToField); - + this.Phrases.Add($"{fieldRef.DeclaringType.Name}.{fieldRef.Name} field"); + instruction.Operand = module.ImportReference(toField); return this.MarkRewritten(); } } diff --git a/src/SMAPI/Metadata/InstructionMetadata.cs b/src/SMAPI/Metadata/InstructionMetadata.cs index 232e54ce..367372b2 100644 --- a/src/SMAPI/Metadata/InstructionMetadata.cs +++ b/src/SMAPI/Metadata/InstructionMetadata.cs @@ -37,9 +37,10 @@ namespace StardewModdingAPI.Metadata if (rewriteMods) { // rewrite for Stardew Valley 1.5 - yield return new FieldReplaceRewriter(typeof(DecoratableLocation), "furniture", typeof(GameLocation), nameof(GameLocation.furniture)); - yield return new FieldReplaceRewriter(typeof(Farm), "resourceClumps", typeof(GameLocation), nameof(GameLocation.resourceClumps)); - yield return new FieldReplaceRewriter(typeof(MineShaft), "resourceClumps", typeof(GameLocation), nameof(GameLocation.resourceClumps)); + yield return new FieldReplaceRewriter() + .AddField(typeof(DecoratableLocation), "furniture", typeof(GameLocation), nameof(GameLocation.furniture)) + .AddField(typeof(Farm), "resourceClumps", typeof(GameLocation), nameof(GameLocation.resourceClumps)) + .AddField(typeof(MineShaft), "resourceClumps", typeof(GameLocation), nameof(GameLocation.resourceClumps)); // heuristic rewrites yield return new HeuristicFieldRewriter(this.ValidateReferencesToAssemblies); @@ -87,7 +88,7 @@ namespace StardewModdingAPI.Metadata typeof(System.IO.DirectoryInfo).FullName, typeof(System.IO.DriveInfo).FullName, typeof(System.IO.FileSystemWatcher).FullName - }, + }, InstructionHandleResult.DetectedFilesystemAccess ); -- cgit From ad0e6b315dc7b4e616dcdf6c090cd54a2f3b7499 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 16 Jan 2022 17:13:28 -0500 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 'src') diff --git a/build/common.targets b/build/common.targets index 1021c2a1..8eac9757 100644 --- a/build/common.targets +++ b/build/common.targets @@ -1,7 +1,7 @@ - 3.13.2 + 3.13.3 SMAPI latest $(AssemblySearchPaths);{GAC} diff --git a/docs/release-notes.md b/docs/release-notes.md index 56564953..957d5199 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,17 +1,19 @@ ← [README](README.md) # Release notes -## Upcoming release +## 3.13.3 +Released 16 January 2021 for Stardew Valley 1.5.6 or later. + * For players: - * **Increased minimum game version to Stardew Valley 1.5.6.** - * Added automatic fix for custom maps which don't have a required tilesheet. - * Added automatic save recovery when the custom farm type isn't available anymore. - * Added the new game build number to the SMAPI console + log. + * **SMAPI now needs Stardew Valley 1.5.6 or later.** + * Added automatic fix for custom maps which are missing a required tilesheet. + * Added automatic save recovery when a custom farm type isn't available anymore. + * Added the game's new build number to the SMAPI console + log. * The installer now detects Xbox app game folders. * Reduced mod loading time a bit. - * Fixed extra newlines shown in the console in non-developer mode. * Fixed macOS launch issue when using some terminals (thanks to bruce2409!). - * Fixed Linux/macOS terminal ignoring backspace in Stardew Valley 1.5.5+. + * Fixed Linux/macOS terminal ignoring backspaces in Stardew Valley 1.5.5+. + * Fixed extra newlines in the SMAPI console. * Fixed outdated instructions in Steam error message. * Fixed uninstaller not removing `StardewModdingAPI.deps.json` file. * Simplified [running without a terminal on Linux/macOS](https://stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting#SMAPI_doesn.27t_recognize_controller_.28Steam_only.29) when needed. diff --git a/src/SMAPI.Mods.ConsoleCommands/manifest.json b/src/SMAPI.Mods.ConsoleCommands/manifest.json index 216a4c32..97e1c243 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.13.2", + "Version": "3.13.3", "Description": "Adds SMAPI console commands that let you manipulate the game.", "UniqueID": "SMAPI.ConsoleCommands", "EntryDll": "ConsoleCommands.dll", - "MinimumApiVersion": "3.13.2" + "MinimumApiVersion": "3.13.3" } diff --git a/src/SMAPI.Mods.ErrorHandler/manifest.json b/src/SMAPI.Mods.ErrorHandler/manifest.json index beb52020..c4246721 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.13.2", + "Version": "3.13.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.13.2" + "MinimumApiVersion": "3.13.3" } diff --git a/src/SMAPI.Mods.SaveBackup/manifest.json b/src/SMAPI.Mods.SaveBackup/manifest.json index 2bd20a63..b1b946c8 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.13.2", + "Version": "3.13.3", "Description": "Automatically backs up all your saves once per day into its folder.", "UniqueID": "SMAPI.SaveBackup", "EntryDll": "SaveBackup.dll", - "MinimumApiVersion": "3.13.2" + "MinimumApiVersion": "3.13.3" } diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index 9e0ba79f..455cfd7e 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -49,7 +49,7 @@ namespace StardewModdingAPI internal static int? LogScreenId { get; set; } /// SMAPI's current raw semantic version. - internal static string RawApiVersion = "3.13.2"; + internal static string RawApiVersion = "3.13.3"; } /// Contains SMAPI's constants and assumptions. -- cgit