diff options
-rw-r--r-- | docs/release-notes.md | 1 | ||||
-rw-r--r-- | src/SMAPI.Web/Controllers/ModsApiController.cs | 53 | ||||
-rw-r--r-- | src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecord.cs | 9 |
3 files changed, 49 insertions, 14 deletions
diff --git a/docs/release-notes.md b/docs/release-notes.md index 6af726a1..12feb68a 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -4,6 +4,7 @@ * Added support for subfolders under `Mods`, for players who want to organise their mods. * Moved most SMAPI files into a `smapi-internal` subfolder. * Moved save backups into a `save-backups` subfolder (instead of `Mods/SaveBackup/backups`). Note that previous backups will be deleted when you update. + * Update checks now work even when the mod has no update keys in most cases. * Fixed installer duplicating bundled mods if you moved them after the last install. * Fixed crash when a mod manifest is corrupted. * Fixed error-handling when initialising paths. diff --git a/src/SMAPI.Web/Controllers/ModsApiController.cs b/src/SMAPI.Web/Controllers/ModsApiController.cs index 18d55665..3d05da16 100644 --- a/src/SMAPI.Web/Controllers/ModsApiController.cs +++ b/src/SMAPI.Web/Controllers/ModsApiController.cs @@ -115,15 +115,10 @@ namespace StardewModdingAPI.Web.Controllers /// <returns>Returns the mod data if found, else <c>null</c>.</returns> private async Task<ModEntryModel> GetModData(ModSearchEntryModel search, WikiCompatibilityEntry[] wikiData, bool includeExtendedMetadata) { - // resolve update keys - var updateKeys = new HashSet<string>(search.UpdateKeys ?? new string[0], StringComparer.InvariantCultureIgnoreCase); + // crossreference data ModDataRecord record = this.ModDatabase.Get(search.ID); - if (record?.Fields != null) - { - string defaultUpdateKey = record.Fields.FirstOrDefault(p => p.Key == ModDataFieldKey.UpdateKey && p.IsDefault)?.Value; - if (!string.IsNullOrWhiteSpace(defaultUpdateKey)) - updateKeys.Add(defaultUpdateKey); - } + WikiCompatibilityEntry wikiEntry = wikiData.FirstOrDefault(entry => entry.ID.Contains(search.ID.Trim(), StringComparer.InvariantCultureIgnoreCase)); + string[] updateKeys = this.GetUpdateKeys(search.UpdateKeys, record, wikiEntry).ToArray(); // get latest versions ModEntryModel result = new ModEntryModel { ID = search.ID }; @@ -166,7 +161,6 @@ namespace StardewModdingAPI.Web.Controllers } // get unofficial version - WikiCompatibilityEntry wikiEntry = wikiData.FirstOrDefault(entry => entry.ID.Contains(result.ID.Trim(), StringComparer.InvariantCultureIgnoreCase)); if (wikiEntry?.UnofficialVersion != null && this.IsNewer(wikiEntry.UnofficialVersion, result.Main?.Version) && this.IsNewer(wikiEntry.UnofficialVersion, result.Optional?.Version)) result.Unofficial = new ModEntryVersionModel(wikiEntry.UnofficialVersion, this.WikiCompatibilityPageUrl); @@ -229,7 +223,7 @@ namespace StardewModdingAPI.Web.Controllers private async Task<WikiCompatibilityEntry[]> GetWikiDataAsync() { ModToolkit toolkit = new ModToolkit(); - return await this.Cache.GetOrCreateAsync($"_wiki", async entry => + return await this.Cache.GetOrCreateAsync("_wiki", async entry => { try { @@ -273,11 +267,42 @@ namespace StardewModdingAPI.Web.Controllers }); } - /// <summary>Get the requested API version.</summary> - private ISemanticVersion GetApiVersion() + /// <summary>Get update keys based on the available mod metadata, while maintaining the precedence order.</summary> + /// <param name="specifiedKeys">The specified update keys.</param> + /// <param name="record">The mod's entry in SMAPI's internal database.</param> + /// <param name="entry">The mod's entry in the wiki list.</param> + public IEnumerable<string> GetUpdateKeys(string[] specifiedKeys, ModDataRecord record, WikiCompatibilityEntry entry) { - string actualVersion = (string)this.RouteData.Values["version"]; - return new SemanticVersion(actualVersion); + IEnumerable<string> GetRaw() + { + // specified update keys + if (specifiedKeys != null) + { + foreach (string key in specifiedKeys) + yield return key?.Trim(); + } + + // default update key + string defaultKey = record?.GetDefaultUpdateKey(); + if (defaultKey != null) + yield return defaultKey; + + // wiki metadata + if (entry != null) + { + if (entry.NexusID.HasValue) + yield return $"Nexus:{entry.NexusID}"; + if (entry.ChucklefishID.HasValue) + yield return $"Chucklefish:{entry.ChucklefishID}"; + } + } + + HashSet<string> seen = new HashSet<string>(StringComparer.InvariantCulture); + foreach (string key in GetRaw()) + { + if (!string.IsNullOrWhiteSpace(key) && seen.Add(key)) + yield return key; + } } } } diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecord.cs b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecord.cs index 82ac8837..3949f7dc 100644 --- a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecord.cs +++ b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecord.cs @@ -96,6 +96,15 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData .Distinct(); } + /// <summary>Get the default update key for this mod, if any.</summary> + public string GetDefaultUpdateKey() + { + string updateKey = this.Fields.FirstOrDefault(p => p.Key == ModDataFieldKey.UpdateKey && p.IsDefault)?.Value; + return !string.IsNullOrWhiteSpace(updateKey) + ? updateKey + : null; + } + /// <summary>Get a parsed representation of the <see cref="ModDataRecord.Fields"/> which match a given manifest.</summary> /// <param name="manifest">The manifest to match.</param> public ModDataRecordVersionedFields GetVersionedFields(IManifest manifest) |