From 4adf8611131a5d86b15f017a42a0366837d14528 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 13 Apr 2022 21:07:43 -0400 Subject: enable nullable annotations in the rest of SMAPI core (#837) --- .../Framework/Logging/InterceptingTextWriter.cs | 24 +++++++-------- src/SMAPI/Framework/Logging/LogManager.cs | 36 ++++++++++++---------- 2 files changed, 30 insertions(+), 30 deletions(-) (limited to 'src/SMAPI/Framework/Logging') diff --git a/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs b/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs index a0957b90..9ecc1626 100644 --- a/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs +++ b/src/SMAPI/Framework/Logging/InterceptingTextWriter.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using System.IO; using System.Text; @@ -9,6 +7,13 @@ namespace StardewModdingAPI.Framework.Logging /// A text writer which allows intercepting output. internal class InterceptingTextWriter : TextWriter { + /********* + ** Fields + *********/ + /// The event raised when a message is written to the console directly. + private readonly Action OnMessageIntercepted; + + /********* ** Accessors *********/ @@ -21,9 +26,6 @@ namespace StardewModdingAPI.Framework.Logging /// public override Encoding Encoding => this.Out.Encoding; - /// 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; } @@ -34,9 +36,11 @@ namespace StardewModdingAPI.Framework.Logging *********/ /// Construct an instance. /// The underlying output writer. - public InterceptingTextWriter(TextWriter output) + /// The event raised when a message is written to the console directly. + public InterceptingTextWriter(TextWriter output, Action onMessageIntercepted) { this.Out = output; + this.OnMessageIntercepted = onMessageIntercepted; } /// @@ -65,7 +69,7 @@ namespace StardewModdingAPI.Framework.Logging this.Out.Write(buffer, index, count); } else - this.OnMessageIntercepted?.Invoke(new string(buffer, index, count)); + this.OnMessageIntercepted(new string(buffer, index, count)); } /// @@ -74,12 +78,6 @@ namespace StardewModdingAPI.Framework.Logging this.Out.Write(ch); } - /// - protected override void Dispose(bool disposing) - { - this.OnMessageIntercepted = null; - } - /********* ** Private methods diff --git a/src/SMAPI/Framework/Logging/LogManager.cs b/src/SMAPI/Framework/Logging/LogManager.cs index dab7f554..a5989673 100644 --- a/src/SMAPI/Framework/Logging/LogManager.cs +++ b/src/SMAPI/Framework/Logging/LogManager.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -95,6 +93,11 @@ namespace StardewModdingAPI.Framework.Logging /// Get the screen ID that should be logged to distinguish between players in split-screen mode, if any. public LogManager(string logPath, ColorSchemeConfig colorConfig, bool writeToConsole, bool isVerbose, bool isDeveloperMode, Func getScreenIdForLog) { + // init fields + this.LogFile = new LogFileManager(logPath); + this.Monitor = this.GetMonitor("SMAPI"); + this.MonitorForGame = this.GetMonitor("game"); + // init construction logic this.GetMonitorImpl = name => new Monitor(name, LogManager.IgnoreChar, this.LogFile, colorConfig, isVerbose, getScreenIdForLog) { @@ -103,15 +106,13 @@ namespace StardewModdingAPI.Framework.Logging ShowFullStampInConsole = isDeveloperMode }; - // init fields - this.LogFile = new LogFileManager(logPath); - this.Monitor = this.GetMonitor("SMAPI"); - this.MonitorForGame = this.GetMonitor("game"); - // redirect direct console output - this.ConsoleInterceptor = new InterceptingTextWriter(Console.Out); - if (writeToConsole) - this.ConsoleInterceptor.OnMessageIntercepted += message => this.HandleConsoleMessage(this.MonitorForGame, message); + this.ConsoleInterceptor = new InterceptingTextWriter( + output: Console.Out, + onMessageIntercepted: writeToConsole + ? message => this.HandleConsoleMessage(this.MonitorForGame, message) + : _ => { } + ); Console.SetOut(this.ConsoleInterceptor); // enable Unicode handling on Windows @@ -156,7 +157,7 @@ namespace StardewModdingAPI.Framework.Logging while (true) { // get input - string input = Console.ReadLine(); + string? input = Console.ReadLine(); if (string.IsNullOrWhiteSpace(input)) continue; @@ -222,7 +223,7 @@ namespace StardewModdingAPI.Framework.Logging if (File.Exists(Constants.UpdateMarker)) { string[] rawUpdateFound = File.ReadAllText(Constants.UpdateMarker).Split(new[] { '|' }, 2); - if (SemanticVersion.TryParse(rawUpdateFound[0], out ISemanticVersion updateFound)) + if (SemanticVersion.TryParse(rawUpdateFound[0], out ISemanticVersion? updateFound)) { if (Constants.ApiVersion.IsPrerelease() && updateFound.IsNewerThan(Constants.ApiVersion)) { @@ -264,7 +265,7 @@ namespace StardewModdingAPI.Framework.Logging /// Log the initial header with general SMAPI and system details. /// The path from which mods will be loaded. /// The custom SMAPI settings. - public void LogIntro(string modsPath, IDictionary customSettings) + public void LogIntro(string modsPath, IDictionary customSettings) { // log platform this.Monitor.Log($"SMAPI {Constants.ApiVersion} with Stardew Valley {Constants.GameVersion} (build {Constants.GetBuildVersionLabel()}) on {EnvironmentUtility.GetFriendlyPlatformName(Constants.Platform)}", LogLevel.Info); @@ -326,7 +327,7 @@ namespace StardewModdingAPI.Framework.Logging // log loaded content packs if (loadedContentPacks.Any()) { - string GetModDisplayName(string id) => loadedMods.FirstOrDefault(p => p.HasID(id))?.DisplayName; + string? GetModDisplayName(string id) => loadedMods.FirstOrDefault(p => p.HasID(id))?.DisplayName; this.Monitor.Log($"Loaded {loadedContentPacks.Length} content packs:", LogLevel.Info); foreach (IModMetadata metadata in loadedContentPacks.OrderBy(p => p.DisplayName)) @@ -335,7 +336,7 @@ namespace StardewModdingAPI.Framework.Logging this.Monitor.Log( $" {metadata.DisplayName} {manifest.Version}" + (!string.IsNullOrWhiteSpace(manifest.Author) ? $" by {manifest.Author}" : "") - + $" | for {GetModDisplayName(metadata.Manifest.ContentPackFor.UniqueID)}" + + $" | for {GetModDisplayName(metadata.Manifest.ContentPackFor!.UniqueID)}" + (!string.IsNullOrWhiteSpace(manifest.Description) ? $" | {manifest.Description}" : ""), LogLevel.Info ); @@ -398,6 +399,7 @@ namespace StardewModdingAPI.Framework.Logging /// The loaded mods. /// The mods which could not be loaded. /// Whether to log issues for mods which directly use potentially sensitive .NET APIs like file or shell access. + [SuppressMessage("ReSharper", "ConstantConditionalAccessQualifier", Justification = "Manifests aren't guaranteed non-null at this point in the loading process.")] private void LogModWarnings(IEnumerable mods, IModMetadata[] skippedMods, bool logParanoidWarnings) { // get mods with warnings @@ -431,7 +433,7 @@ namespace StardewModdingAPI.Framework.Logging // duplicate mod: log first one only, don't show redundant version if (mod.FailReason == ModFailReason.Duplicate && mod.HasManifest()) { - if (loggedDuplicateIds.Add(mod.Manifest.UniqueID)) + if (loggedDuplicateIds.Add(mod.Manifest!.UniqueID)) continue; // already logged message = $" - {mod.DisplayName} because {mod.Error}"; @@ -610,7 +612,7 @@ namespace StardewModdingAPI.Framework.Logging /// A brief heading label for the group. /// A detailed explanation of the warning, split into lines. /// Formats the mod label, or null to use the . - private void LogModWarningGroup(IModMetadata[] mods, Func match, LogLevel level, string heading, string[] blurb, Func modLabel = null) + private void LogModWarningGroup(IModMetadata[] mods, Func match, LogLevel level, string heading, string[] blurb, Func? modLabel = null) { // get matching mods string[] modLabels = mods -- cgit