diff options
author | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2019-06-17 18:51:31 -0400 |
---|---|---|
committer | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2019-09-14 18:10:41 -0400 |
commit | 1a8c7345c3986acd172f91716bbf04fc7192317b (patch) | |
tree | 913761e1c3586c91cbff0c8897e81130f79e2947 | |
parent | a7544e5afb4ba7f12d248503106cc8d407c2bad1 (diff) | |
download | SMAPI-1a8c7345c3986acd172f91716bbf04fc7192317b.tar.gz SMAPI-1a8c7345c3986acd172f91716bbf04fc7192317b.tar.bz2 SMAPI-1a8c7345c3986acd172f91716bbf04fc7192317b.zip |
add stardewvalley.targets support to toolkit
-rw-r--r-- | docs/release-notes.md | 1 | ||||
-rw-r--r-- | src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs | 46 |
2 files changed, 44 insertions, 3 deletions
diff --git a/docs/release-notes.md b/docs/release-notes.md index 6d883baf..efac8f41 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -28,6 +28,7 @@ These changes have not been released yet. * Added `Context.IsGameLaunched` field. * Mods are now loaded much earlier in the game launch. This lets mods intercept any content asset, but the game is not fully initialised when `Entry` is called (use the `GameLaunched` event if you need to run code when the game is initialised). * Added separate `LogNetworkTraffic` option to make verbose logging less overwhelmingly verbose. + * The installer now recognises custom game paths stored in `stardewvalley.targets`, if any. * When a mod is incompatible, the trace logs now list all detected issues instead of the first one. * Removed all deprecated APIs. * Removed the `Monitor.ExitGameImmediately` method. diff --git a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs index 1755a7db..60c7a682 100644 --- a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs +++ b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs @@ -2,6 +2,8 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Xml.Linq; +using System.Xml.XPath; using StardewModdingAPI.Toolkit.Utilities; #if SMAPI_FOR_WINDOWS using Microsoft.Win32; @@ -19,12 +21,18 @@ namespace StardewModdingAPI.Toolkit.Framework.GameScanning /// <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 + // get OS info Platform platform = EnvironmentUtility.DetectPlatform(); string executableFilename = EnvironmentUtility.GetExecutableName(platform); - IEnumerable<string> paths = this.GetDefaultInstallPaths(platform).Select(PathUtilities.NormalisePathSeparators).Distinct(StringComparer.InvariantCultureIgnoreCase); - // get valid folders + // get install paths + IEnumerable<string> paths = this + .GetCustomInstallPaths(platform) + .Concat(this.GetDefaultInstallPaths(platform)) + .Select(PathUtilities.NormalisePathSeparators) + .Distinct(StringComparer.InvariantCultureIgnoreCase); + + // yield valid folders foreach (string path in paths) { DirectoryInfo folder = new DirectoryInfo(path); @@ -98,6 +106,38 @@ namespace StardewModdingAPI.Toolkit.Framework.GameScanning } } + /// <summary>Get the custom install path from the <c>stardewvalley.targets</c> file in the home directory, if any.</summary> + /// <param name="platform">The target platform.</param> + private IEnumerable<string> GetCustomInstallPaths(Platform platform) + { + // get home path + string homePath = Environment.GetEnvironmentVariable(platform == Platform.Windows ? "USERPROFILE" : "HOME"); + if (string.IsNullOrWhiteSpace(homePath)) + yield break; + + // get targets file + FileInfo file = new FileInfo(Path.Combine(homePath, "stardewvalley.targets")); + if (!file.Exists) + yield break; + + // parse file + XElement root; + try + { + using (FileStream stream = file.OpenRead()) + root = XElement.Load(stream); + } + catch + { + yield break; + } + + // get install path + XElement element = root.XPathSelectElement("//*[local-name() = 'GamePath']"); // can't use '//GamePath' due to the default namespace + if (!string.IsNullOrWhiteSpace(element?.Value)) + yield return element.Value.Trim(); + } + #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> |