From 1a8c7345c3986acd172f91716bbf04fc7192317b Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 17 Jun 2019 18:51:31 -0400 Subject: add stardewvalley.targets support to toolkit --- docs/release-notes.md | 1 + .../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 /// 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. public IEnumerable Scan() { - // get unique candidate paths + // get OS info Platform platform = EnvironmentUtility.DetectPlatform(); string executableFilename = EnvironmentUtility.GetExecutableName(platform); - IEnumerable paths = this.GetDefaultInstallPaths(platform).Select(PathUtilities.NormalisePathSeparators).Distinct(StringComparer.InvariantCultureIgnoreCase); - // get valid folders + // get install paths + IEnumerable 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 } } + /// Get the custom install path from the stardewvalley.targets file in the home directory, if any. + /// The target platform. + private IEnumerable 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 /// Get the value of a key in the Windows HKLM registry. /// The full path of the registry key relative to HKLM. -- cgit