summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2019-06-17 18:51:12 -0400
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2019-09-14 18:05:18 -0400
commita7544e5afb4ba7f12d248503106cc8d407c2bad1 (patch)
tree986ee649e5144de93ea03749ea6b041437c899a7 /src
parent46a0dd6236a39175e85c11eac44a710db1c07847 (diff)
downloadSMAPI-a7544e5afb4ba7f12d248503106cc8d407c2bad1.tar.gz
SMAPI-a7544e5afb4ba7f12d248503106cc8d407c2bad1.tar.bz2
SMAPI-a7544e5afb4ba7f12d248503106cc8d407c2bad1.zip
move game detection into toolkit for reuse
Diffstat (limited to 'src')
-rw-r--r--src/SMAPI.Installer/InteractiveInstaller.cs106
-rw-r--r--src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs129
-rw-r--r--src/SMAPI.Toolkit/ModToolkit.cs9
-rw-r--r--src/SMAPI.Toolkit/SMAPI.Toolkit.csproj1
4 files changed, 144 insertions, 101 deletions
diff --git a/src/SMAPI.Installer/InteractiveInstaller.cs b/src/SMAPI.Installer/InteractiveInstaller.cs
index c8d36b01..41400617 100644
--- a/src/SMAPI.Installer/InteractiveInstaller.cs
+++ b/src/SMAPI.Installer/InteractiveInstaller.cs
@@ -7,7 +7,6 @@ using System.Threading;
using Microsoft.Win32;
using StardewModdingApi.Installer.Enums;
using StardewModdingAPI.Installer.Framework;
-using StardewModdingAPI.Internal;
using StardewModdingAPI.Internal.ConsoleWriting;
using StardewModdingAPI.Toolkit;
using StardewModdingAPI.Toolkit.Framework.ModScanning;
@@ -37,64 +36,7 @@ namespace StardewModdingApi.Installer
"SMAPI.ConsoleCommands"
};
- /// <summary>The default file paths where Stardew Valley can be installed.</summary>
- /// <param name="platform">The target platform.</param>
- /// <remarks>Derived from the crossplatform mod config: https://github.com/Pathoschild/Stardew.ModBuildConfig. </remarks>
- private IEnumerable<string> GetDefaultInstallPaths(Platform platform)
- {
- switch (platform)
- {
- case Platform.Linux:
- case Platform.Mac:
- {
- string home = Environment.GetEnvironmentVariable("HOME");
- // Linux
- yield return $"{home}/GOG Games/Stardew Valley/game";
- yield return Directory.Exists($"{home}/.steam/steam/steamapps/common/Stardew Valley")
- ? $"{home}/.steam/steam/steamapps/common/Stardew Valley"
- : $"{home}/.local/share/Steam/steamapps/common/Stardew Valley";
-
- // Mac
- yield return "/Applications/Stardew Valley.app/Contents/MacOS";
- yield return $"{home}/Library/Application Support/Steam/steamapps/common/Stardew Valley/Contents/MacOS";
- }
- break;
-
- case Platform.Windows:
- {
- // Windows
- foreach (string programFiles in new[] { @"C:\Program Files", @"C:\Program Files (x86)" })
- {
- yield return $@"{programFiles}\GalaxyClient\Games\Stardew Valley";
- yield return $@"{programFiles}\GOG Galaxy\Games\Stardew Valley";
- yield return $@"{programFiles}\Steam\steamapps\common\Stardew Valley";
- }
-
- // Windows registry
- IDictionary<string, string> registryKeys = new Dictionary<string, string>
- {
- [@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 413150"] = "InstallLocation", // Steam
- [@"SOFTWARE\WOW6432Node\GOG.com\Games\1453375253"] = "PATH", // GOG on 64-bit Windows
- };
- foreach (var pair in registryKeys)
- {
- string path = this.GetLocalMachineRegistryValue(pair.Key, pair.Value);
- if (!string.IsNullOrWhiteSpace(path))
- yield return path;
- }
-
- // 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");
- }
- break;
-
- default:
- throw new InvalidOperationException($"Unknown platform '{platform}'.");
- }
- }
/// <summary>Get the absolute file or folder paths to remove when uninstalling SMAPI.</summary>
/// <param name="installDir">The folder for Stardew Valley and SMAPI.</param>
@@ -186,8 +128,9 @@ namespace StardewModdingApi.Installer
** Step 1: initial setup
*********/
/****
- ** Get platform & set window title
+ ** Get basic info & set window title
****/
+ ModToolkit toolkit = new ModToolkit();
Platform platform = EnvironmentUtility.DetectPlatform();
Console.Title = $"SMAPI {this.GetDisplayVersion(this.GetType().Assembly.GetName().Version)} installer on {platform} {EnvironmentUtility.GetFriendlyPlatformName(platform)}";
Console.WriteLine();
@@ -323,7 +266,7 @@ namespace StardewModdingApi.Installer
****/
// get game path
this.PrintInfo("Where is your game folder?");
- DirectoryInfo installDir = this.InteractivelyGetInstallPath(platform, gamePathArg);
+ DirectoryInfo installDir = this.InteractivelyGetInstallPath(platform, toolkit, gamePathArg);
if (installDir == null)
{
this.PrintError("Failed finding your game path.");
@@ -489,7 +432,6 @@ namespace StardewModdingApi.Installer
{
this.PrintDebug("Adding bundled mods...");
- ModToolkit toolkit = new ModToolkit();
ModFolder[] targetMods = toolkit.GetModFolders(paths.ModsPath).ToArray();
foreach (ModFolder sourceMod in toolkit.GetModFolders(bundledModsDir.FullName))
{
@@ -597,32 +539,6 @@ namespace StardewModdingApi.Installer
}
}
- /// <summary>Get the value of a key in the Windows HKLM registry.</summary>
- /// <param name="key">The full path of the registry key relative to HKLM.</param>
- /// <param name="name">The name of the value.</param>
- private string GetLocalMachineRegistryValue(string key, string name)
- {
- RegistryKey localMachine = Environment.Is64BitOperatingSystem ? RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64) : Registry.LocalMachine;
- RegistryKey openKey = localMachine.OpenSubKey(key);
- if (openKey == null)
- return null;
- using (openKey)
- return (string)openKey.GetValue(name);
- }
-
- /// <summary>Get the value of a key in the Windows HKCU registry.</summary>
- /// <param name="key">The full path of the registry key relative to HKCU.</param>
- /// <param name="name">The name of the value.</param>
- private string GetCurrentUserRegistryValue(string key, string name)
- {
- RegistryKey currentuser = Environment.Is64BitOperatingSystem ? RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64) : Registry.CurrentUser;
- RegistryKey openKey = currentuser.OpenSubKey(key);
- if (openKey == null)
- return null;
- using (openKey)
- return (string)openKey.GetValue(name);
- }
-
/// <summary>Print a message without formatting.</summary>
/// <param name="text">The text to print.</param>
private void PrintPlain(string text) => Console.WriteLine(text);
@@ -788,8 +704,9 @@ namespace StardewModdingApi.Installer
/// <summary>Interactively locate the game install path to update.</summary>
/// <param name="platform">The current platform.</param>
+ /// <param name="toolkit">The mod toolkit.</param>
/// <param name="specifiedPath">The path specified as a command-line argument (if any), which should override automatic path detection.</param>
- private DirectoryInfo InteractivelyGetInstallPath(Platform platform, string specifiedPath)
+ private DirectoryInfo InteractivelyGetInstallPath(Platform platform, ModToolkit toolkit, string specifiedPath)
{
// get executable name
string executableFilename = EnvironmentUtility.GetExecutableName(platform);
@@ -812,18 +729,7 @@ namespace StardewModdingApi.Installer
}
// get installed paths
- DirectoryInfo[] defaultPaths =
- (
- from path in this.GetDefaultInstallPaths(platform).Distinct(StringComparer.InvariantCultureIgnoreCase)
- let dir = new DirectoryInfo(path)
- where dir.Exists && dir.EnumerateFiles(executableFilename).Any()
- select dir
- )
- .GroupBy(p => p.FullName, StringComparer.InvariantCultureIgnoreCase) // ignore duplicate paths
- .Select(p => p.First())
- .ToArray();
-
- // choose where to install
+ DirectoryInfo[] defaultPaths = toolkit.GetGameFolders().ToArray();
if (defaultPaths.Any())
{
// only one path
diff --git a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs
new file mode 100644
index 00000000..1755a7db
--- /dev/null
+++ b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs
@@ -0,0 +1,129 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using StardewModdingAPI.Toolkit.Utilities;
+#if SMAPI_FOR_WINDOWS
+using Microsoft.Win32;
+#endif
+
+namespace StardewModdingAPI.Toolkit.Framework.GameScanning
+{
+ /// <summary>Finds installed game folders.</summary>
+ public class GameScanner
+ {
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Find all valid Stardew Valley install folders.</summary>
+ /// <remarks>This checks default game locations, and on Windows checks the Windows registry for GOG/Steam install data. A folder is considered 'valid' if it contains the Stardew Valley executable for the current OS.</remarks>
+ public IEnumerable<DirectoryInfo> Scan()
+ {
+ // get unique candidate paths
+ Platform platform = EnvironmentUtility.DetectPlatform();
+ string executableFilename = EnvironmentUtility.GetExecutableName(platform);
+ IEnumerable<string> paths = this.GetDefaultInstallPaths(platform).Select(PathUtilities.NormalisePathSeparators).Distinct(StringComparer.InvariantCultureIgnoreCase);
+
+ // get valid folders
+ foreach (string path in paths)
+ {
+ DirectoryInfo folder = new DirectoryInfo(path);
+ if (folder.Exists && folder.EnumerateFiles(executableFilename).Any())
+ yield return folder;
+ }
+ }
+
+
+ /*********
+ ** Private methods
+ *********/
+ /// <summary>The default file paths where Stardew Valley can be installed.</summary>
+ /// <param name="platform">The target platform.</param>
+ /// <remarks>Derived from the crossplatform mod config: https://github.com/Pathoschild/Stardew.ModBuildConfig. </remarks>
+ private IEnumerable<string> GetDefaultInstallPaths(Platform platform)
+ {
+ switch (platform)
+ {
+ case Platform.Linux:
+ case Platform.Mac:
+ {
+ string home = Environment.GetEnvironmentVariable("HOME");
+
+ // Linux
+ yield return $"{home}/GOG Games/Stardew Valley/game";
+ yield return Directory.Exists($"{home}/.steam/steam/steamapps/common/Stardew Valley")
+ ? $"{home}/.steam/steam/steamapps/common/Stardew Valley"
+ : $"{home}/.local/share/Steam/steamapps/common/Stardew Valley";
+
+ // Mac
+ yield return "/Applications/Stardew Valley.app/Contents/MacOS";
+ yield return $"{home}/Library/Application Support/Steam/steamapps/common/Stardew Valley/Contents/MacOS";
+ }
+ break;
+
+ case Platform.Windows:
+ {
+ // Windows
+ foreach (string programFiles in new[] { @"C:\Program Files", @"C:\Program Files (x86)" })
+ {
+ yield return $@"{programFiles}\GalaxyClient\Games\Stardew Valley";
+ yield return $@"{programFiles}\GOG Galaxy\Games\Stardew Valley";
+ yield return $@"{programFiles}\Steam\steamapps\common\Stardew Valley";
+ }
+
+ // Windows registry
+#if SMAPI_FOR_WINDOWS
+ IDictionary<string, string> registryKeys = new Dictionary<string, string>
+ {
+ [@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 413150"] = "InstallLocation", // Steam
+ [@"SOFTWARE\WOW6432Node\GOG.com\Games\1453375253"] = "PATH", // GOG on 64-bit Windows
+ };
+ foreach (var pair in registryKeys)
+ {
+ string path = this.GetLocalMachineRegistryValue(pair.Key, pair.Value);
+ if (!string.IsNullOrWhiteSpace(path))
+ yield return path;
+ }
+
+ // 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");
+#endif
+ }
+ break;
+
+ default:
+ throw new InvalidOperationException($"Unknown platform '{platform}'.");
+ }
+ }
+
+#if SMAPI_FOR_WINDOWS
+ /// <summary>Get the value of a key in the Windows HKLM registry.</summary>
+ /// <param name="key">The full path of the registry key relative to HKLM.</param>
+ /// <param name="name">The name of the value.</param>
+ private string GetLocalMachineRegistryValue(string key, string name)
+ {
+ RegistryKey localMachine = Environment.Is64BitOperatingSystem ? RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64) : Registry.LocalMachine;
+ RegistryKey openKey = localMachine.OpenSubKey(key);
+ if (openKey == null)
+ return null;
+ using (openKey)
+ return (string)openKey.GetValue(name);
+ }
+
+ /// <summary>Get the value of a key in the Windows HKCU registry.</summary>
+ /// <param name="key">The full path of the registry key relative to HKCU.</param>
+ /// <param name="name">The name of the value.</param>
+ private string GetCurrentUserRegistryValue(string key, string name)
+ {
+ RegistryKey currentuser = Environment.Is64BitOperatingSystem ? RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64) : Registry.CurrentUser;
+ RegistryKey openKey = currentuser.OpenSubKey(key);
+ if (openKey == null)
+ return null;
+ using (openKey)
+ return (string)openKey.GetValue(name);
+ }
+#endif
+ }
+}
diff --git a/src/SMAPI.Toolkit/ModToolkit.cs b/src/SMAPI.Toolkit/ModToolkit.cs
index f1da62a2..4b026b7a 100644
--- a/src/SMAPI.Toolkit/ModToolkit.cs
+++ b/src/SMAPI.Toolkit/ModToolkit.cs
@@ -5,6 +5,7 @@ using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;
using StardewModdingAPI.Toolkit.Framework.Clients.Wiki;
+using StardewModdingAPI.Toolkit.Framework.GameScanning;
using StardewModdingAPI.Toolkit.Framework.ModData;
using StardewModdingAPI.Toolkit.Framework.ModScanning;
using StardewModdingAPI.Toolkit.Serialisation;
@@ -46,6 +47,13 @@ namespace StardewModdingAPI.Toolkit
this.UserAgent = $"SMAPI Mod Handler Toolkit/{version}";
}
+ /// <summary>Find valid Stardew Valley install folders.</summary>
+ /// <remarks>This checks default game locations, and on Windows checks the Windows registry for GOG/Steam install data. A folder is considered 'valid' if it contains the Stardew Valley executable for the current OS.</remarks>
+ public IEnumerable<DirectoryInfo> GetGameFolders()
+ {
+ return new GameScanner().Scan();
+ }
+
/// <summary>Extract mod metadata from the wiki compatibility list.</summary>
public async Task<WikiModList> GetWikiCompatibilityListAsync()
{
@@ -72,7 +80,6 @@ namespace StardewModdingAPI.Toolkit
/// <summary>Extract information about all mods in the given folder.</summary>
/// <param name="rootPath">The root folder containing mods. Only the <paramref name="modPath"/> will be searched, but this field allows it to be treated as a potential mod folder of its own.</param>
/// <param name="modPath">The mod path to search.</param>
- // /// <param name="tryConsolidateMod">If the folder contains multiple XNB mods, treat them as subfolders of a single mod. This is useful when reading a single mod archive, as opposed to a mods folder.</param>
public IEnumerable<ModFolder> GetModFolders(string rootPath, string modPath)
{
return new ModScanner(this.JsonHelper).GetModFolders(rootPath, modPath);
diff --git a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj
index 2be84316..53bbe1ac 100644
--- a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj
+++ b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj
@@ -19,6 +19,7 @@
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="Pathoschild.Http.FluentClient" Version="3.2.0" />
<PackageReference Include="System.Management" Version="4.5.0" Condition="'$(OS)' == 'Windows_NT'" />
+ <PackageReference Include="Microsoft.Win32.Registry" Version="4.5.0" Condition="'$(OS)' == 'Windows_NT' AND '$(TargetFramework)' == 'netstandard2.0'" />
</ItemGroup>
<ItemGroup>