From cfe2c3975f8be62581195fbfffc41528f22b2ee3 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 17 Jan 2021 15:06:04 -0500 Subject: prefer GOG/Steam registry paths when scanning for game folder --- .../Framework/GameScanning/GameScanner.cs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'src/SMAPI.Toolkit/Framework') diff --git a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs index d4c82180..055e3b6d 100644 --- a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs +++ b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs @@ -90,14 +90,6 @@ namespace StardewModdingAPI.Toolkit.Framework.GameScanning 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 registryKeys = new Dictionary @@ -113,10 +105,18 @@ 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"); + string steamPath = this.GetCurrentUserRegistryValue(@"Software\Valve\Steam", "SteamPath"); + if (steamPath != null) + yield return Path.Combine(steamPath.Replace('/', '\\'), @"steamapps\common\Stardew Valley"); #endif + + // 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"; + } } break; -- cgit From bc71f994ece3943f02f91cdefbbe126cbef5a541 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 17 Jan 2021 15:11:45 -0500 Subject: improve game path detection --- build/find-game-folder.targets | 3 ++- docs/release-notes.md | 2 +- src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src/SMAPI.Toolkit/Framework') diff --git a/build/find-game-folder.targets b/build/find-game-folder.targets index 02abb54b..0a766ad4 100644 --- a/build/find-game-folder.targets +++ b/build/find-game-folder.targets @@ -31,12 +31,13 @@ C:\Program Files\GalaxyClient\Games\Stardew Valley C:\Program Files\GOG Galaxy\Games\Stardew Valley + C:\Program Files\GOG Games\Stardew Valley C:\Program Files\Steam\steamapps\common\Stardew Valley C:\Program Files (x86)\GalaxyClient\Games\Stardew Valley C:\Program Files (x86)\GOG Galaxy\Games\Stardew Valley + C:\Program Files (x86)\GOG Games\Stardew Valley C:\Program Files (x86)\Steam\steamapps\common\Stardew Valley - diff --git a/docs/release-notes.md b/docs/release-notes.md index 663ab667..bb379898 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -9,7 +9,7 @@ ## Upcoming release * For players: - * Improved game path detection. The installer now prefers the path installed through Steam or GOG Galaxy. + * Improved game path detection in the installer. The installer now prefers the path registered by Steam or GOG Galaxy, and can also now detect the default install path for manual GOG installs. * For modders: * Expanded `PerScreen` API: you can now get/set the value for any screen, get all active values, or clear all values. diff --git a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs index 055e3b6d..785daba3 100644 --- a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs +++ b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs @@ -110,11 +110,12 @@ namespace StardewModdingAPI.Toolkit.Framework.GameScanning yield return Path.Combine(steamPath.Replace('/', '\\'), @"steamapps\common\Stardew Valley"); #endif - // Windows + // default paths 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}\GOG Games\Stardew Valley"; yield return $@"{programFiles}\Steam\steamapps\common\Stardew Valley"; } } -- cgit From 7fc7a45102f856e84de36fdc5acc0bcb4d99afbb Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 21 Jan 2021 19:01:57 -0500 Subject: fix some broken mods incorrectly listed as XNB mods --- docs/release-notes.md | 5 ++- .../Framework/ModScanning/ModScanner.cs | 37 +++++++++++++++------- 2 files changed, 29 insertions(+), 13 deletions(-) (limited to 'src/SMAPI.Toolkit/Framework') diff --git a/docs/release-notes.md b/docs/release-notes.md index 279e43d2..7e3e48e5 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -9,8 +9,11 @@ ## Upcoming release * For players: - * Improved game path detection in the installer. The installer now prefers the path registered by Steam or GOG Galaxy, and can also now detect the default install path for manual GOG installs. + * Improved game detection in the installer: + * The installer now prefers paths registered by Steam or GOG Galaxy. + * The installer now detects default manual GOG installs. * Fixed compatibility for very old content packs which still load maps from `.xnb` files. These were broken by map loading changes in Stardew Valley 1.5, but SMAPI now corrects them automatically. + * Fixed some broken mods incorrectly listed as XNB mods under 'skipped mods'. * For modders: * Added new input APIs: diff --git a/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs b/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs index 5eacee9e..b2f09431 100644 --- a/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs +++ b/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs @@ -58,16 +58,18 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning ".lnk" }; - /// The extensions for files which an XNB mod may contain. If a mod doesn't have a manifest.json and contains *only* these file extensions, it should be considered an XNB mod. - private readonly HashSet PotentialXnbModExtensions = new HashSet(StringComparer.OrdinalIgnoreCase) + /// The extensions for packed content files. + private readonly HashSet StrictXnbModExtensions = new HashSet(StringComparer.OrdinalIgnoreCase) { - // XNB files ".xgs", ".xnb", ".xsb", - ".xwb", + ".xwb" + }; - // unpacking artifacts + /// The extensions for files which an XNB mod may contain, in addition to . + private readonly HashSet PotentialXnbModExtensions = new HashSet(StringComparer.OrdinalIgnoreCase) + { ".json", ".yaml" }; @@ -118,7 +120,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning return new ModFolder(root, searchFolder, ModType.Invalid, null, ModParseError.EmptyFolder, "it's an empty folder."); // XNB mod - if (files.All(this.IsPotentialXnbFile)) + if (this.IsXnbMod(files)) return new ModFolder(root, searchFolder, ModType.Xnb, null, ModParseError.XnbMod, "it's not a SMAPI mod (see https://smapi.io/xnb for info)."); // SMAPI installer @@ -302,14 +304,25 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning return !this.IgnoreFilesystemNames.Any(p => p.IsMatch(entry.Name)); } - /// Get whether a file is potentially part of an XNB mod. - /// The file. - private bool IsPotentialXnbFile(FileInfo entry) + /// Get whether a set of files looks like an XNB mod. + /// The files in the mod. + private bool IsXnbMod(IEnumerable files) { - if (!this.IsRelevant(entry)) - return true; + bool hasXnbFile = false; + + foreach (FileInfo file in files.Where(this.IsRelevant)) + { + if (this.StrictXnbModExtensions.Contains(file.Extension)) + { + hasXnbFile = true; + continue; + } + + if (!this.PotentialXnbModExtensions.Contains(file.Extension)) + return false; + } - return this.PotentialXnbModExtensions.Contains(entry.Extension); // use EndsWith to handle cases like image..png + return hasXnbFile; } /// Strip newlines from a string. -- cgit From 546012da8c6ab5e29f34926cda47756d6d18c326 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 21 Jan 2021 19:04:34 -0500 Subject: add clearer error for empty Vortex folders to reduce confusion --- docs/release-notes.md | 1 + .../Framework/ModScanning/ModParseError.cs | 3 ++ .../Framework/ModScanning/ModScanner.cs | 49 ++++++++++++++++++---- 3 files changed, 45 insertions(+), 8 deletions(-) (limited to 'src/SMAPI.Toolkit/Framework') diff --git a/docs/release-notes.md b/docs/release-notes.md index 7e3e48e5..58bc2826 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -12,6 +12,7 @@ * Improved game detection in the installer: * The installer now prefers paths registered by Steam or GOG Galaxy. * The installer now detects default manual GOG installs. + * Added clearer error when Vortex creates an empty mod folder. * Fixed compatibility for very old content packs which still load maps from `.xnb` files. These were broken by map loading changes in Stardew Valley 1.5, but SMAPI now corrects them automatically. * Fixed some broken mods incorrectly listed as XNB mods under 'skipped mods'. diff --git a/src/SMAPI.Toolkit/Framework/ModScanning/ModParseError.cs b/src/SMAPI.Toolkit/Framework/ModScanning/ModParseError.cs index b10510ff..f1e782b6 100644 --- a/src/SMAPI.Toolkit/Framework/ModScanning/ModParseError.cs +++ b/src/SMAPI.Toolkit/Framework/ModScanning/ModParseError.cs @@ -9,6 +9,9 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning /// The folder is empty or contains only ignored files. EmptyFolder, + /// The folder is an empty folder managed by Vortex. + EmptyVortexFolder, + /// The folder is ignored by convention. IgnoredFolder, diff --git a/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs b/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs index b2f09431..86a97016 100644 --- a/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs +++ b/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs @@ -74,6 +74,12 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning ".yaml" }; + /// The name of the marker file added by Vortex to indicate it's managing the folder. + private readonly string VortexMarkerFileName = "__folder_managed_by_vortex"; + + /// The name for a mod's configuration JSON file. + private readonly string ConfigFileName = "config.json"; + /********* ** Public methods @@ -113,18 +119,24 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning // set appropriate invalid-mod error if (manifestFile == null) { - FileInfo[] files = this.RecursivelyGetRelevantFiles(searchFolder).ToArray(); + FileInfo[] files = this.RecursivelyGetFiles(searchFolder).ToArray(); + FileInfo[] relevantFiles = files.Where(this.IsRelevant).ToArray(); + + // empty Vortex folder + // (this filters relevant files internally so it can check for the normally-ignored Vortex marker file) + if (this.IsEmptyVortexFolder(files)) + return new ModFolder(root, searchFolder, ModType.Invalid, null, ModParseError.EmptyVortexFolder, "it's an empty Vortex folder (is the mod disabled in Vortex?)."); // empty folder - if (!files.Any()) + if (!relevantFiles.Any()) return new ModFolder(root, searchFolder, ModType.Invalid, null, ModParseError.EmptyFolder, "it's an empty folder."); // XNB mod - if (this.IsXnbMod(files)) + if (this.IsXnbMod(relevantFiles)) return new ModFolder(root, searchFolder, ModType.Xnb, null, ModParseError.XnbMod, "it's not a SMAPI mod (see https://smapi.io/xnb for info)."); // SMAPI installer - if (files.Any(p => p.Name == "install on Linux.sh" || p.Name == "install on Mac.command" || p.Name == "install on Windows.bat")) + if (relevantFiles.Any(p => p.Name == "install on Linux.sh" || p.Name == "install on Mac.command" || p.Name == "install on Windows.bat")) return new ModFolder(root, searchFolder, ModType.Invalid, null, ModParseError.ManifestMissing, "the SMAPI installer isn't a mod (you can delete this folder after running the installer file)."); // not a mod? @@ -272,13 +284,13 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning return subfolders.Any() && !files.Any(); } - /// Recursively get all relevant files in a folder based on the result of . + /// Recursively get all files in a folder. /// The root folder to search. - private IEnumerable RecursivelyGetRelevantFiles(DirectoryInfo folder) + private IEnumerable RecursivelyGetFiles(DirectoryInfo folder) { foreach (FileSystemInfo entry in folder.GetFileSystemInfos()) { - if (!this.IsRelevant(entry)) + if (entry is DirectoryInfo && !this.IsRelevant(entry)) continue; if (entry is FileInfo file) @@ -286,7 +298,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning if (entry is DirectoryInfo subfolder) { - foreach (FileInfo subfolderFile in this.RecursivelyGetRelevantFiles(subfolder)) + foreach (FileInfo subfolderFile in this.RecursivelyGetFiles(subfolder)) yield return subfolderFile; } } @@ -325,6 +337,27 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning return hasXnbFile; } + /// Get whether a set of files looks like an XNB mod. + /// The files in the mod. + private bool IsEmptyVortexFolder(IEnumerable files) + { + bool hasVortexMarker = false; + + foreach (FileInfo file in files) + { + if (file.Name == this.VortexMarkerFileName) + { + hasVortexMarker = true; + continue; + } + + if (this.IsRelevant(file) && file.Name != this.ConfigFileName) + return false; + } + + return hasVortexMarker; + } + /// Strip newlines from a string. /// The input to strip. private string StripNewlines(string input) -- cgit