summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2020-02-22 12:03:39 -0500
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2020-02-22 12:03:39 -0500
commit66079f2253a0c81bb33c1fee848a6cd2222d43d9 (patch)
treeca5fdd5f27c24f8d90665cb369e50f4580ce24fc
parentc8d627cdf2ae3126584ec2500877ff19987db17f (diff)
parent585b23797e262073e0738069eff61e90819216b7 (diff)
downloadSMAPI-66079f2253a0c81bb33c1fee848a6cd2222d43d9.tar.gz
SMAPI-66079f2253a0c81bb33c1fee848a6cd2222d43d9.tar.bz2
SMAPI-66079f2253a0c81bb33c1fee848a6cd2222d43d9.zip
Merge branch 'develop' into stable
-rw-r--r--build/common.targets2
-rw-r--r--docs/release-notes.md36
-rw-r--r--src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj2
-rw-r--r--src/SMAPI.Mods.ConsoleCommands/manifest.json4
-rw-r--r--src/SMAPI.Mods.SaveBackup/ModEntry.cs46
-rw-r--r--src/SMAPI.Mods.SaveBackup/manifest.json4
-rw-r--r--src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryVersionModel.cs4
-rw-r--r--src/SMAPI.Toolkit/SMAPI.Toolkit.csproj2
-rw-r--r--src/SMAPI.Toolkit/SemanticVersion.cs9
-rw-r--r--src/SMAPI.Toolkit/Serialization/Converters/NonStandardSemanticVersionConverter.cs15
-rw-r--r--src/SMAPI.Toolkit/Serialization/Converters/SemanticVersionConverter.cs9
-rw-r--r--src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs14
-rw-r--r--src/SMAPI.Web/Controllers/ModsApiController.cs54
-rw-r--r--src/SMAPI.Web/Framework/ConfigModels/ModOverrideConfig.cs15
-rw-r--r--src/SMAPI.Web/Framework/ConfigModels/ModUpdateCheckConfig.cs3
-rw-r--r--src/SMAPI.Web/Framework/VersionConstraint.cs2
-rw-r--r--src/SMAPI.Web/SMAPI.Web.csproj6
-rw-r--r--src/SMAPI.Web/Views/Mods/Index.cshtml4
-rw-r--r--src/SMAPI.Web/appsettings.json13
-rw-r--r--src/SMAPI.Web/wwwroot/Content/css/mods.css5
-rw-r--r--src/SMAPI.Web/wwwroot/Content/js/mods.js24
-rw-r--r--src/SMAPI.Web/wwwroot/SMAPI.metadata.json10
-rw-r--r--src/SMAPI.Web/wwwroot/schemas/content-patcher.json8
-rw-r--r--src/SMAPI/Constants.cs55
-rw-r--r--src/SMAPI/Framework/Content/AssetDataForImage.cs17
-rw-r--r--src/SMAPI/Framework/ContentCoordinator.cs4
-rw-r--r--src/SMAPI/Framework/ContentManagers/GameContentManager.cs17
-rw-r--r--src/SMAPI/Framework/ContentManagers/ModContentManager.cs142
-rw-r--r--src/SMAPI/Framework/Input/SInputState.cs53
-rw-r--r--src/SMAPI/Framework/ModHelpers/ContentHelper.cs8
-rw-r--r--src/SMAPI/Framework/ModHelpers/InputHelper.cs7
-rw-r--r--src/SMAPI/Framework/Networking/ModMessageModel.cs2
-rw-r--r--src/SMAPI/Framework/SGame.cs166
-rw-r--r--src/SMAPI/Framework/SMultiplayer.cs84
-rw-r--r--src/SMAPI/IAssetDataForImage.cs6
-rw-r--r--src/SMAPI/IInputHelper.cs4
-rw-r--r--src/SMAPI/Metadata/CoreAssetPropagator.cs7
-rw-r--r--src/SMAPI/SButtonState.cs (renamed from src/SMAPI/Framework/Input/InputStatus.cs)14
-rw-r--r--src/SMAPI/SMAPI.csproj4
-rw-r--r--src/SMAPI/i18n/it.json3
40 files changed, 599 insertions, 285 deletions
diff --git a/build/common.targets b/build/common.targets
index 8b0d1301..626eeef6 100644
--- a/build/common.targets
+++ b/build/common.targets
@@ -4,7 +4,7 @@
<!--set properties -->
<PropertyGroup>
- <Version>3.2.0</Version>
+ <Version>3.3.0</Version>
<Product>SMAPI</Product>
<AssemblySearchPaths>$(AssemblySearchPaths);{GAC}</AssemblySearchPaths>
diff --git a/docs/release-notes.md b/docs/release-notes.md
index f1981218..26515b61 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -1,6 +1,40 @@
&larr; [README](README.md)
# Release notes
+## 3.3
+Released 22 February 2020 for Stardew Valley 1.4.1 or later.
+
+* For players:
+ * Improved performance for mods which load many images.
+ * Reduced network traffic for mod broadcasts to players who can't process them.
+ * Fixed update-check errors for recent versions of SMAPI on Android.
+ * Updated draw logic to match recent game updates.
+ * Updated compatibility list.
+ * Updated SMAPI/game version map.
+ * Updated translations. Thanks to xCarloC (added Italian)!
+
+* For the Save Backup mod:
+ * Fixed warning on MacOS when you have no saves yet.
+ * Reduced log messages.
+
+* For modders:
+ * Added support for [message sending](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Integrations#Message_sending) to mods on the current computer (in addition to remote computers).
+ * Added `ExtendImage` method to content API when editing files to resize textures.
+ * Added `helper.Input.GetState` to get the low-level state of a button.
+ * **[Breaking change]** Map tilesheets are no loaded from `Content` if they can't be found in `Content/Maps`. This reflects an upcoming change in the game to delete duplicate map tilesheets under `Content`. Most mods should be unaffected.
+ * Improved map tilesheet errors so they provide more info.
+ * When mods load an asset using a more general type like `content.Load<object>`, SMAPI now calls `IAssetEditor` instances with the actual asset type instead of the specified one.
+ * Updated dependencies (including Mono.Cecil 0.11.1 → 0.11.2).
+ * Fixed dialogue propagation clearing marriage dialogue.
+
+* For the web UI:
+ * Updated the JSON validator and Content Patcher schema for `.tmx` support.
+ * The mod compatibility page now has a sticky table header.
+
+* For SMAPI/tool developers:
+ * Improved support for four-part versions to support SMAPI on Android.
+ * The SMAPI log now prefixes the OS name with `Android` on Android.
+
## 3.2
Released 01 February 2020 for Stardew Valley 1.4.1 or later.
@@ -23,7 +57,7 @@ Released 01 February 2020 for Stardew Valley 1.4.1 or later.
* Fixed Android issue where game files were backed up.
* For modders:
- * Added support for `.tmx` map files.
+ * Added support for `.tmx` map files. (Thanks to [Platonymous for the underlying library](https://github.com/Platonymous/TMXTile)!)
* Added special handling for `Vector2` values in `.json` files, so they work consistently crossplatform.
* Reworked the order that asset editors/loaders are called between multiple mods to support some framework mods like Content Patcher and Json Assets. Note that the order is undefined and should not be depended on.
* Fixed incorrect warning about mods adding invalid schedules in some cases. The validation was unreliable, and has been removed.
diff --git a/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj b/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj
index c1d5626f..e2be66d9 100644
--- a/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj
+++ b/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj
@@ -7,7 +7,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="2.10.0" />
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1">
<PrivateAssets>all</PrivateAssets>
diff --git a/src/SMAPI.Mods.ConsoleCommands/manifest.json b/src/SMAPI.Mods.ConsoleCommands/manifest.json
index 0d0e4901..971c591a 100644
--- a/src/SMAPI.Mods.ConsoleCommands/manifest.json
+++ b/src/SMAPI.Mods.ConsoleCommands/manifest.json
@@ -1,9 +1,9 @@
{
"Name": "Console Commands",
"Author": "SMAPI",
- "Version": "3.2.0",
+ "Version": "3.3.0",
"Description": "Adds SMAPI console commands that let you manipulate the game.",
"UniqueID": "SMAPI.ConsoleCommands",
"EntryDll": "ConsoleCommands.dll",
- "MinimumApiVersion": "3.2.0"
+ "MinimumApiVersion": "3.3.0"
}
diff --git a/src/SMAPI.Mods.SaveBackup/ModEntry.cs b/src/SMAPI.Mods.SaveBackup/ModEntry.cs
index 8b139d8f..b8d3be1c 100644
--- a/src/SMAPI.Mods.SaveBackup/ModEntry.cs
+++ b/src/SMAPI.Mods.SaveBackup/ModEntry.cs
@@ -66,29 +66,37 @@ namespace StardewModdingAPI.Mods.SaveBackup
FileInfo targetFile = new FileInfo(Path.Combine(backupFolder.FullName, this.FileName));
DirectoryInfo fallbackDir = new DirectoryInfo(Path.Combine(backupFolder.FullName, this.BackupLabel));
if (targetFile.Exists || fallbackDir.Exists)
+ {
+ this.Monitor.Log("Already backed up today.");
return;
+ }
// copy saves to fallback directory (ignore non-save files/folders)
- this.Monitor.Log($"Backing up saves to {fallbackDir.FullName}...", LogLevel.Trace);
DirectoryInfo savesDir = new DirectoryInfo(Constants.SavesPath);
- this.RecursiveCopy(savesDir, fallbackDir, entry => this.MatchSaveFolders(savesDir, entry), copyRoot: false);
+ if (!this.RecursiveCopy(savesDir, fallbackDir, entry => this.MatchSaveFolders(savesDir, entry), copyRoot: false))
+ {
+ this.Monitor.Log("No saves found.");
+ return;
+ }
// compress backup if possible
- this.Monitor.Log("Compressing backup if possible...", LogLevel.Trace);
if (!this.TryCompress(fallbackDir.FullName, targetFile, out Exception compressError))
{
- if (Constants.TargetPlatform != GamePlatform.Android) // expected to fail on Android
- this.Monitor.Log($"Couldn't compress backup, leaving it uncompressed.\n{compressError}", LogLevel.Trace);
+ this.Monitor.Log(Constants.TargetPlatform != GamePlatform.Android
+ ? $"Backed up to {fallbackDir.FullName}." // expected to fail on Android
+ : $"Backed up to {fallbackDir.FullName}. Couldn't compress backup:\n{compressError}"
+ );
}
else
+ {
+ this.Monitor.Log($"Backed up to {targetFile.FullName}.");
fallbackDir.Delete(recursive: true);
-
- this.Monitor.Log("Backup done!", LogLevel.Trace);
+ }
}
catch (Exception ex)
{
- this.Monitor.Log("Couldn't back up save files (see log file for details).", LogLevel.Warn);
- this.Monitor.Log(ex.ToString(), LogLevel.Trace);
+ this.Monitor.Log("Couldn't back up saves (see log file for details).", LogLevel.Warn);
+ this.Monitor.Log(ex.ToString());
}
}
@@ -108,7 +116,7 @@ namespace StardewModdingAPI.Mods.SaveBackup
{
try
{
- this.Monitor.Log($"Deleting {entry.Name}...", LogLevel.Trace);
+ this.Monitor.Log($"Deleting {entry.Name}...");
if (entry is DirectoryInfo folder)
folder.Delete(recursive: true);
else
@@ -123,7 +131,7 @@ namespace StardewModdingAPI.Mods.SaveBackup
catch (Exception ex)
{
this.Monitor.Log("Couldn't remove old backups (see log file for details).", LogLevel.Warn);
- this.Monitor.Log(ex.ToString(), LogLevel.Trace);
+ this.Monitor.Log(ex.ToString());
}
}
@@ -199,29 +207,33 @@ namespace StardewModdingAPI.Mods.SaveBackup
/// <param name="copyRoot">Whether to copy the root folder itself, or <c>false</c> to only copy its contents.</param>
/// <param name="filter">A filter which matches the files or directories to copy, or <c>null</c> to copy everything.</param>
/// <remarks>Derived from the SMAPI installer code.</remarks>
- private void RecursiveCopy(FileSystemInfo source, DirectoryInfo targetFolder, Func<FileSystemInfo, bool> filter, bool copyRoot = true)
+ /// <returns>Returns whether any files were copied.</returns>
+ private bool RecursiveCopy(FileSystemInfo source, DirectoryInfo targetFolder, Func<FileSystemInfo, bool> filter, bool copyRoot = true)
{
- if (!targetFolder.Exists)
- targetFolder.Create();
+ if (!source.Exists || filter?.Invoke(source) == false)
+ return false;
- if (filter?.Invoke(source) == false)
- return;
+ bool anyCopied = false;
switch (source)
{
case FileInfo sourceFile:
+ targetFolder.Create();
sourceFile.CopyTo(Path.Combine(targetFolder.FullName, sourceFile.Name));
+ anyCopied = true;
break;
case DirectoryInfo sourceDir:
DirectoryInfo targetSubfolder = copyRoot ? new DirectoryInfo(Path.Combine(targetFolder.FullName, sourceDir.Name)) : targetFolder;
foreach (var entry in sourceDir.EnumerateFileSystemInfos())
- this.RecursiveCopy(entry, targetSubfolder, filter);
+ anyCopied = this.RecursiveCopy(entry, targetSubfolder, filter) || anyCopied;
break;
default:
throw new NotSupportedException($"Unknown filesystem info type '{source.GetType().FullName}'.");
}
+
+ return anyCopied;
}
/// <summary>A copy filter which matches save folders.</summary>
diff --git a/src/SMAPI.Mods.SaveBackup/manifest.json b/src/SMAPI.Mods.SaveBackup/manifest.json
index 74256013..4559d1b0 100644
--- a/src/SMAPI.Mods.SaveBackup/manifest.json
+++ b/src/SMAPI.Mods.SaveBackup/manifest.json
@@ -1,9 +1,9 @@
{
"Name": "Save Backup",
"Author": "SMAPI",
- "Version": "3.2.0",
+ "Version": "3.3.0",
"Description": "Automatically backs up all your saves once per day into its folder.",
"UniqueID": "SMAPI.SaveBackup",
"EntryDll": "SaveBackup.dll",
- "MinimumApiVersion": "3.2.0"
+ "MinimumApiVersion": "3.3.0"
}
diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryVersionModel.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryVersionModel.cs
index dadb8c10..188db31d 100644
--- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryVersionModel.cs
+++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryVersionModel.cs
@@ -1,3 +1,6 @@
+using Newtonsoft.Json;
+using StardewModdingAPI.Toolkit.Serialization.Converters;
+
namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
{
/// <summary>Metadata about a version.</summary>
@@ -7,6 +10,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi
** Accessors
*********/
/// <summary>The version number.</summary>
+ [JsonConverter(typeof(NonStandardSemanticVersionConverter))]
public ISemanticVersion Version { get; set; }
/// <summary>The mod page URL.</summary>
diff --git a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj
index 16a97dbf..a7de7166 100644
--- a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj
+++ b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj
@@ -12,7 +12,7 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="HtmlAgilityPack" Version="1.11.18" />
+ <PackageReference Include="HtmlAgilityPack" Version="1.11.20" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Pathoschild.Http.FluentClient" Version="3.3.1" />
<PackageReference Include="System.Management" Version="4.5.0" Condition="'$(OS)' == 'Windows_NT'" />
diff --git a/src/SMAPI.Toolkit/SemanticVersion.cs b/src/SMAPI.Toolkit/SemanticVersion.cs
index 5ead6dc8..86db2820 100644
--- a/src/SMAPI.Toolkit/SemanticVersion.cs
+++ b/src/SMAPI.Toolkit/SemanticVersion.cs
@@ -199,18 +199,19 @@ namespace StardewModdingAPI.Toolkit
/// <returns>Returns whether parsing the version succeeded.</returns>
public static bool TryParse(string version, out ISemanticVersion parsed)
{
- return SemanticVersion.TryParseNonStandard(version, out parsed) && !parsed.IsNonStandard();
+ return SemanticVersion.TryParse(version, allowNonStandard: false, out parsed);
}
- /// <summary>Parse a version string without throwing an exception if it fails, including support for non-standard extensions like <see cref="IPlatformSpecificVersion"/>.</summary>
+ /// <summary>Parse a version string without throwing an exception if it fails.</summary>
/// <param name="version">The version string.</param>
+ /// <param name="allowNonStandard">Whether to allow non-standard extensions to semantic versioning.</param>
/// <param name="parsed">The parsed representation.</param>
/// <returns>Returns whether parsing the version succeeded.</returns>
- public static bool TryParseNonStandard(string version, out ISemanticVersion parsed)
+ public static bool TryParse(string version, bool allowNonStandard, out ISemanticVersion parsed)
{
try
{
- parsed = new SemanticVersion(version, true);
+ parsed = new SemanticVersion(version, allowNonStandard);
return true;
}
catch
diff --git a/src/SMAPI.Toolkit/Serialization/Converters/NonStandardSemanticVersionConverter.cs b/src/SMAPI.Toolkit/Serialization/Converters/NonStandardSemanticVersionConverter.cs
new file mode 100644
index 00000000..6f870bcf
--- /dev/null
+++ b/src/SMAPI.Toolkit/Serialization/Converters/NonStandardSemanticVersionConverter.cs
@@ -0,0 +1,15 @@
+namespace StardewModdingAPI.Toolkit.Serialization.Converters
+{
+ /// <summary>Handles deserialization of <see cref="ISemanticVersion"/>, allowing for non-standard extensions.</summary>
+ internal class NonStandardSemanticVersionConverter : SemanticVersionConverter
+ {
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ public NonStandardSemanticVersionConverter()
+ {
+ this.AllowNonStandard = true;
+ }
+ }
+}
diff --git a/src/SMAPI.Toolkit/Serialization/Converters/SemanticVersionConverter.cs b/src/SMAPI.Toolkit/Serialization/Converters/SemanticVersionConverter.cs
index e1b9db1d..3604956b 100644
--- a/src/SMAPI.Toolkit/Serialization/Converters/SemanticVersionConverter.cs
+++ b/src/SMAPI.Toolkit/Serialization/Converters/SemanticVersionConverter.cs
@@ -8,6 +8,13 @@ namespace StardewModdingAPI.Toolkit.Serialization.Converters
internal class SemanticVersionConverter : JsonConverter
{
/*********
+ ** Fields
+ *********/
+ /// <summary>Whether to allow non-standard extensions to semantic versioning.</summary>
+ protected bool AllowNonStandard { get; set; }
+
+
+ /*********
** Accessors
*********/
/// <summary>Get whether this converter can read JSON.</summary>
@@ -78,7 +85,7 @@ namespace StardewModdingAPI.Toolkit.Serialization.Converters
{
if (string.IsNullOrWhiteSpace(str))
return null;
- if (!SemanticVersion.TryParse(str, out ISemanticVersion version))
+ if (!SemanticVersion.TryParse(str, allowNonStandard: this.AllowNonStandard, out ISemanticVersion version))
throw new SParseException($"Can't parse semantic version from invalid value '{str}', should be formatted like 1.2, 1.2.30, or 1.2.30-beta (path: {path}).");
return version;
}
diff --git a/src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs b/src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs
index 2a01fe4b..c45448f3 100644
--- a/src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs
+++ b/src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs
@@ -53,7 +53,19 @@ namespace StardewModdingAPI.Toolkit.Utilities
}
catch { }
#endif
- return (platform == Platform.Mac ? "MacOS " : "") + Environment.OSVersion;
+
+ string name = Environment.OSVersion.ToString();
+ switch (platform)
+ {
+ case Platform.Android:
+ name = $"Android {name}";
+ break;
+
+ case Platform.Mac:
+ name = $"MacOS {name}";
+ break;
+ }
+ return name;
}
/// <summary>Get the name of the Stardew Valley executable.</summary>
diff --git a/src/SMAPI.Web/Controllers/ModsApiController.cs b/src/SMAPI.Web/Controllers/ModsApiController.cs
index f194b4d0..06768f03 100644
--- a/src/SMAPI.Web/Controllers/ModsApiController.cs
+++ b/src/SMAPI.Web/Controllers/ModsApiController.cs
@@ -41,11 +41,8 @@ namespace StardewModdingAPI.Web.Controllers
/// <summary>The cache in which to store mod data.</summary>
private readonly IModCacheRepository ModCache;
- /// <summary>The number of minutes successful update checks should be cached before refetching them.</summary>
- private readonly int SuccessCacheMinutes;
-
- /// <summary>The number of minutes failed update checks should be cached before refetching them.</summary>
- private readonly int ErrorCacheMinutes;
+ /// <summary>The config settings for mod update checks.</summary>
+ private readonly IOptions<ModUpdateCheckConfig> Config;
/// <summary>The internal mod metadata list.</summary>
private readonly ModDatabase ModDatabase;
@@ -58,21 +55,19 @@ namespace StardewModdingAPI.Web.Controllers
/// <param name="environment">The web hosting environment.</param>
/// <param name="wikiCache">The cache in which to store wiki data.</param>
/// <param name="modCache">The cache in which to store mod metadata.</param>
- /// <param name="configProvider">The config settings for mod update checks.</param>
+ /// <param name="config">The config settings for mod update checks.</param>
/// <param name="chucklefish">The Chucklefish API client.</param>
/// <param name="curseForge">The CurseForge API client.</param>
/// <param name="github">The GitHub API client.</param>
/// <param name="modDrop">The ModDrop API client.</param>
/// <param name="nexus">The Nexus API client.</param>
- public ModsApiController(IHostingEnvironment environment, IWikiCacheRepository wikiCache, IModCacheRepository modCache, IOptions<ModUpdateCheckConfig> configProvider, IChucklefishClient chucklefish, ICurseForgeClient curseForge, IGitHubClient github, IModDropClient modDrop, INexusClient nexus)
+ public ModsApiController(IHostingEnvironment environment, IWikiCacheRepository wikiCache, IModCacheRepository modCache, IOptions<ModUpdateCheckConfig> config, IChucklefishClient chucklefish, ICurseForgeClient curseForge, IGitHubClient github, IModDropClient modDrop, INexusClient nexus)
{
this.ModDatabase = new ModToolkit().GetModDatabase(Path.Combine(environment.WebRootPath, "SMAPI.metadata.json"));
- ModUpdateCheckConfig config = configProvider.Value;
this.WikiCache = wikiCache;
this.ModCache = modCache;
- this.SuccessCacheMinutes = config.SuccessCacheMinutes;
- this.ErrorCacheMinutes = config.ErrorCacheMinutes;
+ this.Config = config;
this.Repositories =
new IModRepository[]
{
@@ -133,6 +128,8 @@ namespace StardewModdingAPI.Web.Controllers
ModDataRecord record = this.ModDatabase.Get(search.ID);
WikiModEntry wikiEntry = wikiData.FirstOrDefault(entry => entry.ID.Contains(search.ID.Trim(), StringComparer.InvariantCultureIgnoreCase));
UpdateKey[] updateKeys = this.GetUpdateKeys(search.UpdateKeys, record, wikiEntry).ToArray();
+ ModOverrideConfig overrides = this.Config.Value.ModOverrides.FirstOrDefault(p => p.ID.Equals(search.ID?.Trim(), StringComparison.InvariantCultureIgnoreCase));
+ bool allowNonStandardVersions = overrides?.AllowNonStandardVersions ?? false;
// get latest versions
ModEntryModel result = new ModEntryModel { ID = search.ID };
@@ -151,7 +148,7 @@ namespace StardewModdingAPI.Web.Controllers
}
// fetch data
- ModInfoModel data = await this.GetInfoForUpdateKeyAsync(updateKey);
+ ModInfoModel data = await this.GetInfoForUpdateKeyAsync(updateKey, allowNonStandardVersions);
if (data.Error != null)
{
errors.Add(data.Error);
@@ -161,7 +158,7 @@ namespace StardewModdingAPI.Web.Controllers
// handle main version
if (data.Version != null)
{
- ISemanticVersion version = this.GetMappedVersion(data.Version, wikiEntry?.MapRemoteVersions);
+ ISemanticVersion version = this.GetMappedVersion(data.Version, wikiEntry?.MapRemoteVersions, allowNonStandardVersions);
if (version == null)
{
errors.Add($"The update key '{updateKey}' matches a mod with invalid semantic version '{data.Version}'.");
@@ -175,7 +172,7 @@ namespace StardewModdingAPI.Web.Controllers
// handle optional version
if (data.PreviewVersion != null)
{
- ISemanticVersion version = this.GetMappedVersion(data.PreviewVersion, wikiEntry?.MapRemoteVersions);
+ ISemanticVersion version = this.GetMappedVersion(data.PreviewVersion, wikiEntry?.MapRemoteVersions, allowNonStandardVersions);
if (version == null)
{
errors.Add($"The update key '{updateKey}' matches a mod with invalid optional semantic version '{data.PreviewVersion}'.");
@@ -215,16 +212,16 @@ namespace StardewModdingAPI.Web.Controllers
}
// special cases
- if (result.ID == "Pathoschild.SMAPI")
+ if (overrides?.SetUrl != null)
{
if (main != null)
- main.Url = "https://smapi.io/";
+ main.Url = overrides.SetUrl;
if (optional != null)
- optional.Url = "https://smapi.io/";
+ optional.Url = overrides.SetUrl;
}
// get recommended update (if any)
- ISemanticVersion installedVersion = this.GetMappedVersion(search.InstalledVersion?.ToString(), wikiEntry?.MapLocalVersions);
+ ISemanticVersion installedVersion = this.GetMappedVersion(search.InstalledVersion?.ToString(), wikiEntry?.MapLocalVersions, allowNonStandard: allowNonStandardVersions);
if (apiVersion != null && installedVersion != null)
{
// get newer versions
@@ -283,10 +280,11 @@ namespace StardewModdingAPI.Web.Controllers
/// <summary>Get the mod info for an update key.</summary>
/// <param name="updateKey">The namespaced update key.</param>
- private async Task<ModInfoModel> GetInfoForUpdateKeyAsync(UpdateKey updateKey)
+ /// <param name="allowNonStandardVersions">Whether to allow non-standard versions.</param>
+ private async Task<ModInfoModel> GetInfoForUpdateKeyAsync(UpdateKey updateKey, bool allowNonStandardVersions)
{
// get mod
- if (!this.ModCache.TryGetMod(updateKey.Repository, updateKey.ID, out CachedMod mod) || this.ModCache.IsStale(mod.LastUpdated, mod.FetchStatus == RemoteModStatus.TemporaryError ? this.ErrorCacheMinutes : this.SuccessCacheMinutes))
+ if (!this.ModCache.TryGetMod(updateKey.Repository, updateKey.ID, out CachedMod mod) || this.ModCache.IsStale(mod.LastUpdated, mod.FetchStatus == RemoteModStatus.TemporaryError ? this.Config.Value.ErrorCacheMinutes : this.Config.Value.SuccessCacheMinutes))
{
// get site
if (!this.Repositories.TryGetValue(updateKey.Repository, out IModRepository repository))
@@ -298,7 +296,7 @@ namespace StardewModdingAPI.Web.Controllers
{
if (result.Version == null)
result.SetError(RemoteModStatus.InvalidData, $"The update key '{updateKey}' matches a mod with no version number.");
- else if (!SemanticVersion.TryParse(result.Version, out _))
+ else if (!SemanticVersion.TryParse(result.Version, allowNonStandardVersions, out _))
result.SetError(RemoteModStatus.InvalidData, $"The update key '{updateKey}' matches a mod with invalid semantic version '{result.Version}'.");
}
@@ -357,15 +355,16 @@ namespace StardewModdingAPI.Web.Controllers
/// <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)
+ /// <param name="allowNonStandard">Whether to allow non-standard versions.</param>
+ private ISemanticVersion GetMappedVersion(string version, IDictionary<string, string> map, bool allowNonStandard)
{
// try mapped version
- string rawNewVersion = this.GetRawMappedVersion(version, map);
- if (SemanticVersion.TryParse(rawNewVersion, out ISemanticVersion parsedNew))
+ string rawNewVersion = this.GetRawMappedVersion(version, map, allowNonStandard);
+ if (SemanticVersion.TryParse(rawNewVersion, allowNonStandard, out ISemanticVersion parsedNew))
return parsedNew;