list broken dependencies first in 'skipped mods' list

This commit is contained in:
Jesse Plamondon-Willard 2019-12-24 13:51:21 -05:00
parent 4c471ea215
commit d932a11f51
No known key found for this signature in database
GPG Key ID: CF8B1456B3E29F49
4 changed files with 61 additions and 13 deletions

View File

@ -6,6 +6,7 @@
* For players: * For players:
* Added friendly log message for save file-not-found errors. * Added friendly log message for save file-not-found errors.
* Updated for the 'Force Off' gamepad mode added in Stardew Valley 1.4.1. * 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 Mint 18 (thanks to techge!) and Arch Linux.
* Fixed compatibility with Linux systems which have libhybris-utils installed. * Fixed compatibility with Linux systems which have libhybris-utils installed.
* Fixes for the bundled Console Commands mod: * Fixes for the bundled Console Commands mod:

View File

@ -105,6 +105,10 @@ namespace StardewModdingAPI.Framework
/// <param name="validOnly">Only return valid update keys.</param> /// <param name="validOnly">Only return valid update keys.</param>
IEnumerable<UpdateKey> GetUpdateKeys(bool validOnly = true); IEnumerable<UpdateKey> GetUpdateKeys(bool validOnly = true);
/// <summary>Get the mod IDs that must be installed to load this mod.</summary>
/// <param name="includeOptional">Whether to include optional dependencies.</param>
IEnumerable<string> GetRequiredModIds(bool includeOptional = false);
/// <summary>Whether the mod has at least one valid update key set.</summary> /// <summary>Whether the mod has at least one valid update key set.</summary>
bool HasValidUpdateKeys(); bool HasValidUpdateKeys();

View File

@ -188,6 +188,27 @@ namespace StardewModdingAPI.Framework.ModLoading
} }
} }
/// <summary>Get the mod IDs that must be installed to load this mod.</summary>
/// <param name="includeOptional">Whether to include optional dependencies.</param>
public IEnumerable<string> GetRequiredModIds(bool includeOptional = false)
{
HashSet<string> required = new HashSet<string>(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;
}
/// <summary>Whether the mod has at least one valid update key set.</summary> /// <summary>Whether the mod has at least one valid update key set.</summary>
public bool HasValidUpdateKeys() public bool HasValidUpdateKeys()
{ {

View File

@ -1046,26 +1046,48 @@ namespace StardewModdingAPI.Framework
// log skipped mods // log skipped mods
if (skippedMods.Any()) if (skippedMods.Any())
{ {
// get logging logic
HashSet<string> logged = new HashSet<string>();
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<IModMetadata, Tuple<string, string>>[] skippedDependencies;
{
HashSet<string> skippedDependencyIds = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
HashSet<string> skippedModIds = new HashSet<string>(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(" Skipped mods", LogLevel.Error);
this.Monitor.Log(" " + "".PadRight(50, '-'), 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.Log(" These mods could not be added to your game.", LogLevel.Error);
this.Monitor.Newline(); this.Monitor.Newline();
HashSet<string> logged = new HashSet<string>(); if (skippedDependencies.Any())
foreach (var pair in skippedMods.OrderBy(p => p.Key.DisplayName))
{ {
IModMetadata mod = pair.Key; foreach (var pair in skippedDependencies.OrderBy(p => p.Key.DisplayName))
string errorReason = pair.Value.Item1; LogSkippedMod(pair.Key, pair.Value.Item1, pair.Value.Item2);
string errorDetails = pair.Value.Item2; this.Monitor.Newline();
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 skippedMods.OrderBy(p => p.Key.DisplayName))
LogSkippedMod(pair.Key, pair.Value.Item1, pair.Value.Item2);
this.Monitor.Newline(); this.Monitor.Newline();
} }