summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2022-10-09 20:11:34 -0400
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2022-10-09 20:11:34 -0400
commit93a748996c1f728a1daafd2e69775c7eeb346b26 (patch)
tree2eeecc639014a6558e3d0f3ca41f65b429211412
parente7d29a2f7dabde75fb1ad76af1975c9194b1b8bd (diff)
parentee77efcc976ef1a5ee64933a6174d2fac9c6d0f9 (diff)
downloadSMAPI-93a748996c1f728a1daafd2e69775c7eeb346b26.tar.gz
SMAPI-93a748996c1f728a1daafd2e69775c7eeb346b26.tar.bz2
SMAPI-93a748996c1f728a1daafd2e69775c7eeb346b26.zip
Merge branch 'develop' into stable
-rw-r--r--build/0Harmony.dllbin238592 -> 241152 bytes
-rw-r--r--build/0Harmony.xml27
-rw-r--r--build/common.targets2
-rw-r--r--build/windows/prepare-install-package.ps14
-rw-r--r--docs/release-notes.md22
-rw-r--r--docs/technical/mod-package.md6
-rw-r--r--docs/technical/smapi.md4
-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
47 files changed, 612 insertions, 247 deletions
diff --git a/build/0Harmony.dll b/build/0Harmony.dll
index 492255be..72ca2b61 100644
--- a/build/0Harmony.dll
+++ b/build/0Harmony.dll
Binary files differ
diff --git a/build/0Harmony.xml b/build/0Harmony.xml
index 8499d20b..f1b9b4cf 100644
--- a/build/0Harmony.xml
+++ b/build/0Harmony.xml
@@ -845,7 +845,7 @@
</member>
<member name="F:HarmonyLib.ExceptionBlockType.BeginExceptFilterBlock">
- <summary>The beginning of an except filter block</summary>
+ <summary>The beginning of an except filter block (currently not supported to use in a patch)</summary>
</member>
<member name="F:HarmonyLib.ExceptionBlockType.BeginFaultBlock">
@@ -2661,6 +2661,18 @@
<param name="name">The optional name</param>
</member>
+ <member name="M:HarmonyLib.CodeMatch.#ctor(System.Linq.Expressions.Expression{System.Action},System.String)">
+ <summary>Creates a code match that calls a method</summary>
+ <param name="expression">The lambda expression using the method</param>
+ <param name="name">The optional name</param>
+
+ </member>
+ <member name="M:HarmonyLib.CodeMatch.#ctor(System.Linq.Expressions.LambdaExpression,System.String)">
+ <summary>Creates a code match that calls a method</summary>
+ <param name="expression">The lambda expression using the method</param>
+ <param name="name">The optional name</param>
+
+ </member>
<member name="M:HarmonyLib.CodeMatch.#ctor(HarmonyLib.CodeInstruction,System.String)">
<summary>Creates a code match</summary>
<param name="instruction">The CodeInstruction</param>
@@ -3217,6 +3229,13 @@
<returns>True if the instruction loads the constant</returns>
</member>
+ <member name="M:HarmonyLib.CodeInstructionExtensions.LoadsConstant(HarmonyLib.CodeInstruction,System.String)">
+ <summary>Tests if the code instruction loads a string constant</summary>
+ <param name="code">The <see cref="T:HarmonyLib.CodeInstruction"/></param>
+ <param name="str">The string</param>
+ <returns>True if the instruction loads the constant</returns>
+
+ </member>
<member name="M:HarmonyLib.CodeInstructionExtensions.LoadsField(HarmonyLib.CodeInstruction,System.Reflection.FieldInfo,System.Boolean)">
<summary>Tests if the code instruction loads a field</summary>
<param name="code">The <see cref="T:HarmonyLib.CodeInstruction"/></param>
@@ -3346,7 +3365,11 @@
<summary>A file log for debugging</summary>
</member>
- <member name="F:HarmonyLib.FileLog.logPath">
+ <member name="P:HarmonyLib.FileLog.LogWriter">
+ <summary>Set this to make Harmony write its log content to this stream</summary>
+
+ </member>
+ <member name="P:HarmonyLib.FileLog.LogPath">
<summary>Full pathname of the log file, defaults to a file called <c>harmony.log.txt</c> on your Desktop</summary>
</member>
diff --git a/build/common.targets b/build/common.targets
index 7fe66fab..02cf69bd 100644
--- a/build/common.targets
+++ b/build/common.targets
@@ -7,7 +7,7 @@ repo. It imports the other MSBuild files as needed.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!--set general build properties -->
- <Version>3.16.2</Version>
+ <Version>3.17.0</Version>
<Product>SMAPI</Product>
<LangVersion>latest</LangVersion>
<AssemblySearchPaths>$(AssemblySearchPaths);{GAC}</AssemblySearchPaths>
diff --git a/build/windows/prepare-install-package.ps1 b/build/windows/prepare-install-package.ps1
index 87a4fe01..71de1154 100644
--- a/build/windows/prepare-install-package.ps1
+++ b/build/windows/prepare-install-package.ps1
@@ -158,6 +158,10 @@ foreach ($folder in $folders) {
cp "$smapiBin/$name" "$bundlePath/smapi-internal"
}
+ if ($folder -eq "windows") {
+ cp "$smapiBin/VdfConverter.dll" "$bundlePath/smapi-internal"
+ }
+
cp "$smapiBin/SMAPI.config.json" "$bundlePath/smapi-internal/config.json"
cp "$smapiBin/SMAPI.metadata.json" "$bundlePath/smapi-internal/metadata.json"
if ($folder -eq "linux" -or $folder -eq "macOS") {
diff --git a/docs/release-notes.md b/docs/release-notes.md
index ab23b46e..7574d62b 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -7,6 +7,28 @@
_If needed, you can update to SMAPI 3.16.0 first and then install the latest version._
-->
+## 3.17.0
+Released 09 October 2022 for Stardew Valley 1.5.6 or later. See [release highlights](https://www.patreon.com/posts/73090322).
+
+* For players:
+ * You can now download SMAPI 'strict mode' from [Nexus files](https://www.nexusmods.com/stardewvalley/mods/2400/?tab=files), which removes all deprecated APIs. This may significantly improve performance, but mods which still show deprecation warnings won't work.
+ * The SMAPI installer now also detects game folders in Steam's `.vdf` library data on Windows (thanks to pizzaoverhead!).
+ * SMAPI now prevents mods from enabling Harmony debug mode, which impacts performance and creates a file on your desktop.
+ _You can allow debug mode by editing `smapi-internal/config.json` in your game folder._
+ * Optimized performance and memory usage (thanks to atravita!).
+ * Other internal optimizations.
+ * Added more file extensions to ignore when searching for mod folders: `.7z`, `.tar`, `.tar.gz`, and `.xcf` (thanks to atravita!).
+ * Removed transitional `UseRawImageLoading` option added in 3.15.0. This is now always enabled, except when PyTK is installed.
+ * Fixed update alerts incorrectly shown for prerelease versions on GitHub that aren't marked as prerelease.
+
+* For mod authors:
+ * When [providing a mod API in a C# mod](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Integrations), you can now get the mod requesting it as an optional parameter (thanks to KhloeLeclair!).
+ * SMAPI now treats square brackets in the manifest `Name` field as round ones to avoid breaking tools which parse log files.
+ * Made deprecation message wording stronger for the upcoming SMAPI 4.0.0 release.
+ * The `Texture2D.Name` field is now set earlier to support mods like SpriteMaster.
+ * Updated dependencies: [Harmony](https://harmony.pardeike.net) 2.2.2 (see [changes](https://github.com/pardeike/Harmony/releases/tag/v2.2.2.0)) and [FluentHttpClient](https://github.com/Pathoschild/FluentHttpClient#readme) 4.2.0 (see [changes](https://github.com/Pathoschild/FluentHttpClient/blob/develop/RELEASE-NOTES.md#420)).
+ * Fixed `LocationListChanged` event not raised & memory leak occurring when a generated mine/volcano is removed (thanks to tylergibbs2!).
+
## 3.16.2
Released 31 August 2022 for Stardew Valley 1.5.6 or later.
diff --git a/docs/technical/mod-package.md b/docs/technical/mod-package.md
index ca78be55..77260a57 100644
--- a/docs/technical/mod-package.md
+++ b/docs/technical/mod-package.md
@@ -412,8 +412,12 @@ The NuGet package is generated automatically in `StardewModdingAPI.ModBuildConfi
when you compile it.
## Release notes
-### Upcoming release
+### 4.0.2
+Released 09 October 2022.
+
* Switched to the newer crossplatform `portable` debug symbols (thanks to lanturnalis!).
+* Fixed `BundleExtraAssemblies` option being partly case-sensitive.
+* Fixed `BundleExtraAssemblies` not applying `All` value to game assemblies.
### 4.0.1
Released 14 April 2022.
diff --git a/docs/technical/smapi.md b/docs/technical/smapi.md
index b8a1683b..d115aefa 100644
--- a/docs/technical/smapi.md
+++ b/docs/technical/smapi.md
@@ -78,8 +78,8 @@ the `SMAPI` project with debugging from Visual Studio or Rider should launch SMA
debugger attached, so you can intercept errors and step through the code being executed.
### Custom Harmony build
-SMAPI uses [a custom build of Harmony](https://github.com/Pathoschild/Harmony#readme), which is
-included in the `build` folder. To use a different build, just replace `0Harmony.dll` in that
+SMAPI uses [a custom build of Harmony 2.2.2](https://github.com/Pathoschild/Harmony#readme), which
+is included in the `build` folder. To use a different build, just replace `0Harmony.dll` in that
folder before compiling.
## Prepare a release
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.Too