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 --- src/SMAPI/Framework/Logging/LogManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI/Framework/Logging') 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 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/SMAPI/Framework/Logging') 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 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/SMAPI/Framework/Logging') 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/SMAPI/Framework/Logging') 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 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/SMAPI/Framework/Logging') 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