diff options
-rw-r--r-- | docs/release-notes.md | 1 | ||||
-rw-r--r-- | src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs | 2 | ||||
-rw-r--r-- | src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs | 3 | ||||
-rw-r--r-- | src/SMAPI.Web/Controllers/ModsApiController.cs | 103 |
4 files changed, 69 insertions, 40 deletions
diff --git a/docs/release-notes.md b/docs/release-notes.md index 5813298d..90835fa3 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -16,6 +16,7 @@ * Migrated to Harmony 2.0 (see [_migrate to Harmony 2.0_](https://stardewvalleywiki.com/Modding:Migrate_to_Harmony_2.0) for more info). * Added [update subkeys](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Update_checks#Update_subkeys). * Added `Multiplayer.PeerConnected` event. + * Added ability to override update keys from the compatibility list. * Added `harmony_summary` console command which lists all current Harmony patches, optionally with a search filter. * Harmony mods which use the `[HarmonyPatch(type)]` attribute now work crossplatform. Previously SMAPI couldn't rewrite types in custom attributes for compatibility. * Improved mod rewriting for compatibility: diff --git a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs index c829c0f4..34e2e1b8 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs @@ -105,6 +105,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki string pullRequestUrl = this.GetAttribute(node, "data-pr"); IDictionary<string, string> mapLocalVersions = this.GetAttributeAsVersionMapping(node, "data-map-local-versions"); IDictionary<string, string> mapRemoteVersions = this.GetAttributeAsVersionMapping(node, "data-map-remote-versions"); + string[] changeUpdateKeys = this.GetAttributeAsCsv(node, "data-change-update-keys"); // parse stable compatibility WikiCompatibilityInfo compatibility = new WikiCompatibilityInfo @@ -153,6 +154,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki Warnings = warnings, PullRequestUrl = pullRequestUrl, DevNote = devNote, + ChangeUpdateKeys = changeUpdateKeys, MapLocalVersions = mapLocalVersions, MapRemoteVersions = mapRemoteVersions, Anchor = anchor diff --git a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs index 474dce3d..21466c6a 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs @@ -63,6 +63,9 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki /// <summary>Special notes intended for developers who maintain unofficial updates or submit pull requests. </summary> public string DevNote { get; set; } + /// <summary>Update keys to add (optionally prefixed by '+') or remove (prefixed by '-').</summary> + public string[] ChangeUpdateKeys { get; set; } + /// <summary>Maps local versions to a semantic version for update checks.</summary> public IDictionary<string, string> MapLocalVersions { get; set; } diff --git a/src/SMAPI.Web/Controllers/ModsApiController.cs b/src/SMAPI.Web/Controllers/ModsApiController.cs index 028fc613..db669bf9 100644 --- a/src/SMAPI.Web/Controllers/ModsApiController.cs +++ b/src/SMAPI.Web/Controllers/ModsApiController.cs @@ -280,56 +280,79 @@ namespace StardewModdingAPI.Web.Controllers /// <param name="entry">The mod's entry in the wiki list.</param> private IEnumerable<UpdateKey> GetUpdateKeys(string[] specifiedKeys, ModDataRecord record, WikiModEntry entry) { - // get every update key (including duplicates) - IEnumerable<string> GetRaw() + // get unique update keys + List<UpdateKey> updateKeys = this.GetUnfilteredUpdateKeys(specifiedKeys, record, entry) + .Select(UpdateKey.Parse) + .Distinct() + .ToList(); + + // apply remove overrides from wiki + { + var removeKeys = new HashSet<UpdateKey>( + from key in entry?.ChangeUpdateKeys ?? new string[0] + where key.StartsWith('-') + select UpdateKey.Parse(key.Substring(1)) + ); + if (removeKeys.Any()) + updateKeys.RemoveAll(removeKeys.Contains); + } + + // if the list has both an update key (like "Nexus:2400") and subkey (like "Nexus:2400@subkey") for the same page, the subkey takes priority { - // specified update keys - if (specifiedKeys != null) + var removeKeys = new HashSet<UpdateKey>(); + foreach (var key in updateKeys) { - foreach (string key in specifiedKeys) - { - if (!string.IsNullOrWhiteSpace(key)) - yield return key.Trim(); - } + if (key.Subkey != null) + removeKeys.Add(new UpdateKey(key.Site, key.ID, null)); } + if (removeKeys.Any()) + updateKeys.RemoveAll(removeKeys.Contains); + } + + return updateKeys; + } + + /// <summary>Get every available update key based on the available mod metadata, including duplicates and keys which should be filtered.</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> + private IEnumerable<string> GetUnfilteredUpdateKeys(string[] specifiedKeys, ModDataRecord record, WikiModEntry entry) + { + // specified update keys + foreach (string key in specifiedKeys ?? Array.Empty<string>()) + { + if (!string.IsNullOrWhiteSpace(key)) + yield return key.Trim(); + } - // default update key + // default update key + { string defaultKey = record?.GetDefaultUpdateKey(); if (!string.IsNullOrWhiteSpace(defaultKey)) yield return defaultKey; - - // wiki metadata - if (entry != null) - { - if (entry.NexusID.HasValue) - yield return UpdateKey.GetString(ModSiteKey.Nexus, entry.NexusID.ToString()); - if (entry.ModDropID.HasValue) - yield return UpdateKey.GetString(ModSiteKey.ModDrop, entry.ModDropID.ToString()); - if (entry.CurseForgeID.HasValue) - yield return UpdateKey.GetString(ModSiteKey.CurseForge, entry.CurseForgeID.ToString()); - if (entry.ChucklefishID.HasValue) - yield return UpdateKey.GetString(ModSiteKey.Chucklefish, entry.ChucklefishID.ToString()); - } } - // get unique update keys - var subkeyRoots = new HashSet<UpdateKey>(); - List<UpdateKey> updateKeys = GetRaw() - .Select(raw => - { - var key = UpdateKey.Parse(raw); - if (key.Subkey != null) - subkeyRoots.Add(new UpdateKey(key.Site, key.ID, null)); - return key; - }) - .Distinct() - .ToList(); - - // if the list has both an update key (like "Nexus:2400") and subkey (like "Nexus:2400@subkey") for the same page, the subkey takes priority - if (subkeyRoots.Any()) - updateKeys.RemoveAll(subkeyRoots.Contains); + // wiki metadata + if (entry != null) + { + if (entry.NexusID.HasValue) + yield return UpdateKey.GetString(ModSiteKey.Nexus, entry.NexusID.ToString()); + if (entry.ModDropID.HasValue) + yield return UpdateKey.GetString(ModSiteKey.ModDrop, entry.ModDropID.ToString()); + if (entry.CurseForgeID.HasValue) + yield return UpdateKey.GetString(ModSiteKey.CurseForge, entry.CurseForgeID.ToString()); + if (entry.ChucklefishID.HasValue) + yield return UpdateKey.GetString(ModSiteKey.Chucklefish, entry.ChucklefishID.ToString()); + } - return updateKeys; + // overrides from wiki + foreach (string key in entry?.ChangeUpdateKeys ?? Array.Empty<string>()) + { + if (key.StartsWith('+')) + yield return key.Substring(1); + else if (!key.StartsWith("-")) + yield return key; + } } } } |