summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryModel.cs18
-rw-r--r--src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs24
-rw-r--r--src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs11
-rw-r--r--src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchModel.cs (renamed from src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs)18
-rw-r--r--src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs8
-rw-r--r--src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs26
-rw-r--r--src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs7
-rw-r--r--src/SMAPI.Toolkit/Framework/ModData/ModDataModel.cs6
-rw-r--r--src/SMAPI.Toolkit/Framework/ModData/ModDataRecord.cs31
-rw-r--r--src/SMAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs24
-rw-r--r--src/SMAPI.Web/Controllers/ModsApiController.cs162
-rw-r--r--src/SMAPI.Web/Framework/Caching/Wiki/CachedWikiMod.cs24
-rw-r--r--src/SMAPI.Web/Views/Index/Privacy.cshtml2
-rw-r--r--src/SMAPI.Web/wwwroot/SMAPI.metadata.json97
-rw-r--r--src/SMAPI/Framework/SCore.cs57
15 files changed, 276 insertions, 239 deletions
diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryModel.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryModel.cs
index 8a9c0a25..f1bcfccc 100644
--- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryModel.cs
+++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryModel.cs
@@ -1,3 +1,5 @@
+using System;
+
namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
{
/// <summary>Metadata about a mod.</summary>
@@ -9,23 +11,31 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
/// <summary>The mod's unique ID (if known).</summary>
public string ID { get; set; }
+ /// <summary>The update version recommended by the web API based on its version update and mapping rules.</summary>
+ public ModEntryVersionModel SuggestedUpdate { get; set; }
+
+ /// <summary>Optional extended data which isn't needed for update checks.</summary>
+ public ModExtendedMetadataModel Metadata { get; set; }
+
/// <summary>The main version.</summary>
+ [Obsolete]
public ModEntryVersionModel Main { get; set; }
/// <summary>The latest optional version, if newer than <see cref="Main"/>.</summary>
+ [Obsolete]
public ModEntryVersionModel Optional { get; set; }
/// <summary>The latest unofficial version, if newer than <see cref="Main"/> and <see cref="Optional"/>.</summary>
+ [Obsolete]
public ModEntryVersionModel Unofficial { get; set; }
/// <summary>The latest unofficial version for the current Stardew Valley or SMAPI beta, if any (see <see cref="HasBetaInfo"/>).</summary>
+ [Obsolete]
public ModEntryVersionModel UnofficialForBeta { get; set; }
- /// <summary>Optional extended data which isn't needed for update checks.</summary>
- public ModExtendedMetadataModel Metadata { get; set; }
-
/// <summary>Whether a Stardew Valley or SMAPI beta which affects mod compatibility is in progress. If this is true, <see cref="UnofficialForBeta"/> should be used for beta versions of SMAPI instead of <see cref="Unofficial"/>.</summary>
- public bool HasBetaInfo { get; set; }
+ [Obsolete]
+ public bool? HasBetaInfo { get; set; }
/// <summary>The errors that occurred while fetching update data.</summary>
public string[] Errors { get; set; } = new string[0];
diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs
index 8074210c..4a697585 100644
--- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs
+++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs
@@ -46,6 +46,17 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
/// <summary>The custom mod page URL (if applicable).</summary>
public string CustomUrl { get; set; }
+ /// <summary>The main version.</summary>
+ public ModEntryVersionModel Main { get; set; }
+
+ /// <summary>The latest optional version, if newer than <see cref="Main"/>.</summary>
+ public ModEntryVersionModel Optional { get; set; }
+
+ /// <summary>The latest unofficial version, if newer than <see cref="Main"/> and <see cref="Optional"/>.</summary>
+ public ModEntryVersionModel Unofficial { get; set; }
+
+ /// <summary>The latest unofficial version for the current Stardew Valley or SMAPI beta, if any (see <see cref="HasBetaInfo"/>).</summary>
+ public ModEntryVersionModel UnofficialForBeta { get; set; }
/****
** Stable compatibility
@@ -60,7 +71,6 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
/// <summary>The game or SMAPI version which broke this mod, if applicable.</summary>
public string BrokeIn { get; set; }
-
/****
** Beta compatibility
****/
@@ -84,8 +94,18 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
/// <summary>Construct an instance.</summary>
/// <param name="wiki">The mod metadata from the wiki (if available).</param>
/// <param name="db">The mod metadata from SMAPI's internal DB (if available).</param>
- public ModExtendedMetadataModel(WikiModEntry wiki, ModDataRecord db)
+ /// <param name="main">The main version.</param>
+ /// <param name="optional">The latest optional version, if newer than <paramref name="main"/>.</param>
+ /// <param name="unofficial">The latest unofficial version, if newer than <paramref name="main"/> and <paramref name="optional"/>.</param>
+ /// <param name="unofficialForBeta">The latest unofficial version for the current Stardew Valley or SMAPI beta, if any.</param>
+ public ModExtendedMetadataModel(WikiModEntry wiki, ModDataRecord db, ModEntryVersionModel main, ModEntryVersionModel optional, ModEntryVersionModel unofficial, ModEntryVersionModel unofficialForBeta)
{
+ // versions
+ this.Main = main;
+ this.Optional = optional;
+ this.Unofficial = unofficial;
+ this.UnofficialForBeta = unofficialForBeta;
+
// wiki data
if (wiki != null)
{
diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs
index 886cd5a1..bf81e102 100644
--- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs
+++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs
@@ -12,6 +12,12 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
/// <summary>The namespaced mod update keys (if available).</summary>
public string[] UpdateKeys { get; set; }
+ /// <summary>The mod version installed by the local player. This is used for version mapping in some cases.</summary>
+ public ISemanticVersion InstalledVersion { get; set; }
+
+ /// <summary>Whether the installed version is broken or could not be loaded.</summary>
+ public bool IsBroken { get; set; }
+
/*********
** Public methods
@@ -24,10 +30,13 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
/// <summary>Construct an instance.</summary>
/// <param name="id">The unique mod ID.</param>
+ /// <param name="installedVersion">The version installed by the local player. This is used for version mapping in some cases.</param>
/// <param name="updateKeys">The namespaced mod update keys (if available).</param>
- public ModSearchEntryModel(string id, string[] updateKeys)
+ /// <param name="isBroken">Whether the installed version is broken or could not be loaded.</param>
+ public ModSearchEntryModel(string id, ISemanticVersion installedVersion, string[] updateKeys, bool isBroken = false)
{
this.ID = id;
+ this.InstalledVersion = installedVersion;
this.UpdateKeys = updateKeys ?? new string[0];
}
}
diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchModel.cs
index a2eaad16..73698173 100644
--- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs
+++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchModel.cs
@@ -1,4 +1,5 @@
using System.Linq;
+using StardewModdingAPI.Toolkit.Utilities;
namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
{
@@ -14,6 +15,15 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
/// <summary>Whether to include extended metadata for each mod.</summary>
public bool IncludeExtendedMetadata { get; set; }
+ /// <summary>The SMAPI version installed by the player. This is used for version mapping in some cases.</summary>
+ public ISemanticVersion ApiVersion { get; set; }
+
+ /// <summary>The Stardew Valley version installed by the player.</summary>
+ public ISemanticVersion GameVersion { get; set; }
+
+ /// <summary>The OS on which the player plays.</summary>
+ public Platform? Platform { get; set; }
+
/*********
** Public methods
@@ -26,10 +36,16 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
/// <summary>Construct an instance.</summary>
/// <param name="mods">The mods to search.</param>
+ /// <param name="apiVersion">The SMAPI version installed by the player. If this is null, the API won't provide a recommended update.</param>
+ /// <param name="gameVersion">The Stardew Valley version installed by the player.</param>
+ /// <param name="platform">The OS on which the player plays.</param>
/// <param name="includeExtendedMetadata">Whether to include extended metadata for each mod.</param>
- public ModSearchModel(ModSearchEntryModel[] mods, bool includeExtendedMetadata)
+ public ModSearchModel(ModSearchEntryModel[] mods, ISemanticVersion apiVersion, ISemanticVersion gameVersion, Platform platform, bool includeExtendedMetadata)
{
this.Mods = mods.ToArray();
+ this.ApiVersion = apiVersion;
+ this.GameVersion = gameVersion;
+ this.Platform = platform;
this.IncludeExtendedMetadata = includeExtendedMetadata;
}
}
diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs
index 80c8f62b..f0a7c82a 100644
--- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs
+++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Net;
using Newtonsoft.Json;
using StardewModdingAPI.Toolkit.Serialization;
+using StardewModdingAPI.Toolkit.Utilities;
namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
{
@@ -37,12 +38,15 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
/// <summary>Get metadata about a set of mods from the web API.</summary>
/// <param name="mods">The mod keys for which to fetch the latest version.</param>
+ /// <param name="apiVersion">The SMAPI version installed by the player. If this is null, the API won't provide a recommended update.</param>
+ /// <param name="gameVersion">The Stardew Valley version installed by the player.</param>
+ /// <param name="platform">The OS on which the player plays.</param>
/// <param name="includeExtendedMetadata">Whether to include extended metadata for each mod.</param>
- public IDictionary<string, ModEntryModel> GetModInfo(ModSearchEntryModel[] mods, bool includeExtendedMetadata = false)
+ public IDictionary<string, ModEntryModel> GetModInfo(ModSearchEntryModel[] mods, ISemanticVersion apiVersion, ISemanticVersion gameVersion, Platform platform, bool includeExtendedMetadata = false)
{
return this.Post<ModSearchModel, ModEntryModel[]>(
$"v{this.Version}/mods",
- new ModSearchModel(mods, includeExtendedMetadata)
+ new ModSearchModel(mods, apiVersion, gameVersion, platform, includeExtendedMetadata)
).ToDictionary(p => p.ID);
}
diff --git a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs
index 610e14f1..384f23fc 100644
--- a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs
+++ b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs
@@ -102,6 +102,8 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
string anchor = this.GetAttribute(node, "id");
string contentPackFor = this.GetAttribute(node, "data-content-pack-for");
string devNote = this.GetAttribute(node, "data-dev-note");
+ IDictionary<string, string> mapLocalVersions = this.GetAttributeAsVersionMapping(node, "data-map-local-versions");
+ IDictionary<string, string> mapRemoteVersions = this.GetAttributeAsVersionMapping(node, "data-map-remote-versions");
// parse stable compatibility
WikiCompatibilityInfo compatibility = new WikiCompatibilityInfo
@@ -159,6 +161,8 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
Warnings = warnings,
MetadataLinks = metadataLinks.ToArray(),
DevNote = devNote,
+ MapLocalVersions = mapLocalVersions,
+ MapRemoteVersions = mapRemoteVersions,
Anchor = anchor
};
}
@@ -223,6 +227,28 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
return null;
}
+ /// <summary>Get an attribute value and parse it as a version mapping.</summary>
+ /// <param name="element">The element whose attributes to read.</param>
+ /// <param name="name">The attribute name.</param>
+ private IDictionary<string, string> GetAttributeAsVersionMapping(HtmlNode element, string name)
+ {
+ // get raw value
+ string raw = this.GetAttribute(element, name);
+ if (raw?.Contains("→") != true)
+ return null;
+
+ // parse
+ // Specified on the wiki in the form "remote version → mapped version; another remote version → mapped version"
+ IDictionary<string, string> map = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
+ foreach (string pair in raw.Split(';'))
+ {
+ string[] versions = pair.Split('→');
+ if (versions.Length == 2 && !string.IsNullOrWhiteSpace(versions[0]) && !string.IsNullOrWhiteSpace(versions[1]))
+ map[versions[0].Trim()] = versions[1].Trim();
+ }
+ return map;
+ }
+
/// <summary>Get the text of an element with the given class name.</summary>
/// <param name="container">The metadata container.</param>
/// <param name="className">The field name.</param>
diff --git a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs
index 51bb2336..931dcd43 100644
--- a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs
+++ b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
{
@@ -62,6 +63,12 @@ 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>Maps local versions to a semantic version for update checks.</summary>
+ public IDictionary<string, string> MapLocalVersions { get; set; }
+
+ /// <summary>Maps remote versions to a semantic version for update checks.</summary>
+ public IDictionary<string, string> MapRemoteVersions { get; set; }
+
/// <summary>The link anchor for the mod entry in the wiki compatibility list.</summary>
public string Anchor { get; set; }
}
diff --git a/src/SMAPI.Toolkit/Framework/ModData/ModDataModel.cs b/src/SMAPI.Toolkit/Framework/ModData/ModDataModel.cs
index dd0bd07b..8b40c301 100644
--- a/src/SMAPI.Toolkit/Framework/ModData/ModDataModel.cs
+++ b/src/SMAPI.Toolkit/Framework/ModData/ModDataModel.cs
@@ -25,12 +25,6 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
/// </remarks>
public string FormerIDs { get; set; }
- /// <summary>Maps local versions to a semantic version for update checks.</summary>
- public IDictionary<string, string> MapLocalVersions { get; set; } = new Dictionary<string, string>();
-
- /// <summary>Maps remote versions to a semantic version for update checks.</summary>
- public IDictionary<string, string> MapRemoteVersions { get; set; } = new Dictionary<string, string>();
-
/// <summary>The mod warnings to suppress, even if they'd normally be shown.</summary>
public ModWarning SuppressWarnings { get; set; }
diff --git a/src/SMAPI.Toolkit/Framework/ModData/ModDataRecord.cs b/src/SMAPI.Toolkit/Framework/ModData/ModDataRecord.cs
index f01ada7c..c892d820 100644
--- a/src/SMAPI.Toolkit/Framework/ModData/ModDataRecord.cs
+++ b/src/SMAPI.Toolkit/Framework/ModData/ModDataRecord.cs
@@ -22,12 +22,6 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
/// <summary>The mod warnings to suppress, even if they'd normally be shown.</summary>
public ModWarning SuppressWarnings { get; set; }
- /// <summary>Maps local versions to a semantic version for update checks.</summary>
- public IDictionary<string, string> MapLocalVersions { get; }
-
- /// <summary>Maps remote versions to a semantic version for update checks.</summary>
- public IDictionary<string, string> MapRemoteVersions { get; }
-
/// <summary>The versioned field data.</summary>
public ModDataField[] Fields { get; }
@@ -44,8 +38,6 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
this.ID = model.ID;
this.FormerIDs = model.GetFormerIDs().ToArray();
this.SuppressWarnings = model.SuppressWarnings;
- this.MapLocalVersions = new Dictionary<string, string>(model.MapLocalVersions, StringComparer.InvariantCultureIgnoreCase);
- this.MapRemoteVersions = new Dictionary<string, string>(model.MapRemoteVersions, StringComparer.InvariantCultureIgnoreCase);
this.Fields = model.GetFields().ToArray();
}
@@ -67,29 +59,6 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
return false;
}
- /// <summary>Get a semantic local version for update checks.</summary>
- /// <param name="version">The remote version to normalize.</param>
- public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version)
- {
- return this.MapLocalVersions != null && this.MapLocalVersions.TryGetValue(version.ToString(), out string newVersion)
- ? new SemanticVersion(newVersion)
- : version;
- }
-
- /// <summary>Get a semantic remote version for update checks.</summary>
- /// <param name="version">The remote version to normalize.</param>
- public string GetRemoteVersionForUpdateChecks(string version)
- {
- // normalize version if possible
- if (SemanticVersion.TryParse(version, out ISemanticVersion parsed))
- version = parsed.ToString();
-
- // fetch remote version
- return this.MapRemoteVersions != null && this.MapRemoteVersions.TryGetValue(version, out string newVersion)
- ? newVersion
- : version;
- }
-
/// <summary>Get the possible mod IDs.</summary>
public IEnumerable<string> GetIDs()
{
diff --git a/src/SMAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs b/src/SMAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs
index 9e22990d..598da66a 100644
--- a/src/SMAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs
+++ b/src/SMAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs
@@ -26,29 +26,5 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData
/// <summary>The upper version for which the <see cref="Status"/> applies (if any).</summary>
public ISemanticVersion StatusUpperVersion { get; set; }
-
-
- /*********
- ** Public methods
- *********/
- /// <summary>Get a semantic local version for update checks.</summary>
- /// <param name="version">The remote version to normalize.</param>
- public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version)
- {
- return this.DataRecord.GetLocalVersionForUpdateChecks(version);
- }
-
- /// <summary>Get a semantic remote version for update checks.</summary>
- /// <param name="version">The remote version to normalize.</param>
- public ISemanticVersion GetRemoteVersionForUpdateChecks(ISemanticVersion version)
- {
- if (version == null)
- return null;
-
- string rawVersion = this.DataRecord.GetRemoteVersionForUpdateChecks(version.ToString());
- return rawVersion != null
- ? new SemanticVersion(rawVersion)
- : version;
- }
}
}
diff --git a/src/SMAPI.Web/Controllers/ModsApiController.cs b/src/SMAPI.Web/Controllers/ModsApiController.cs
index f65b164f..fe220eb5 100644
--- a/src/SMAPI.Web/Controllers/ModsApiController.cs
+++ b/src/SMAPI.Web/Controllers/ModsApiController.cs
@@ -80,7 +80,7 @@ namespace StardewModdingAPI.Web.Controllers
new IModRepository[]
{
new ChucklefishRepository(chucklefish),
- new CurseForgeRepository(curseForge),
+ new CurseForgeRepository(curseForge),
new GitHubRepository(github),
new ModDropRepository(modDrop),
new NexusRepository(nexus)
@@ -90,12 +90,15 @@ namespace StardewModdingAPI.Web.Controllers
/// <summary>Fetch version metadata for the given mods.</summary>
/// <param name="model">The mod search criteria.</param>
+ /// <param name="version">The requested API version.</param>
[HttpPost]
- public async Task<IEnumerable<ModEntryModel>> PostAsync([FromBody] ModSearchModel model)
+ public async Task<IEnumerable<ModEntryModel>> PostAsync([FromBody] ModSearchModel model, [FromRoute] string version)
{
if (model?.Mods == null)
return new ModEntryModel[0];
+ bool legacyMode = SemanticVersion.TryParse(version, out ISemanticVersion parsedVersion) && parsedVersion.IsOlderThan("3.0.0-beta.20191109");
+
// fetch wiki data
WikiModEntry[] wikiData = this.WikiCache.GetWikiMods().Select(p => p.GetModel()).ToArray();
IDictionary<string, ModEntryModel> mods = new Dictionary<string, ModEntryModel>(StringComparer.CurrentCultureIgnoreCase);
@@ -104,7 +107,25 @@ namespace StardewModdingAPI.Web.Controllers
if (string.IsNullOrWhiteSpace(mod.ID))
continue;
- ModEntryModel result = await this.GetModData(mod, wikiData, model.IncludeExtendedMetadata);
+ ModEntryModel result = await this.GetModData(mod, wikiData, model.IncludeExtendedMetadata || legacyMode, model.ApiVersion);
+ if (legacyMode)
+ {
+ result.Main = result.Metadata.Main;
+ result.Optional = result.Metadata.Optional;
+ result.Unofficial = result.Metadata.Unofficial;
+ result.UnofficialForBeta = result.Metadata.UnofficialForBeta;
+ result.HasBetaInfo = result.Metadata.BetaCompatibilityStatus != null;
+ result.SuggestedUpdate = null;
+ if (!model.IncludeExtendedMetadata)
+ result.Metadata = null;
+ }
+ else if (!model.IncludeExtendedMetadata && (model.ApiVersion == null || mod.InstalledVersion == null))
+ {
+ var errors = new List<string>(result.Errors);
+ errors.Add($"This API can't suggest an update because {nameof(model.ApiVersion)} or {nameof(mod.InstalledVersion)} are null, and you didn't specify {nameof(model.IncludeExtendedMetadata)} to get other info. See the SMAPI technical docs for usage.");
+ result.Errors = errors.ToArray();
+ }
+
mods[mod.ID] = result;
}
@@ -120,8 +141,9 @@ namespace StardewModdingAPI.Web.Controllers
/// <param name="search">The mod data to match.</param>
/// <param name="wikiData">The wiki data.</param>
/// <param name="includeExtendedMetadata">Whether to include extended metadata for each mod.</param>
+ /// <param name="apiVersion">The SMAPI version installed by the player.</param>
/// <returns>Returns the mod data if found, else <c>null</c>.</returns>
- private async Task<ModEntryModel> GetModData(ModSearchEntryModel search, WikiModEntry[] wikiData, bool includeExtendedMetadata)
+ private async Task<ModEntryModel> GetModData(ModSearchEntryModel search, WikiModEntry[] wikiData, bool includeExtendedMetadata, ISemanticVersion apiVersion)
{
// cross-reference data
ModDataRecord record = this.ModDatabase.Get(search.ID);
@@ -131,6 +153,10 @@ namespace StardewModdingAPI.Web.Controllers
// get latest versions
ModEntryModel result = new ModEntryModel { ID = search.ID };
IList<string> errors = new List<string>();
+ ModEntryVersionModel main = null;
+ ModEntryVersionModel optional = null;
+ ModEntryVersionModel unofficial = null;
+ ModEntryVersionModel unofficialForBeta = null;
foreach (UpdateKey updateKey in updateKeys)
{
// validate update key
@@ -151,76 +177,118 @@ namespace StardewModdingAPI.Web.Controllers
// handle main version
if (data.Version != null)
{
- if (!SemanticVersion.TryParse(data.Version, out ISemanticVersion version))
+ ISemanticVersion version = this.GetMappedVersion(data.Version, wikiEntry?.MapRemoteVersions);
+ if (version == null)
{
errors.Add($"The update key '{updateKey}' matches a mod with invalid semantic version '{data.Version}'.");
continue;
}
- if (this.IsNewer(version, result.Main?.Version))
- result.Main = new ModEntryVersionModel(version, data.Url);
+ if (this.IsNewer(version, main?.Version))
+ main = new ModEntryVersionModel(version, data.Url);
}
// handle optional version
if (data.PreviewVersion != null)
{
- if (!SemanticVersion.TryParse(data.PreviewVersion, out ISemanticVersion version))
+ ISemanticVersion version = this.GetMappedVersion(data.PreviewVersion, wikiEntry?.MapRemoteVersions);
+ if (version == null)
{
errors.Add($"The update key '{updateKey}' matches a mod with invalid optional semantic version '{data.PreviewVersion}'.");
continue;
}
- if (this.IsNewer(version, result.Optional?.Version))
- result.Optional = new ModEntryVersionModel(version, data.Url);
+ if (this.IsNewer(version, optional?.Version))
+ optional = new ModEntryVersionModel(version, data.Url);
}
}
// get unofficial version
- if (wikiEntry?.Compatibility.UnofficialVersion != null && this.IsNewer(wikiEntry.Compatibility.UnofficialVersion, result.Main?.Version) && this.IsNewer(wikiEntry.Compatibility.UnofficialVersion, result.Optional?.Version))
- result.Unofficial = new ModEntryVersionModel(wikiEntry.Compatibility.UnofficialVersion, $"{this.CompatibilityPageUrl}/#{wikiEntry.Anchor}");
+ if (wikiEntry?.Compatibility.UnofficialVersion != null && this.IsNewer(wikiEntry.Compatibility.UnofficialVersion, main?.Version) && this.IsNewer(wikiEntry.Compatibility.UnofficialVersion, optional?.Version))
+ unofficial = new ModEntryVersionModel(wikiEntry.Compatibility.UnofficialVersion, $"{this.CompatibilityPageUrl}/#{wikiEntry.Anchor}");
// get unofficial version for beta
if (wikiEntry?.HasBetaInfo == true)
{
- result.HasBetaInfo = true;
if (wikiEntry.BetaCompatibility.Status == WikiCompatibilityStatus.Unofficial)
{
if (wikiEntry.BetaCompatibility.UnofficialVersion != null)
{
- result.UnofficialForBeta = (wikiEntry.BetaCompatibility.UnofficialVersion != null && this.IsNewer(wikiEntry.BetaCompatibility.UnofficialVersion, result.Main?.Version) && this.IsNewer(wikiEntry.BetaCompatibility.UnofficialVersion, result.Optional?.Version))
+ unofficialForBeta = (wikiEntry.BetaCompatibility.UnofficialVersion != null && this.IsNewer(wikiEntry.BetaCompatibility.UnofficialVersion, main?.Version) && this.IsNewer(wikiEntry.BetaCompatibility.UnofficialVersion, optional?.Version))
? new ModEntryVersionModel(wikiEntry.BetaCompatibility.UnofficialVersion, $"{this.CompatibilityPageUrl}/#{wikiEntry.Anchor}")
: null;
}
else
- result.UnofficialForBeta = result.Unofficial;
+ unofficialForBeta = unofficial;
}
}
// fallback to preview if latest is invalid
- if (result.Main == null && result.Optional != null)
+ if (main == null && optional != null)
{
- result.Main = result.Optional;
- result.Optional = null;
+ main = optional;
+ optional = null;
}
// special cases
if (result.ID == "Pathoschild.SMAPI")
{
- if (result.Main != null)
- result.Main.Url = "https://smapi.io/";
- if (result.Optional != null)
- result.Optional.Url = "https://smapi.io/";
+ if (main != null)
+ main.Url = "https://smapi.io/";
+ if (optional != null)
+ optional.Url = "https://smapi.io/";
+ }
+
+ // get recommended update (if any)
+ ISemanticVersion installedVersion = this.GetMappedVersion(search.InstalledVersion?.ToString(), wikiEntry?.MapLocalVersions);
+ if (apiVersion != null && installedVersion != null)
+ {
+ // get newer versions
+ List<ModEntryVersionModel> updates = new List<ModEntryVersionModel>();
+ if (this.IsRecommendedUpdate(installedVersion, main?.Version, useBetaChannel: true))
+ updates.Add(main);
+ if (this.IsRecommendedUpdate(installedVersion, optional?.Version, useBetaChannel: installedVersion.IsPrerelease()))
+ updates.Add(optional);
+ if (this.IsRecommendedUpdate(installedVersion, unofficial?.Version, useBetaChannel: search.IsBroken))
+ updates.Add(unofficial);
+ if (this.IsRecommendedUpdate(installedVersion, unofficialForBeta?.Version, useBetaChannel: apiVersion.IsPrerelease()))
+ updates.Add(unofficialForBeta);
+
+ // get newest version
+ ModEntryVersionModel newest = null;
+ foreach (ModEntryVersionModel update in updates)
+ {
+ if (newest == null || update.Version.IsNewerThan(newest.Version))
+ newest = update;
+ }
+
+ // set field
+ result.SuggestedUpdate = newest != null
+ ? new ModEntryVersionModel(newest.Version, newest.Url)
+ : null;
}
// add extended metadata
- if (includeExtendedMetadata && (wikiEntry != null || record != null))
- result.Metadata = new ModExtendedMetadataModel(wikiEntry, record);
+ if (includeExtendedMetadata)
+ result.Metadata = new ModExtendedMetadataModel(wikiEntry, record, main: main, optional: optional, unofficial: unofficial, unofficialForBeta: unofficialForBeta);
// add result
result.Errors = errors.ToArray();
return result;
}
+ /// <summary>Get whether a given version should be offered to the user as an update.</summary>
+ /// <param name="currentVersion">The current semantic version.</param>
+ /// <param name="newVersion">The target semantic version.</param>
+ /// <param name="useBetaChannel">Whether the user enabled the beta channel and should be offered prerelease updates.</param>
+ private bool IsRecommendedUpdate(ISemanticVersion currentVersion, ISemanticVersion newVersion, bool useBetaChannel)
+ {
+ return
+ newVersion != null
+ && newVersion.IsNewerThan(currentVersion)
+ && (useBetaChannel || !newVersion.IsPrerelease());
+ }
+
/// <summary>Get whether a <paramref name="current"/> version is newer than an <paramref name="other"/> version.</summary>
/// <param name="current">The current version.</param>
/// <param name="other">The other version.</param>
@@ -260,7 +328,7 @@ namespace StardewModdingAPI.Web.Controllers
/// <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<UpdateKey> GetUpdateKeys(string[] specifiedKeys, ModDataRecord record, WikiModEntry entry)
+ private IEnumerable<UpdateKey> GetUpdateKeys(string[] specifiedKeys, ModDataRecord record, WikiModEntry entry)
{
IEnumerable<string> GetRaw()
{
@@ -301,5 +369,49 @@ namespace StardewModdingAPI.Web.Controllers
yield return key;
}
}
+
+ /// <summary>Get a semantic local version for update checks.</summary>
+ /// <param name="version">The version to parse.</param>
+ /// <param name="map">A map of version replacements.</param>
+ private ISemanticVersion GetMappedVersion(string version, IDictionary<string, string> map)
+ {
+ // try mapped version
+ string rawNewVersion = this.GetRawMappedVersion(version, map);
+ if (SemanticVersion.TryParse(rawNewVersion, out ISemanticVersion parsedNew))
+ return parsedNew;
+
+ // return original version
+ return SemanticVersion.TryParse(version, out ISemanticVersion parsedOld)
+ ? parsedOld
+ : null;
+ }
+
+ /// <summary>Get a semantic local version for update checks.</summary>
+ /// <param name="version">The version to map.</param>
+ /// <param name="map">A map of version replacements.</param>
+ private string GetRawMappedVersion(string version, IDictionary<string, string> map)
+ {
+ if (version == null || map == null || !map.Any())
+ return version;
+
+ // match exact raw version
+ if (map.ContainsKey(version))
+ return map[version];
+
+ // match parsed version
+ if (SemanticVersion.TryParse(version, out ISemanticVersion parsed))
+ {
+ if (map.ContainsKey(parsed.ToString()))
+ return map[parsed.ToString()];
+
+ foreach (var pair in map)
+ {
+ if (SemanticVersion.TryParse(pair.Key, out ISemanticVersion target) && parsed.Equals(target) && SemanticVersion.TryParse(pair.Value, out ISemanticVersion newVersion))
+ return newVersion.ToString();
+ }
+ }
+
+ return version;
+ }
}
}
diff --git a/src/SMAPI.Web/Framework/Caching/Wiki/CachedWikiMod.cs b/src/SMAPI.Web/Framework/Caching/Wiki/CachedWikiMod.cs
index fddf99ee..8569984a 100644
--- a/src/SMAPI.Web/Framework/Caching/Wiki/CachedWikiMod.cs
+++ b/src/SMAPI.Web/Framework/Caching/Wiki/CachedWikiMod.cs
@@ -1,6 +1,9 @@
using System;
+using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using MongoDB.Bson;
+using MongoDB.Bson.Serialization.Attributes;
+using MongoDB.Bson.Serialization.Options;
using StardewModdingAPI.Toolkit;
using StardewModdingAPI.Toolkit.Framework.Clients.Wiki;
@@ -109,6 +112,17 @@ namespace StardewModdingAPI.Web.Framework.Caching.Wiki
/// <summary>The URL to the latest unofficial update, if applicable.</summary>
public string BetaUnofficialUrl { get; set; }
+ /****
+ ** Version maps
+ ****/
+ /// <summary>Maps local versions to a semantic version for update checks.</summary>
+ [BsonDictionaryOptions(Representation = DictionaryRepresentation.ArrayOfArrays)]
+ public IDictionary<string, string> MapLocalVersions { get; set; }
+
+ /// <summary>Maps remote versions to a semantic version for update checks.</summary>
+ [BsonDictionaryOptions(Representation = DictionaryRepresentation.ArrayOfArrays)]
+ public IDictionary<string, string> MapRemoteVersions { get; set; }
+
/*********
** Accessors
@@ -154,6 +168,10 @@ namespace StardewModdingAPI.Web.Framework.Caching.Wiki
this.BetaBrokeIn = mod.BetaCompatibility?.BrokeIn;
this.BetaUnofficialVersion = mod.BetaCompatibility?.UnofficialVersion?.ToString();
this.BetaUnofficialUrl = mod.BetaCompatibility?.UnofficialUrl;
+
+ // version maps
+ this.MapLocalVersions = mod.MapLocalVersions;
+ this.MapRemoteVersions = mod.MapRemoteVersions;
}
/// <summary>Reconstruct the original model.</summary>
@@ -186,7 +204,11 @@ namespace StardewModdingAPI.Web.Framework.Caching.Wiki
BrokeIn = this.MainBrokeIn,
UnofficialVersion = this.MainUnofficialVersion != null ? new SemanticVersion(this.MainUnofficialVersion) : null,
UnofficialUrl = this.MainUnofficialUrl
- }
+ },
+
+ // version maps
+ MapLocalVersions = this.MapLocalVersions,
+ MapRemoteVersions = this.MapRemoteVersions
};
// beta compatibility
diff --git a/src/SMAPI.Web/Views/Index/Privacy.cshtml b/src/SMAPI.Web/Views/Index/Privacy.cshtml
index 356580b4..914384a8 100644
--- a/src/SMAPI.Web/Views/Index/Privacy.cshtml
+++ b/src/SMAPI.Web/Views/Index/Privacy.cshtml
@@ -24,7 +24,7 @@
<p>This website and SMAPI's web API are hosted by Amazon Web Services. Their servers may automatically collect diagnostics like your IP address, but this information is not visible to SMAPI's web application or developers. For more information, see the <a href="https://aws.amazon.com/privacy/">Amazon Privacy Notice</a>.</p>
<h3>Update checks</h3>
-<p>SMAPI notifies you when there's a new version of SMAPI or your mods available. To do so, it sends your SMAPI and mod versions to its web API. No personal information is stored by the web application, but see <em><a href="#web-logging">web logging</a></em>.</p>
+<p>SMAPI notifies you when there's a new version of SMAPI or your mods available. To do so, it sends your game/SMAPI/mod versions and platform type to its web API. No personal information is stored by the web application, but see <em><a href="#web-logging">web logging</a></em>.</p>
<p>You can disable update checks, and no information will be transmitted to the web API. To do so:</p>
<ol>
diff --git a/src/SMAPI.Web/wwwroot/SMAPI.metadata.json b/src/SMAPI.Web/wwwroot/SMAPI.metadata.json
index e4c0a6f6..553b6934 100644
--- a/src/SMAPI.Web/wwwroot/SMAPI.metadata.json
+++ b/src/SMAPI.Web/wwwroot/SMAPI.metadata.json
@@ -14,11 +14,6 @@
* other fields if no ID was specified. This doesn't include the latest ID, if any. Multiple
* variants can be separated with '|'.
*
- * - MapLocalVersions and MapRemoteVersions correct local manifest versions and remote versions
- * during update checks. For example, if the API returns version '1.1-1078' where '1078' is
- * intended to be a build number, MapRemoteVersions can map it to '1.1' when comparing to the
- * mod's current version. This is only meant to support legacy mods with injected update keys.
- *
* Versioned metadata
* ==================
* Each record can also specify extra metadata using the field keys below.
@@ -122,91 +117,6 @@
"Default | UpdateKey": "Nexus:1820"
},
-
- /*********
- ** Map versions
- *********/
- "Adjust Artisan Prices": {
- "ID": "ThatNorthernMonkey.AdjustArtisanPrices",
- "FormerIDs": "1e36d4ca-c7ef-4dfb-9927-d27a6c3c8bdc", // changed in 0.0.2-pathoschild-update
- "MapRemoteVersions": { "0.01": "0.0.1" }
- },
-
- "Almighty Farming Tool": {
- "ID": "439",
- "MapRemoteVersions": {
- "1.21": "1.2.1",
- "1.22-unofficial.3.mizzion": "1.2.2-unofficial.3.mizzion"
- }
- },
-
- "Basic Sprinkler Improved": {
- "ID": "lrsk_sdvm_bsi.0117171308",
- "MapRemoteVersions": { "1.0.2": "1.0.1-release" } // manifest not updated
- },
-
- "Better Shipping Box": {
- "ID": "Kithio:BetterShippingBox",
- "MapLocalVersions": { "1.0.1": "1.0.2" }
- },
-
- "Chefs Closet": {
- "ID": "Duder.ChefsCloset",
- "MapLocalVersions": { "1.3-1": "1.3" }
- },
-
- "Configurable Machines": {
- "ID": "21da6619-dc03-4660-9794-8e5b498f5b97",
- "MapLocalVersions": { "1.2-beta": "1.2" }
- },
-
- "Crafting Counter": {
- "ID": "lolpcgaming.CraftingCounter",
- "MapRemoteVersions": { "1.1": "1.0" } // not updated in manifest
- },
-
- "Custom Linens": {
- "ID": "Mevima.CustomLinens",
- "MapRemoteVersions": { "1.1": "1.0" } // manifest not updated
- },
-
- "Dynamic Horses": {
- "ID": "Bpendragon-DynamicHorses",
- "MapRemoteVersions": { "1.2": "1.1-release" } // manifest not updated
- },
-
- "Dynamic Machines": {
- "ID": "DynamicMachines",
- "MapLocalVersions": { "1.1": "1.1.1" }
- },
-
- "Multiple Sprites and Portraits On Rotation (File Loading)": {
- "ID": "FileLoading",
- "MapLocalVersions": { "1.1": "1.12" }
- },
-
- "Relationship Status": {
- "ID": "relationshipstatus",
- "MapRemoteVersions": { "1.0.5": "1.0.4" } // not updated in manifest
- },
-
- "ReRegeneration": {
- "ID": "lrsk_sdvm_rerg.0925160827",
- "MapLocalVersions": { "1.1.2-release": "1.1.2" }
- },
-
- "Showcase Mod": {
- "ID": "Igorious.Showcase",
- "MapLocalVersions": { "0.9-500": "0.9" }
- },
-
- "Siv's Marriage Mod": {
- "ID": "6266959802", // official version
- "FormerIDs": "Siv.MarriageMod | medoli900.Siv's Marriage Mod", // 1.2.3-unofficial versions
- "MapLocalVersions": { "0.0": "1.4" }
- },
-
-
/*********
** Obsolete
*********/
@@ -477,12 +387,6 @@
"~1.0.0 | Status": "AssumeBroken" // broke in Stardew Valley 1.3.29 (runtime errors)
},
- "Skill Prestige: Cooking Adapter": {
- "ID": "Alphablackwolf.CookingSkillPrestigeAdapter",
- "FormerIDs": "20d6b8a3-b6e7-460b-a6e4-07c2b0cb6c63", // changed circa 1.1
- "MapRemoteVersions": { "1.2.3": "1.1" } // manifest not updated
- },
-
"Skull Cave Saver": {
"ID": "cantorsdust.SkullCaveSaver",
"FormerIDs": "8ac06349-26f7-4394-806c-95d48fd35774 | community.SkullCaveSaver", // changed in 1.1 and 1.2.2
@@ -501,7 +405,6 @@
"Stephan's Lots of Crops": {
"ID": "stephansstardewcrops",
- "MapRemoteVersions": { "1.41": "1.1" }, // manifest not updated
"~1.1 | Status": "AssumeBroken" // broke in SDV 1.3 (overwrites vanilla items)
},
diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs
index 50bd562a..77b17c8a 100644
--- a/src/SMAPI/Framework/SCore.cs
+++ b/src/SMAPI/Framework/SCore.cs
@@ -593,27 +593,19 @@ namespace StardewModdingAPI.Framework
ISemanticVersion updateFound = null;
try
{
- ModEntryModel response = client.GetModInfo(new[] { new ModSearchEntryModel("Pathoschild.SMAPI", new[] { $"GitHub:{this.Settings.GitHubProjectName}" }) }).Single().Value;
- ISemanticVersion latestStable = response.Main?.Version;
- ISemanticVersion latestBeta = response.Optional?.Version;
+ // fetch update check
+ ModEntryModel response = client.GetModInfo(new[] { new ModSearchEntryModel("Pathoschild.SMAPI", Constants.ApiVersion, new[] { $"GitHub:{this.Settings.GitHubProjectName}" }) }, apiVersion: Constants.ApiVersion, gameVersion: Constants.GameVersion, platform: Constants.Platform).Single().Value;
+ if (response.SuggestedUpdate != null)
+ this.Monitor.Log($"You can update SMAPI to {response.SuggestedUpdate.Version}: {Constants.HomePageUrl}", LogLevel.Alert);
+ else
+ this.Monitor.Log(" SMAPI okay.", LogLevel.Trace);
- if (latestStable == null && response.Errors.Any())
+ // show errors
+ if (response.Errors.Any())
{
this.Monitor.Log("Couldn't check for a new version of SMAPI. This won't affect your game, but you may not be notified of new versions if this keeps happening.", LogLevel.Warn);
this.Monitor.Log($"Error: {string.Join("\n", response.Errors)}", LogLevel.Trace);
}
- else if (this.IsValidUpdate(Constants.ApiVersion, latestBeta, this.Settings.UseBetaChannel))
- {
- updateFound = latestBeta;
- this.Monitor.Log($"You can update SMAPI to {latestBeta}: {Constants.HomePageUrl}", LogLevel.Alert);
- }
- else if (this.IsValidUpdate(Constants.ApiVersion, latestStable, this.Settings.UseBetaChannel))
- {
- updateFound = latestStable;
- this.Monitor.Log($"You can update SMAPI to {latestStable}: {Constants.HomePageUrl}", LogLevel.Alert);
- }
- else
- this.Monitor.Log(" SMAPI okay.", LogLevel.Trace);
}
catch (Exception ex)
{
@@ -646,12 +638,12 @@ namespace StardewModdingAPI.Framework
.GetUpdateKeys(validOnly: true)
.Select(p => p.ToString())
.ToArray();
- searchMods.Add(new ModSearchEntryModel(mod.Manifest.UniqueID, updateKeys.ToArray()));
+ searchMods.Add(new ModSearchEntryModel(mod.Manifest.UniqueID, mod.Manifest.Version, updateKeys.ToArray(), isBroken: mod.Status == ModMetadataStatus.Failed));
}
// fetch results
this.Monitor.Log($" Checking for updates to {searchMods.Count} mods...", LogLevel.Trace);
- IDictionary<string, ModEntryModel> results = client.GetModInfo(searchMods.ToArray());
+ IDictionary<string, ModEntryModel> results = client.GetModInfo(searchMods.ToArray(), apiVersion: Constants.ApiVersion, gameVersion: Constants.GameVersion, platform: Constants.Platform);
// extract update alerts & errors
var updates = new List<Tuple<IModMetadata, ISemanticVersion, string>>();
@@ -672,20 +664,9 @@ namespace StardewModdingAPI.Framework
);
}
- // parse versions
- bool useBetaInfo = result.HasBetaInfo && Constants.ApiVersion.IsPrerelease();
- ISemanticVersion localVersion = mod.DataRecord?.GetLocalVersionForUpdateChecks(mod.Manifest.Version) ?? mod.Manifest.Version;
- ISemanticVersion latestVersion = mod.DataRecord?.GetRemoteVersionForUpdateChecks(result.Main?.Version) ?? result.Main?.Version;
- ISemanticVersion optionalVersion = mod.DataRecord?.GetRemoteVersionForUpdateChecks(result.Optional?.Version) ?? result.Optional?.Version;
- ISemanticVersion unofficialVersion = useBetaInfo ? result.UnofficialForBeta?.Version : result.Unofficial?.Version;
-
- // show update alerts
- if (this.IsValidUpdate(localVersion, latestVersion, useBetaChannel: true))
- updates.Add(Tuple.Create(mod, latestVersion, result.Main?.Url));
- else if (this.IsValidUpdate(localVersion, optionalVersion, useBetaChannel: localVersion.IsPrerelease()))
- updates.Add(Tuple.Create(mod, optionalVersion, result.Optional?.Url));
- else if (this.IsValidUpdate(localVersion, unofficialVersion, useBetaChannel: mod.Status == ModMetadataStatus.Failed))
- updates.Add(Tuple.Create(mod, unofficialVersion, useBetaInfo ? result.UnofficialForBeta?.Url : result.Unofficial?.Url));
+ // handle update
+ if (result.SuggestedUpdate != null)
+ updates.Add(Tuple.Create(mod, result.SuggestedUpdate.Version, result.SuggestedUpdate.Url));
}
// show update errors
@@ -720,18 +701,6 @@ namespace StardewModdingAPI.Framework
}).Start();
}
- /// <summary>Get whether a given version should be offered to the user as an update.</summary>
- /// <param name="currentVersion">The current semantic version.</param>
- /// <param name="newVersion">The target semantic version.</param>
- /// <param name="useBetaChannel">Whether the user enabled the beta channel and should be offered prerelease updates.</param>
- private bool IsValidUpdate(ISemanticVersion currentVersion, ISemanticVersion newVersion, bool useBetaChannel)
- {
- return
- newVersion != null
- && newVersion.IsNewerThan(currentVersion)
- && (useBetaChannel || !newVersion.IsPrerelease());
- }
-
/// <summary>Create a directory path if it doesn't exist.</summary>
/// <param name="path">The directory path.</param>
private void VerifyPath(string path)