summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/SMAPI.ModBuildConfig/SMAPI.ModBuildConfig.csproj2
-rw-r--r--src/SMAPI.ModBuildConfig/build/smapi.targets20
-rw-r--r--src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetColorCommand.cs2
-rw-r--r--src/SMAPI.Mods.ConsoleCommands/manifest.json4
-rw-r--r--src/SMAPI.Mods.ErrorHandler/manifest.json4
-rw-r--r--src/SMAPI.Mods.SaveBackup/manifest.json4
-rw-r--r--src/SMAPI.Tests/Utilities/KeybindListTests.cs6
-rw-r--r--src/SMAPI.Tests/Utilities/SemanticVersionTests.cs4
-rw-r--r--src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs50
-rw-r--r--src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs4
-rw-r--r--src/SMAPI.Toolkit/SMAPI.Toolkit.csproj3
-rw-r--r--src/SMAPI.Toolkit/Serialization/Models/Manifest.cs53
-rw-r--r--src/SMAPI.Web/Controllers/ModsApiController.cs17
-rw-r--r--src/SMAPI.Web/Framework/Clients/Nexus/NexusClient.cs4
-rw-r--r--src/SMAPI.Web/Framework/LogParsing/LogParser.cs9
-rw-r--r--src/SMAPI.Web/Framework/LogParsing/Models/ParsedLog.cs3
-rw-r--r--src/SMAPI.Web/SMAPI.Web.csproj2
-rw-r--r--src/SMAPI.Web/Views/LogParser/Index.cshtml27
-rw-r--r--src/SMAPI.Web/wwwroot/Content/css/log-parser.css5
-rw-r--r--src/SMAPI/Constants.cs2
-rw-r--r--src/SMAPI/Framework/Content/AssetDataForImage.cs164
-rw-r--r--src/SMAPI/Framework/ContentCoordinator.cs10
-rw-r--r--src/SMAPI/Framework/ContentManagers/BaseContentManager.cs2
-rw-r--r--src/SMAPI/Framework/ContentManagers/ModContentManager.cs132
-rw-r--r--src/SMAPI/Framework/Deprecations/DeprecationManager.cs2
-rw-r--r--src/SMAPI/Framework/InternalExtensions.cs30
-rw-r--r--src/SMAPI/Framework/Logging/LogManager.cs12
-rw-r--r--src/SMAPI/Framework/Logging/LogOnceCacheKey.cs10
-rw-r--r--src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs47
-rw-r--r--src/SMAPI/Framework/ModLoading/AssemblyLoader.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs2
-rw-r--r--src/SMAPI/Framework/Models/SConfig.cs16
-rw-r--r--src/SMAPI/Framework/Monitor.cs11
-rw-r--r--src/SMAPI/Framework/SCore.cs85
-rw-r--r--src/SMAPI/Framework/StateTracking/FieldWatchers/ComparableListWatcher.cs2
-rw-r--r--src/SMAPI/IMod.cs10
-rw-r--r--src/SMAPI/Mod.cs6
-rw-r--r--src/SMAPI/SMAPI.config.json20
-rw-r--r--src/SMAPI/SMAPI.csproj2
-rw-r--r--src/SMAPI/Utilities/Keybind.cs4
40 files changed, 553 insertions, 241 deletions
diff --git a/src/SMAPI.ModBuildConfig/SMAPI.ModBuildConfig.csproj b/src/SMAPI.ModBuildConfig/SMAPI.ModBuildConfig.csproj
index e25da168..cded6f65 100644
--- a/src/SMAPI.ModBuildConfig/SMAPI.ModBuildConfig.csproj
+++ b/src/SMAPI.ModBuildConfig/SMAPI.ModBuildConfig.csproj
@@ -10,7 +10,7 @@
<!--NuGet package-->
<PackageId>Pathoschild.Stardew.ModBuildConfig</PackageId>
<Title>Build package for SMAPI mods</Title>
- <Version>4.0.1</Version>
+ <Version>4.0.2</Version>
<Authors>Pathoschild</Authors>
<Description>Automates the build configuration for crossplatform Stardew Valley SMAPI mods. For SMAPI 3.13.0 or later.</Description>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
diff --git a/src/SMAPI.ModBuildConfig/build/smapi.targets b/src/SMAPI.ModBuildConfig/build/smapi.targets
index 12619439..b4fd312e 100644
--- a/src/SMAPI.ModBuildConfig/build/smapi.targets
+++ b/src/SMAPI.ModBuildConfig/build/smapi.targets
@@ -27,8 +27,12 @@
<EnableGameDebugging Condition="'$(EnableGameDebugging)' == ''">true</EnableGameDebugging>
<BundleExtraAssemblies Condition="'$(BundleExtraAssemblies)' == ''"></BundleExtraAssemblies>
+ <!-- simplify conditions -->
+ <_BundleExtraAssembliesForGame>$([System.Text.RegularExpressions.Regex]::IsMatch('$(BundleExtraAssemblies)', '\bGame|All\b', RegexOptions.IgnoreCase))</_BundleExtraAssembliesForGame>
+ <_BundleExtraAssembliesForAny>$([System.Text.RegularExpressions.Regex]::IsMatch('$(BundleExtraAssemblies)', '\bGame|System|ThirdParty|All\b', RegexOptions.IgnoreCase))</_BundleExtraAssembliesForAny>
+
<!-- coppy referenced DLLs into build output -->
- <CopyLocalLockFileAssemblies Condition="$(BundleExtraAssemblies.Contains('ThirdParty')) OR $(BundleExtraAssemblies.Contains('Game')) OR $(BundleExtraAssemblies.Contains('System')) OR $(BundleExtraAssemblies.Contains('All'))">true</CopyLocalLockFileAssemblies>
+ <CopyLocalLockFileAssemblies Condition="$(_BundleExtraAssembliesForAny)">true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<PropertyGroup Condition="'$(OS)' == 'Windows_NT' AND '$(EnableGameDebugging)' == 'true'">
@@ -44,17 +48,17 @@
**********************************************-->
<ItemGroup>
<!-- game -->
- <Reference Include="Stardew Valley" HintPath="$(GamePath)\Stardew Valley.dll" Private="$(BundleExtraAssemblies.Contains('Game'))" />
- <Reference Include="StardewValley.GameData" HintPath="$(GamePath)\StardewValley.GameData.dll" Private="$(BundleExtraAssemblies.Contains('Game'))" />
- <Reference Include="MonoGame.Framework" HintPath="$(GamePath)\MonoGame.Framework.dll" Private="$(BundleExtraAssemblies.Contains('Game'))" />
- <Reference Include="xTile" HintPath="$(GamePath)\xTile.dll" Private="$(BundleExtraAssemblies.Contains('Game'))" />
+ <Reference Include="Stardew Valley" HintPath="$(GamePath)\Stardew Valley.dll" Private="$(_BundleExtraAssembliesForGame)" />
+ <Reference Include="StardewValley.GameData" HintPath="$(GamePath)\StardewValley.GameData.dll" Private="$(_BundleExtraAssembliesForGame)" />
+ <Reference Include="MonoGame.Framework" HintPath="$(GamePath)\MonoGame.Framework.dll" Private="$(_BundleExtraAssembliesForGame)" />
+ <Reference Include="xTile" HintPath="$(GamePath)\xTile.dll" Private="$(_BundleExtraAssembliesForGame)" />
<!-- SMAPI -->
- <Reference Include="StardewModdingAPI" HintPath="$(GamePath)\StardewModdingAPI.dll" Private="$(BundleExtraAssemblies.Contains('Game'))" />
- <Reference Include="SMAPI.Toolkit.CoreInterfaces" HintPath="$(GamePath)\smapi-internal\SMAPI.Toolkit.CoreInterfaces.dll" Private="$(BundleExtraAssemblies.Contains('Game'))" />
+ <Reference Include="StardewModdingAPI" HintPath="$(GamePath)\StardewModdingAPI.dll" Private="$(_BundleExtraAssembliesForGame)" />
+ <Reference Include="SMAPI.Toolkit.CoreInterfaces" HintPath="$(GamePath)\smapi-internal\SMAPI.Toolkit.CoreInterfaces.dll" Private="$(_BundleExtraAssembliesForGame)" />
<!-- Harmony -->
- <Reference Include="0Harmony" Condition="'$(EnableHarmony)' == 'true'" HintPath="$(GamePath)\smapi-internal\0Harmony.dll" Private="$(BundleExtraAssemblies.Contains('Game'))" />
+ <Reference Include="0Harmony" Condition="'$(EnableHarmony)' == 'true'" HintPath="$(GamePath)\smapi-internal\0Harmony.dll" Private="$(_BundleExtraAssembliesForGame)" />
</ItemGroup>
diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetColorCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetColorCommand.cs
index 12a51bc9..ea9f1d82 100644
--- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetColorCommand.cs
+++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetColorCommand.cs
@@ -63,7 +63,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player
/// <param name="color">The color to set.</param>
private bool TryParseColor(string input, out Color color)
{
- string[] colorHexes = input.Split(new[] { ',' }, 3);
+ string[] colorHexes = input.Split(',', 3);
if (int.TryParse(colorHexes[0], out int r) && int.TryParse(colorHexes[1], out int g) && int.TryParse(colorHexes[2], out int b))
{
color = new Color(r, g, b);
diff --git a/src/SMAPI.Mods.ConsoleCommands/manifest.json b/src/SMAPI.Mods.ConsoleCommands/manifest.json
index abe8b334..754e543a 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.16.2",
+ "Version": "3.17.0",
"Description": "Adds SMAPI console commands that let you manipulate the game.",
"UniqueID": "SMAPI.ConsoleCommands",
"EntryDll": "ConsoleCommands.dll",
- "MinimumApiVersion": "3.16.2"
+ "MinimumApiVersion": "3.17.0"
}
diff --git a/src/SMAPI.Mods.ErrorHandler/manifest.json b/src/SMAPI.Mods.ErrorHandler/manifest.json
index b6764bc0..8f94e5ab 100644
--- a/src/SMAPI.Mods.ErrorHandler/manifest.json
+++ b/src/SMAPI.Mods.ErrorHandler/manifest.json
@@ -1,9 +1,9 @@
{
"Name": "Error Handler",
"Author": "SMAPI",
- "Version": "3.16.2",
+ "Version": "3.17.0",
"Description": "Handles some common vanilla errors to log more useful info or avoid breaking the game.",
"UniqueID": "SMAPI.ErrorHandler",
"EntryDll": "ErrorHandler.dll",
- "MinimumApiVersion": "3.16.2"
+ "MinimumApiVersion": "3.17.0"
}
diff --git a/src/SMAPI.Mods.SaveBackup/manifest.json b/src/SMAPI.Mods.SaveBackup/manifest.json
index a2657168..a9401fc3 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.16.2",
+ "Version": "3.17.0",
"Description": "Automatically backs up all your saves once per day into its folder.",
"UniqueID": "SMAPI.SaveBackup",
"EntryDll": "SaveBackup.dll",
- "MinimumApiVersion": "3.16.2"
+ "MinimumApiVersion": "3.17.0"
}
diff --git a/src/SMAPI.Tests/Utilities/KeybindListTests.cs b/src/SMAPI.Tests/Utilities/KeybindListTests.cs
index c4c086de..c5fd5daf 100644
--- a/src/SMAPI.Tests/Utilities/KeybindListTests.cs
+++ b/src/SMAPI.Tests/Utilities/KeybindListTests.cs
@@ -136,11 +136,11 @@ namespace SMAPI.Tests.Utilities
foreach (string rawPair in stateMap.Split(','))
{
// parse values
- string[] parts = rawPair.Split(new[] { ':' }, 2);
+ string[] parts = rawPair.Split(':', 2, StringSplitOptions.TrimEntries);
if (!Enum.TryParse(parts[0], ignoreCase: true, out SButton curButton))
- Assert.Fail($"The state map is invalid: unknown button value '{parts[0].Trim()}'");
+ Assert.Fail($"The state map is invalid: unknown button value '{parts[0]}'");
if (!Enum.TryParse(parts[1], ignoreCase: true, out SButtonState state))
- Assert.Fail($"The state map is invalid: unknown state value '{parts[1].Trim()}'");
+ Assert.Fail($"The state map is invalid: unknown state value '{parts[1]}'");
// get state
if (curButton == button)
diff --git a/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs b/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs
index fedadba6..77c0da5f 100644
--- a/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs
+++ b/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs
@@ -382,11 +382,11 @@ namespace SMAPI.Tests.Utilities
{
// act
string json = JsonConvert.SerializeObject(new SemanticVersion(versionStr));
- SemanticVersion after = JsonConvert.DeserializeObject<SemanticVersion>(json);
+ SemanticVersion? after = JsonConvert.DeserializeObject<SemanticVersion>(json);
// assert
Assert.IsNotNull(after, "The semantic version after deserialization is unexpectedly null.");
- Assert.AreEqual(versionStr, after.ToString(), "The semantic version after deserialization doesn't match the input version.");
+ Assert.AreEqual(versionStr, after!.ToString(), "The semantic version after deserialization doesn't match the input version.");
}
diff --git a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs
index 8e1538a5..66465ffe 100644
--- a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs
+++ b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs
@@ -9,6 +9,7 @@ using StardewModdingAPI.Toolkit.Utilities;
using System.Reflection;
#if SMAPI_FOR_WINDOWS
using Microsoft.Win32;
+using VdfParser;
#endif
namespace StardewModdingAPI.Toolkit.Framework.GameScanning
@@ -23,6 +24,9 @@ namespace StardewModdingAPI.Toolkit.Framework.GameScanning
/// <summary>The current OS.</summary>
private readonly Platform Platform;
+ /// <summary>The Steam app ID for Stardew Valley.</summary>
+ private const string SteamAppId = "413150";
+
/*********
** Public methods
@@ -145,7 +149,7 @@ namespace StardewModdingAPI.Toolkit.Framework.GameScanning
#if SMAPI_FOR_WINDOWS
IDictionary<string, string> registryKeys = new Dictionary<string, string>
{
- [@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 413150"] = "InstallLocation", // Steam
+ [@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App " + GameScanner.SteamAppId] = "InstallLocation", // Steam
[@"SOFTWARE\WOW6432Node\GOG.com\Games\1453375253"] = "PATH", // GOG on 64-bit Windows
};
foreach (var pair in registryKeys)
@@ -158,7 +162,15 @@ namespace StardewModdingAPI.Toolkit.Framework.GameScanning
// via Steam library path
string? steamPath = this.GetCurrentUserRegistryValue(@"Software\Valve\Steam", "SteamPath");
if (steamPath != null)
+ {
+ // conventional path
yield return Path.Combine(steamPath.Replace('/', '\\'), @"steamapps\common\Stardew Valley");
+
+ // from Steam's .vdf file
+ string? path = this.GetPathFromSteamLibrary(steamPath);
+ if (!string.IsNullOrWhiteSpace(path))
+ yield return path;
+ }
#endif
// default GOG/Steam paths
@@ -243,6 +255,42 @@ namespace StardewModdingAPI.Toolkit.Framework.GameScanning
using (openKey)
return (string?)openKey.GetValue(name);
}
+
+ /// <summary>Get the game directory path from alternative Steam library locations.</summary>
+ /// <param name="steamPath">The full path to the directory containing steam.exe.</param>
+ /// <returns>The game directory, if found.</returns>
+ private string? GetPathFromSteamLibrary(string? steamPath)
+ {
+ if (steamPath == null)
+ return null;
+
+ // get raw .vdf data
+ string libraryFoldersPath = Path.Combine(steamPath.Replace('/', '\\'), "steamapps\\libraryfolders.vdf");
+ using FileStream fileStream = File.OpenRead(libraryFoldersPath);
+ VdfDeserializer deserializer = new();
+ dynamic libraries = deserializer.Deserialize(fileStream);
+ if (libraries?.libraryfolders is null)
+ return null;
+
+ // get path from Stardew Valley app (if any)
+ foreach (dynamic pair in libraries.libraryfolders)
+ {
+ dynamic library = pair.Value;
+
+ foreach (dynamic app in library.apps)
+ {
+ string key = app.Key;
+ if (key == GameScanner.SteamAppId)
+ {
+ string path = library.path;
+
+ return Path.Combine(path.Replace("\\\\", "\\"), "steamapps", "common", "Stardew Valley");
+ }
+ }
+ }
+
+ return null;
+ }
#endif
}
}
diff --git a/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs b/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs
index a85ef109..5e9e3c35 100644
--- a/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs
+++ b/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs
@@ -45,10 +45,14 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning
".png",
".psd",
".tif",
+ ".xcf", // gimp files
// archives
".rar",
".zip",
+ ".7z",
+ ".tar",
+ ".tar.gz",
// backup files
".backup",
diff --git a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj
index 7b79105f..10f1df70 100644
--- a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj
+++ b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj
@@ -11,9 +11,10 @@
<ItemGroup>
<PackageReference Include="HtmlAgilityPack" Version="1.11.43" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
- <PackageReference Include="Pathoschild.Http.FluentClient" Version="4.1.1" />
+ <PackageReference Include="Pathoschild.Http.FluentClient" Version="4.2.0" />
<PackageReference Include="System.Management" Version="5.0.0" Condition="'$(OS)' == 'Windows_NT'" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" Condition="'$(OS)' == 'Windows_NT'" />
+ <PackageReference Include="VdfConverter" Version="1.0.3" Condition="'$(OS)' == 'Windows_NT'" Private="False" />
</ItemGroup>
<ItemGroup>
diff --git a/src/SMAPI.Toolkit/Serialization/Models/Manifest.cs b/src/SMAPI.Toolkit/Serialization/Models/Manifest.cs
index da3ad608..8a449f0a 100644
--- a/src/SMAPI.Toolkit/Serialization/Models/Manifest.cs
+++ b/src/SMAPI.Toolkit/Serialization/Models/Manifest.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
+using System.Text;
using Newtonsoft.Json;
using StardewModdingAPI.Toolkit.Serialization.Converters;
@@ -90,13 +91,13 @@ namespace StardewModdingAPI.Toolkit.Serialization.Models
[JsonConstructor]
public Manifest(string uniqueId, string name, string author, string description, ISemanticVersion version, ISemanticVersion? minimumApiVersion, string? entryDll, IManifestContentPackFor? contentPackFor, IManifestDependency[]? dependencies, string[]? updateKeys)
{
- this.UniqueID = this.NormalizeWhitespace(uniqueId);
- this.Name = this.NormalizeWhitespace(name);
- this.Author = this.NormalizeWhitespace(author);
- this.Description = this.NormalizeWhitespace(description);
+ this.UniqueID = this.NormalizeField(uniqueId);
+ this.Name = this.NormalizeField(name, replaceSquareBrackets: true);
+ this.Author = this.NormalizeField(author);
+ this.Description = this.NormalizeField(description);
this.Version = version;
this.MinimumApiVersion = minimumApiVersion;
- this.EntryDll = this.NormalizeWhitespace(entryDll);
+ this.EntryDll = this.NormalizeField(entryDll);
this.ContentPackFor = contentPackFor;
this.Dependencies = dependencies ?? Array.Empty<IManifestDependency>();
this.UpdateKeys = updateKeys ?? Array.Empty<string>();
@@ -113,17 +114,47 @@ namespace StardewModdingAPI.Toolkit.Serialization.Models
/*********
** Private methods
*********/
- /// <summary>Normalize whitespace in a raw string.</summary>
+ /// <summary>Normalize a manifest field to strip newlines, trim whitespace, and optionally strip square brackets.</summary>
/// <param name="input">The input to strip.</param>
+ /// <param name="replaceSquareBrackets">Whether to replace square brackets with round ones. This is used in the mod name to avoid breaking the log format.</param>
#if NET5_0_OR_GREATER
[return: NotNullIfNotNull("input")]
#endif
- private string? NormalizeWhitespace(string? input)
+ private string? NormalizeField(string? input, bool replaceSquareBrackets = false)
{
- return input
- ?.Trim()
- .Replace("\r", "")
- .Replace("\n", "");
+ input = input?.Trim();
+
+ if (!string.IsNullOrEmpty(input))
+ {
+ StringBuilder? builder = null;
+
+ for (int i = 0; i < input.Length; i++)
+ {
+ switch (input[i])
+ {
+ case '\r':
+ case '\n':
+ builder ??= new StringBuilder(input);
+ builder[i] = ' ';
+ break;
+
+ case '[' when replaceSquareBrackets:
+ builder ??= new StringBuilder(input);
+ builder[i] = '(';
+ break;
+
+ case ']' when replaceSquareBrackets:
+ builder ??= new StringBuilder(input);
+ builder[i] = ')';
+ break;
+ }
+ }
+
+ if (builder != null)
+ input = builder.ToString();
+ }
+
+ return input;
}
}
}
diff --git a/src/SMAPI.Web/Controllers/ModsApiController.cs b/src/SMAPI.Web/Controllers/ModsApiController.cs
index 401bba4f..71fb42c2 100644
--- a/src/SMAPI.Web/Controllers/ModsApiController.cs
+++ b/src/SMAPI.Web/Controllers/ModsApiController.cs
@@ -159,11 +159,20 @@ namespace StardewModdingAPI.Web.Controllers
continue;
}
+ // if there's only a prerelease version (e.g. from GitHub), don't override the main version
+ ISemanticVersion? curMain = data.Version;
+ ISemanticVersion? curPreview = data.PreviewVersion;
+ if (curPreview == null && curMain?.IsPrerelease() == true)
+ {
+ curPreview = curMain;
+ curMain = null;
+ }
+
// handle versions
- if (this.IsNewer(data.Version, main?.Version))
- main = new ModEntryVersionModel(data.Version, data.Url!);
- if (this.IsNewer(data.PreviewVersion, optional?.Version))
- optional = new ModEntryVersionModel(data.PreviewVersion, data.Url!);
+ if (this.IsNewer(curMain, main?.Version))
+ main = new ModEntryVersionModel(curMain, data.Url!);
+ if (this.IsNewer(curPreview, optional?.Version))
+ optional = new ModEntryVersionModel(curPreview, data.Url!);
}
// get unofficial version
diff --git a/src/SMAPI.Web/Framework/Clients/Nexus/NexusClient.cs b/src/SMAPI.Web/Framework/Clients/Nexus/NexusClient.cs
index 23b25f95..46c3092c 100644
--- a/src/SMAPI.Web/Framework/Clients/Nexus/NexusClient.cs
+++ b/src/SMAPI.Web/Framework/Clients/Nexus/NexusClient.cs
@@ -121,10 +121,10 @@ namespace StardewModdingAPI.Web.Framework.Clients.Nexus
HtmlNode? node = doc.DocumentNode.SelectSingleNode("//div[contains(@class, 'site-notice')][contains(@class, 'warning')]");
if (node != null)
{
- string[] errorParts = node.InnerText.Trim().Split(new[] { '\n' }, 2, System.StringSplitOptions.RemoveEmptyEntries);
+ string[] errorParts = node.InnerText.Trim().Split('\n', 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
string errorCode = errorParts[0];
string? errorText = errorParts.Length > 1 ? errorParts[1] : null;
- switch (errorCode.Trim().ToLower())
+ switch (errorCode.ToLower())
{
case "not found":
return null;
diff --git a/src/SMAPI.Web/Framework/LogParsing/LogParser.cs b/src/SMAPI.Web/Framework/LogParsing/LogParser.cs
index 18ba754c..5e0dedf3 100644
--- a/src/SMAPI.Web/Framework/LogParsing/LogParser.cs
+++ b/src/SMAPI.Web/Framework/LogParsing/LogParser.cs
@@ -199,8 +199,15 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
log.ApiVersion = match.Groups["apiVersion"].Value;
log.GameVersion = match.Groups["gameVersion"].Value;
log.OperatingSystem = match.Groups["os"].Value;
- smapiMod.OverrideVersion(log.ApiVersion);
+ const string strictModeSuffix = " (strict mode)";
+ if (log.ApiVersion.EndsWith(strictModeSuffix))
+ {
+ log.IsStrictMode = true;
+ log.ApiVersion = log.ApiVersion[..^strictModeSuffix.Length];
+ }
+
+ smapiMod.OverrideVersion(log.ApiVersion);
log.ApiVersionParsed = smapiMod.GetParsedVersion();
}
diff --git a/src/SMAPI.Web/Framework/LogParsing/Models/ParsedLog.cs b/src/SMAPI.Web/Framework/LogParsing/Models/ParsedLog.cs
index 3f649199..cda0f653 100644
--- a/src/SMAPI.Web/Framework/LogParsing/Models/ParsedLog.cs
+++ b/src/SMAPI.Web/Framework/LogParsing/Models/ParsedLog.cs
@@ -25,6 +25,9 @@ namespace StardewModdingAPI.Web.Framework.LogParsing.Models
/****
** Log data
****/
+ /// <summary>Whether SMAPI is running in strict mode, which disables all deprecated APIs.</summary>
+ public bool IsStrictMode { get; set; }
+
/// <summary>The SMAPI version.</summary>
public string? ApiVersion { get; set; }
diff --git a/src/SMAPI.Web/SMAPI.Web.csproj b/src/SMAPI.Web/SMAPI.Web.csproj
index d26cb6f8..81b187fe 100644
--- a/src/SMAPI.Web/SMAPI.Web.csproj
+++ b/src/SMAPI.Web/SMAPI.Web.csproj
@@ -25,7 +25,7 @@
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.5" />
<PackageReference Include="Newtonsoft.Json.Schema" Version="3.0.14" />
<PackageReference Include="Pathoschild.FluentNexus" Version="1.0.5" />
- <PackageReference Include="Pathoschild.Http.FluentClient" Version="4.1.1" />
+ <PackageReference Include="Pathoschild.Http.FluentClient" Version="4.2.0" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.1" />
diff --git a/src/SMAPI.Web/Views/LogParser/Index.cshtml b/src/SMAPI.Web/Views/LogParser/Index.cshtml
index 24fe5fa2..28127903 100644
--- a/src/SMAPI.Web/Views/LogParser/Index.cshtml
+++ b/src/SMAPI.Web/Views/LogParser/Index.cshtml
@@ -40,7 +40,7 @@
<meta name="robots" content="noindex" />
}
<link rel="stylesheet" href="~/Content/css/file-upload.css" />
- <link rel="stylesheet" href="~/Content/css/log-parser.css" />
+ <link rel="stylesheet" href="~/Content/css/log-parser.css?r=20221009" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tabbyjs@12.0.3/dist/css/tabby-ui-vertical.min.css" />
<script src="https://cdn.jsdelivr.net/npm/tabbyjs@12.0.3" crossorigin="anonymous"></script>
@@ -243,7 +243,7 @@ else if (log?.IsValid == true)
@if (log?.IsValid == true)
{
<div id="output">
- @if (outdatedMods.Any() || errorHandler is null || hasOlderErrorHandler || isPyTkCompatibilityMode)
+ @if (outdatedMods.Any() || errorHandler is null || hasOlderErrorHandler || isPyTkCompatibilityMode || log.IsStrictMode)
{
<h2>Suggested fixes</h2>
<ul id="fix-list">
@@ -257,7 +257,14 @@ else if (log?.IsValid == true)
}
@if (isPyTkCompatibilityMode)
{
- <li>PyTK 1.23.* or earlier