diff options
author | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2020-09-04 22:02:59 -0400 |
---|---|---|
committer | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2020-09-04 22:02:59 -0400 |
commit | 4088f4cb2bfe777cf6f86ac5fbf64f7d67565057 (patch) | |
tree | 859199135d654f7bf6b356a8b20ff5259bf51025 /src/SMAPI/Framework/ModLoading | |
parent | f57feb7319725513fadde8b14d55f4e8e4b82c24 (diff) | |
download | SMAPI-4088f4cb2bfe777cf6f86ac5fbf64f7d67565057.tar.gz SMAPI-4088f4cb2bfe777cf6f86ac5fbf64f7d67565057.tar.bz2 SMAPI-4088f4cb2bfe777cf6f86ac5fbf64f7d67565057.zip |
simplify error shown for duplicate mods
Diffstat (limited to 'src/SMAPI/Framework/ModLoading')
-rw-r--r-- | src/SMAPI/Framework/ModLoading/ModFailReason.cs | 27 | ||||
-rw-r--r-- | src/SMAPI/Framework/ModLoading/ModMetadata.cs | 14 | ||||
-rw-r--r-- | src/SMAPI/Framework/ModLoading/ModResolver.cs | 48 |
3 files changed, 64 insertions, 25 deletions
diff --git a/src/SMAPI/Framework/ModLoading/ModFailReason.cs b/src/SMAPI/Framework/ModLoading/ModFailReason.cs new file mode 100644 index 00000000..cd4623e7 --- /dev/null +++ b/src/SMAPI/Framework/ModLoading/ModFailReason.cs @@ -0,0 +1,27 @@ +namespace StardewModdingAPI.Framework.ModLoading +{ + /// <summary>Indicates why a mod could not be loaded.</summary> + internal enum ModFailReason + { + /// <summary>The mod has been disabled by prefixing its folder with a dot.</summary> + DisabledByDotConvention, + + /// <summary>Multiple copies of the mod are installed.</summary> + Duplicate, + + /// <summary>The mod has incompatible code instructions, needs a newer SMAPI version, or is marked 'assume broken' in the SMAPI metadata list.</summary> + Incompatible, + + /// <summary>The mod's manifest is missing or invalid.</summary> + InvalidManifest, + + /// <summary>The mod was deemed compatible, but SMAPI failed when it tried to load it.</summary> + LoadFailed, + + /// <summary>The mod requires other mods which aren't installed, or its dependencies have a circular reference.</summary> + MissingDependencies, + + /// <summary>The mod is marked obsolete in the SMAPI metadata list.</summary> + Obsolete + } +} diff --git a/src/SMAPI/Framework/ModLoading/ModMetadata.cs b/src/SMAPI/Framework/ModLoading/ModMetadata.cs index e793b0cd..18d2b112 100644 --- a/src/SMAPI/Framework/ModLoading/ModMetadata.cs +++ b/src/SMAPI/Framework/ModLoading/ModMetadata.cs @@ -38,6 +38,9 @@ namespace StardewModdingAPI.Framework.ModLoading public ModMetadataStatus Status { get; private set; } /// <inheritdoc /> + public ModFailReason? FailReason { get; private set; } + + /// <inheritdoc /> public ModWarning Warnings { get; private set; } /// <inheritdoc /> @@ -93,9 +96,18 @@ namespace StardewModdingAPI.Framework.ModLoading } /// <inheritdoc /> - public IModMetadata SetStatus(ModMetadataStatus status, string error = null, string errorDetails = null) + public IModMetadata SetStatusFound() + { + this.SetStatus(ModMetadataStatus.Found, ModFailReason.Incompatible, null); + this.FailReason = null; + return this; + } + + /// <inheritdoc /> + public IModMetadata SetStatus(ModMetadataStatus status, ModFailReason reason, string error, string errorDetails = null) { this.Status = status; + this.FailReason = reason; this.Error = error; this.ErrorDetails = errorDetails; return this; diff --git a/src/SMAPI/Framework/ModLoading/ModResolver.cs b/src/SMAPI/Framework/ModLoading/ModResolver.cs index 8bbeb2a3..08df7b76 100644 --- a/src/SMAPI/Framework/ModLoading/ModResolver.cs +++ b/src/SMAPI/Framework/ModLoading/ModResolver.cs @@ -43,8 +43,13 @@ namespace StardewModdingAPI.Framework.ModLoading ? ModMetadataStatus.Found : ModMetadataStatus.Failed; - yield return new ModMetadata(folder.DisplayName, folder.Directory.FullName, rootPath, manifest, dataRecord, isIgnored: shouldIgnore) - .SetStatus(status, shouldIgnore ? "disabled by dot convention" : folder.ManifestParseErrorText); + var metadata = new ModMetadata(folder.DisplayName, folder.Directory.FullName, rootPath, manifest, dataRecord, isIgnored: shouldIgnore); + if (shouldIgnore) + metadata.SetStatus(status, ModFailReason.DisabledByDotConvention, "disabled by dot convention"); + else + metadata.SetStatus(status, ModFailReason.InvalidManifest, folder.ManifestParseErrorText); + + yield return metadata; } } @@ -67,7 +72,7 @@ namespace StardewModdingAPI.Framework.ModLoading switch (mod.DataRecord?.Status) { case ModStatus.Obsolete: - mod.SetStatus(ModMetadataStatus.Failed, $"it's obsolete: {mod.DataRecord.StatusReasonPhrase}"); + mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.Obsolete, $"it's obsolete: {mod.DataRecord.StatusReasonPhrase}"); continue; case ModStatus.AssumeBroken: @@ -97,7 +102,7 @@ namespace StardewModdingAPI.Framework.ModLoading error += $"version newer than {mod.DataRecord.StatusUpperVersion}"; error += " at " + string.Join(" or ", updateUrls); - mod.SetStatus(ModMetadataStatus.Failed, error); + mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.Incompatible, error); } continue; } @@ -105,7 +110,7 @@ namespace StardewModdingAPI.Framework.ModLoading // validate SMAPI version if (mod.Manifest.MinimumApiVersion?.IsNewerThan(apiVersion) == true) { - mod.SetStatus(ModMetadataStatus.Failed, $"it needs SMAPI {mod.Manifest.MinimumApiVersion} or later. Please update SMAPI to the latest version to use this mod."); + mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.Incompatible, $"it needs SMAPI {mod.Manifest.MinimumApiVersion} or later. Please update SMAPI to the latest version to use this mod."); continue; } @@ -117,12 +122,12 @@ namespace StardewModdingAPI.Framework.ModLoading // validate field presence if (!hasDll && !isContentPack) { - mod.SetStatus(ModMetadataStatus.Failed, $"its manifest has no {nameof(IManifest.EntryDll)} or {nameof(IManifest.ContentPackFor)} field; must specify one."); + mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.InvalidManifest, $"its manifest has no {nameof(IManifest.EntryDll)} or {nameof(IManifest.ContentPackFor)} field; must specify one."); continue; } if (hasDll && isContentPack) { - mod.SetStatus(ModMetadataStatus.Failed, $"its manifest sets both {nameof(IManifest.EntryDll)} and {nameof(IManifest.ContentPackFor)}, which are mutually exclusive."); + mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.InvalidManifest, $"its manifest sets both {nameof(IManifest.EntryDll)} and {nameof(IManifest.ContentPackFor)}, which are mutually exclusive."); continue; } @@ -132,14 +137,14 @@ namespace StardewModdingAPI.Framework.ModLoading // invalid filename format if (mod.Manifest.EntryDll.Intersect(Path.GetInvalidFileNameChars()).Any()) { - mod.SetStatus(ModMetadataStatus.Failed, $"its manifest has invalid filename '{mod.Manifest.EntryDll}' for the EntryDLL field."); + mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.InvalidManifest, $"its manifest has invalid filename '{mod.Manifest.EntryDll}' for the EntryDLL field."); continue; } // invalid path if (!File.Exists(Path.Combine(mod.DirectoryPath, mod.Manifest.EntryDll))) { - mod.SetStatus(ModMetadataStatus.Failed, $"its DLL '{mod.Manifest.EntryDll}' doesn't exist."); + mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.InvalidManifest, $"its DLL '{mod.Manifest.EntryDll}' doesn't exist."); continue; } @@ -147,7 +152,7 @@ namespace StardewModdingAPI.Framework.ModLoading string actualFilename = new DirectoryInfo(mod.DirectoryPath).GetFiles(mod.Manifest.EntryDll).FirstOrDefault()?.Name; if (actualFilename != mod.Manifest.EntryDll) { - mod.SetStatus(ModMetadataStatus.Failed, $"its {nameof(IManifest.EntryDll)} value '{mod.Manifest.EntryDll}' doesn't match the actual file capitalization '{actualFilename}'. The capitalization must match for crossplatform compatibility."); + mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.InvalidManifest, $"its {nameof(IManifest.EntryDll)} value '{mod.Manifest.EntryDll}' doesn't match the actual file capitalization '{actualFilename}'. The capitalization must match for crossplatform compatibility."); continue; } } @@ -158,7 +163,7 @@ namespace StardewModdingAPI.Framework.ModLoading // invalid content pack ID if (string.IsNullOrWhiteSpace(mod.Manifest.ContentPackFor.UniqueID)) { - mod.SetStatus(ModMetadataStatus.Failed, $"its manifest declares {nameof(IManifest.ContentPackFor)} without its required {nameof(IManifestContentPackFor.UniqueID)} field."); + mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.InvalidManifest, $"its manifest declares {nameof(IManifest.ContentPackFor)} without its required {nameof(IManifestContentPackFor.UniqueID)} field."); continue; } } @@ -177,14 +182,14 @@ namespace StardewModdingAPI.Framework.ModLoading if (missingFields.Any()) { - mod.SetStatus(ModMetadataStatus.Failed, $"its manifest is missing required fields ({string.Join(", ", missingFields)})."); + mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.InvalidManifest, $"its manifest is missing required fields ({string.Join(", ", missingFields)})."); continue; } } // validate ID format if (!PathUtilities.IsSlug(mod.Manifest.UniqueID)) - mod.SetStatus(ModMetadataStatus.Failed, "its manifest specifies an invalid ID (IDs must only contain letters, numbers, underscores, periods, or hyphens)."); + mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.InvalidManifest, "its manifest specifies an invalid ID (IDs must only contain letters, numbers, underscores, periods, or hyphens)."); } // validate IDs are unique @@ -199,13 +204,8 @@ namespace StardewModdingAPI.Framework.ModLoading if (mod.Status == ModMetadataStatus.Failed) continue; // don't replace metadata error - string folderList = string.Join(", ", - from entry in @group - let relativePath = entry.GetRelativePathWithRoot() - orderby relativePath - select $"{relativePath} ({entry.Manifest.Version})" - ); - mod.SetStatus(ModMetadataStatus.Failed, $"you have multiple copies of this mod installed. Found in folders: {folderList}."); + string folderList = string.Join(", ", group.Select(p => p.GetRelativePathWithRoot()).OrderBy(p => p)); + mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.Duplicate, $"you have multiple copies of this mod installed. To fix this, delete these folders and reinstall the mod: {folderList}."); } } } @@ -298,7 +298,7 @@ namespace StardewModdingAPI.Framework.ModLoading if (failedModNames.Any()) { sortedMods.Push(mod); - mod.SetStatus(ModMetadataStatus.Failed, $"it requires mods which aren't installed ({string.Join(", ", failedModNames)})."); + mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.MissingDependencies, $"it requires mods which aren't installed ({string.Join(", ", failedModNames)})."); return states[mod] = ModDependencyStatus.Failed; } } @@ -315,7 +315,7 @@ namespace StardewModdingAPI.Framework.ModLoading if (failedLabels.Any()) { sortedMods.Push(mod); - mod.SetStatus(ModMetadataStatus.Failed, $"it needs newer versions of some mods: {string.Join(", ", failedLabels)}."); + mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.MissingDependencies, $"it needs newer versions of some mods: {string.Join(", ", failedLabels)}."); return states[mod] = ModDependencyStatus.Failed; } } @@ -338,7 +338,7 @@ namespace StardewModdingAPI.Framework.ModLoading if (states[requiredMod] == ModDependencyStatus.Checking) { sortedMods.Push(mod); - mod.SetStatus(ModMetadataStatus.Failed, $"its dependencies have a circular reference: {string.Join(" => ", subchain.Select(p => p.DisplayName))} => {requiredMod.DisplayName})."); + mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.MissingDependencies, $"its dependencies have a circular reference: {string.Join(" => ", subchain.Select(p => p.DisplayName))} => {requiredMod.DisplayName})."); return states[mod] = ModDependencyStatus.Failed; } @@ -354,7 +354,7 @@ namespace StardewModdingAPI.Framework.ModLoading // failed, which means this mod can't be loaded either case ModDependencyStatus.Failed: sortedMods.Push(mod); - mod.SetStatus(ModMetadataStatus.Failed, $"it needs the '{requiredMod.DisplayName}' mod, which couldn't be loaded."); + mod.SetStatus(ModMetadataStatus.Failed, ModFailReason.MissingDependencies, $"it needs the '{requiredMod.DisplayName}' mod, which couldn't be loaded."); return states[mod] = ModDependencyStatus.Failed; // unexpected status |