summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs36
-rw-r--r--src/SMAPI.Toolkit/Framework/GameScanning/SteamLibraryCollection.cs47
-rw-r--r--src/SMAPI.Toolkit/SMAPI.Toolkit.csproj1
3 files changed, 84 insertions, 0 deletions
diff --git a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs
index 8e1538a5..8e24dcdf 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
@@ -158,7 +159,14 @@ namespace StardewModdingAPI.Toolkit.Framework.GameScanning
// via Steam library path
string? steamPath = this.GetCurrentUserRegistryValue(@"Software\Valve\Steam", "SteamPath");
if (steamPath != null)
+ {
yield return Path.Combine(steamPath.Replace('/', '\\'), @"steamapps\common\Stardew Valley");
+
+ // Check for Steam libraries in other locations
+ string? path = this.GetPathFromSteamLibrary(steamPath);
+ if (!string.IsNullOrWhiteSpace(path))
+ yield return path;
+ }
#endif
// default GOG/Steam paths
@@ -243,6 +251,34 @@ 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)
+ {
+ string stardewAppId = "413150";
+ if (steamPath != null)
+ {
+ string? libraryFoldersPath = Path.Combine(steamPath.Replace('/', '\\'), "steamapps\\libraryfolders.vdf");
+ using FileStream fs = File.OpenRead(libraryFoldersPath);
+ VdfDeserializer deserializer = new VdfDeserializer();
+ SteamLibraryCollection libraries = deserializer.Deserialize<SteamLibraryCollection>(fs);
+ if (libraries.libraryfolders != null)
+ {
+ var stardewLibrary = libraries.libraryfolders.FirstOrDefault(f =>
+ {
+ var apps = f.Value?.apps;
+ return apps != null && apps.Any(a => a.Key.Equals(stardewAppId));
+ });
+ if (stardewLibrary.Value?.path != null)
+ {
+ return Path.Combine(stardewLibrary.Value.path.Replace("\\\\", "\\"), @"steamapps\common\Stardew Valley");
+ }
+ }
+ }
+ return null;
+ }
#endif
}
}
diff --git a/src/SMAPI.Toolkit/Framework/GameScanning/SteamLibraryCollection.cs b/src/SMAPI.Toolkit/Framework/GameScanning/SteamLibraryCollection.cs
new file mode 100644
index 00000000..7a186f69
--- /dev/null
+++ b/src/SMAPI.Toolkit/Framework/GameScanning/SteamLibraryCollection.cs
@@ -0,0 +1,47 @@
+#if SMAPI_FOR_WINDOWS
+using System.Collections.Generic;
+
+namespace StardewModdingAPI.Toolkit.Framework.GameScanning
+{
+#pragma warning disable IDE1006 // Model requires lowercase naming.
+#pragma warning disable CS8618 // Required for model.
+ /// <summary>Model for Steam's libraryfolders.vdf.</summary>
+ public class SteamLibraryCollection
+ {
+ /// <summary>Each entry identifies a different location that part of the Steam games library is installed to.</summary>
+ public LibraryFolders<int, LibraryFolder> libraryfolders { get; set; }
+ }
+
+ /// <summary>A collection of LibraryFolders. Like a dictionary, but has contentstatsid used as an index also.</summary>
+ /// <typeparam name="TKey"></typeparam>
+ /// <typeparam name="TValue"></typeparam>
+#pragma warning disable CS8714 // Required for model.
+ public class LibraryFolders<TKey, TValue> : Dictionary<TKey, TValue>
+#pragma warning restore CS8714
+ {
+ /// <summary>Index of the library, starting from "0".</summary>
+ public string contentstatsid { get; set; }
+ }
+
+ /// <summary>A Steam library folder, containing information on the location and size of games installed there.</summary>
+ public class LibraryFolder
+ {
+ /// <summary>The escaped path to this Steam library folder. There will be a steam.exe here, but this may not be the one the player generally launches.</summary>
+ public string path { get; set; }
+ /// <summary>Label for the library, or ""</summary>
+ public string label { get; set; }
+ /// <summary>~19-digit identifier.</summary>
+ public string contentid { get; set; }
+ /// <summary>Size of the library in bytes. May show 0 when size is non-zero.</summary>
+ public string totalsize { get; set; }
+ /// <summary>Used for downloads.</summary>
+ public string update_clean_bytes_tally { get; set; }
+ /// <summary>Normally "0".</summary>
+ public string time_last_update_corruption { get; set; }
+ /// <summary>List of Steam app IDs, and their current size in bytes.</summary>
+ public Dictionary<string, string> apps { get; set; }
+ }
+#pragma warning restore IDE1006
+#pragma warning restore CS8618
+}
+#endif
diff --git a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj
index 7b79105f..411fd469 100644
--- a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj
+++ b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj
@@ -14,6 +14,7 @@
<PackageReference Include="Pathoschild.Http.FluentClient" Version="4.1.1" />
<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" />
</ItemGroup>
<ItemGroup>