summaryrefslogtreecommitdiff
path: root/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs')
-rw-r--r--src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs65
1 files changed, 64 insertions, 1 deletions
diff --git a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs
index 8e1538a5..88142805 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,57 @@ 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)
+ {
+ try
+ {
+ if (steamPath == null)
+ return null;
+
+ // get .vdf file path
+ string libraryFoldersPath = Path.Combine(steamPath.Replace('/', '\\'), "steamapps\\libraryfolders.vdf");
+ if (!File.Exists(libraryFoldersPath))
+ return null;
+
+ // read data
+ 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;
+ }
+ catch
+ {
+ // The file might not be parseable in some cases (e.g. some players have an older Steam version using
+ // a different format). Ideally we'd log an error to know when it's actually an issue, but the SMAPI
+ // installer doesn't have a logging mechanism (and third-party code calling the toolkit may not either).
+ // So for now, just ignore the error and fallback to the other discovery mechanisms.
+ return null;
+ }
+ }
#endif
}
}