From 0a00c70397d85777499dcf7877cef08727a2dbae Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 20 Dec 2019 20:27:21 -0500 Subject: add console warning in paranoid mode --- src/SMAPI/Framework/ModLoading/AssemblyLoader.cs | 5 +++++ src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs | 3 +++ 2 files changed, 8 insertions(+) (limited to 'src/SMAPI/Framework/ModLoading') diff --git a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs index 7670eb3a..b5533335 100644 --- a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs +++ b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs @@ -356,6 +356,11 @@ namespace StardewModdingAPI.Framework.ModLoading mod.SetWarning(ModWarning.UsesDynamic); break; + case InstructionHandleResult.DetectedConsoleAccess: + this.Monitor.LogOnce(loggedMessages, $"{logPrefix}Detected direct console access ({handler.NounPhrase}) in assembly {filename}."); + mod.SetWarning(ModWarning.AccessesConsole); + break; + case InstructionHandleResult.DetectedFilesystemAccess: this.Monitor.LogOnce(loggedMessages, $"{logPrefix}Detected filesystem access ({handler.NounPhrase}) in assembly {filename}."); mod.SetWarning(ModWarning.AccessesFilesystem); diff --git a/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs b/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs index d93b603d..a948213b 100644 --- a/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs +++ b/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs @@ -26,6 +26,9 @@ namespace StardewModdingAPI.Framework.ModLoading /// The instruction is compatible, but references or which may impact stability. DetectedUnvalidatedUpdateTick, + /// The instruction accesses the SMAPI console directly. + DetectedConsoleAccess, + /// The instruction accesses the filesystem directly. DetectedFilesystemAccess, -- cgit From d932a11f51392cd42ab501185982af971f954c8d Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 24 Dec 2019 13:51:21 -0500 Subject: list broken dependencies first in 'skipped mods' list --- docs/release-notes.md | 1 + src/SMAPI/Framework/IModMetadata.cs | 4 +++ src/SMAPI/Framework/ModLoading/ModMetadata.cs | 21 ++++++++++++ src/SMAPI/Framework/SCore.cs | 48 +++++++++++++++++++-------- 4 files changed, 61 insertions(+), 13 deletions(-) (limited to 'src/SMAPI/Framework/ModLoading') diff --git a/docs/release-notes.md b/docs/release-notes.md index dc0f584d..d31b95e5 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -6,6 +6,7 @@ * For players: * Added friendly log message for save file-not-found errors. * Updated for the 'Force Off' gamepad mode added in Stardew Valley 1.4.1. + * The 'skipped mods' list now shows broken dependencies first, so it's easier to see which ones to fix first. * Fixed compatibility with Linux Mint 18 (thanks to techge!) and Arch Linux. * Fixed compatibility with Linux systems which have libhybris-utils installed. * Fixes for the bundled Console Commands mod: diff --git a/src/SMAPI/Framework/IModMetadata.cs b/src/SMAPI/Framework/IModMetadata.cs index 6ee7df69..37927482 100644 --- a/src/SMAPI/Framework/IModMetadata.cs +++ b/src/SMAPI/Framework/IModMetadata.cs @@ -105,6 +105,10 @@ namespace StardewModdingAPI.Framework /// Only return valid update keys. IEnumerable GetUpdateKeys(bool validOnly = true); + /// Get the mod IDs that must be installed to load this mod. + /// Whether to include optional dependencies. + IEnumerable GetRequiredModIds(bool includeOptional = false); + /// Whether the mod has at least one valid update key set. bool HasValidUpdateKeys(); diff --git a/src/SMAPI/Framework/ModLoading/ModMetadata.cs b/src/SMAPI/Framework/ModLoading/ModMetadata.cs index 7f788d17..0e90362e 100644 --- a/src/SMAPI/Framework/ModLoading/ModMetadata.cs +++ b/src/SMAPI/Framework/ModLoading/ModMetadata.cs @@ -188,6 +188,27 @@ namespace StardewModdingAPI.Framework.ModLoading } } + /// Get the mod IDs that must be installed to load this mod. + /// Whether to include optional dependencies. + public IEnumerable GetRequiredModIds(bool includeOptional = false) + { + HashSet required = new HashSet(StringComparer.InvariantCultureIgnoreCase); + + // yield dependencies + if (this.Manifest?.Dependencies != null) + { + foreach (var entry in this.Manifest?.Dependencies) + { + if ((entry.IsRequired || includeOptional) && required.Add(entry.UniqueID)) + yield return entry.UniqueID; + } + } + + // yield content pack parent + if (this.Manifest?.ContentPackFor?.UniqueID != null && required.Add(this.Manifest.ContentPackFor.UniqueID)) + yield return this.Manifest.ContentPackFor.UniqueID; + } + /// Whether the mod has at least one valid update key set. public bool HasValidUpdateKeys() { diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index c9c9d14a..a89c14d7 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -1046,26 +1046,48 @@ namespace StardewModdingAPI.Framework // log skipped mods if (skippedMods.Any()) { + // get logging logic + HashSet logged = new HashSet(); + void LogSkippedMod(IModMetadata mod, string errorReason, string errorDetails) + { + string message = $" - {mod.DisplayName}{(mod.Manifest?.Version != null ? " " + mod.Manifest.Version.ToString() : "")} because {errorReason}"; + + if (logged.Add($"{message}|{errorDetails}")) + { + this.Monitor.Log(message, LogLevel.Error); + if (errorDetails != null) + this.Monitor.Log($" ({errorDetails})", LogLevel.Trace); + } + } + + // find skipped dependencies + KeyValuePair>[] skippedDependencies; + { + HashSet skippedDependencyIds = new HashSet(StringComparer.InvariantCultureIgnoreCase); + HashSet skippedModIds = new HashSet(from mod in skippedMods where mod.Key.HasID() select mod.Key.Manifest.UniqueID, StringComparer.InvariantCultureIgnoreCase); + foreach (IModMetadata mod in skippedMods.Keys) + { + foreach (string requiredId in skippedModIds.Intersect(mod.GetRequiredModIds())) + skippedDependencyIds.Add(requiredId); + } + skippedDependencies = skippedMods.Where(p => p.Key.HasID() && skippedDependencyIds.Contains(p.Key.Manifest.UniqueID)).ToArray(); + } + + // log skipped mods this.Monitor.Log(" Skipped mods", LogLevel.Error); this.Monitor.Log(" " + "".PadRight(50, '-'), LogLevel.Error); this.Monitor.Log(" These mods could not be added to your game.", LogLevel.Error); this.Monitor.Newline(); - HashSet logged = new HashSet(); - foreach (var pair in skippedMods.OrderBy(p => p.Key.DisplayName)) + if (skippedDependencies.Any()) { - IModMetadata mod = pair.Key; - string errorReason = pair.Value.Item1; - string errorDetails = pair.Value.Item2; - string message = $" - {mod.DisplayName}{(mod.Manifest?.Version != null ? " " + mod.Manifest.Version.ToString() : "")} because {errorReason}"; - - if (!logged.Add($"{message}|{errorDetails}")) - continue; // skip duplicate messages (e.g. if multiple copies of the mod are installed) - - this.Monitor.Log(message, LogLevel.Error); - if (errorDetails != null) - this.Monitor.Log($" ({errorDetails})", LogLevel.Trace); + foreach (var pair in skippedDependencies.OrderBy(p => p.Key.DisplayName)) + LogSkippedMod(pair.Key, pair.Value.Item1, pair.Value.Item2); + this.Monitor.Newline(); } + + foreach (var pair in skippedMods.OrderBy(p => p.Key.DisplayName)) + LogSkippedMod(pair.Key, pair.Value.Item1, pair.Value.Item2); this.Monitor.Newline(); } -- cgit