diff options
author | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2021-01-22 21:05:04 -0500 |
---|---|---|
committer | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2021-01-22 21:05:04 -0500 |
commit | d0dc3ea6f6d03e6aabdab5f5f10a60177f0e53b6 (patch) | |
tree | 02896d970c7650d8f7c8b84f54e53eddab88b4ca /src/SMAPI.Toolkit | |
parent | 5953fc3bd083ae0a579d2da1ad833e6163848086 (diff) | |
parent | 733750fdc4f5d16069d95880144619c0e31e8a89 (diff) | |
download | SMAPI-d0dc3ea6f6d03e6aabdab5f5f10a60177f0e53b6.tar.gz SMAPI-d0dc3ea6f6d03e6aabdab5f5f10a60177f0e53b6.tar.bz2 SMAPI-d0dc3ea6f6d03e6aabdab5f5f10a60177f0e53b6.zip |
Merge branch 'develop' into stable
Diffstat (limited to 'src/SMAPI.Toolkit')
5 files changed, 88 insertions, 38 deletions
diff --git a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs index d4c82180..785daba3 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<string, string> registryKeys = new Dictionary<string, string> @@ -113,10 +105,19 @@ 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 + + // 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"; + } } break; 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 /// <summary>The folder is empty or contains only ignored files.</summary> EmptyFolder, + /// <summary>The folder is an empty folder managed by Vortex.</summary> + EmptyVortexFolder, + /// <summary>The folder is ignored by convention.</summary> IgnoredFolder, diff --git a/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs b/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs index 5eacee9e..86a97016 100644 --- a/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs +++ b/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs @@ -58,20 +58,28 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning ".lnk" }; - /// <summary>The extensions for files which an XNB mod may contain. If a mod doesn't have a <c>manifest.json</c> and contains *only* these file extensions, it should be considered an XNB mod.</summary> - private readonly HashSet<string> PotentialXnbModExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase) + /// <summary>The extensions for packed content files.</summary> + private readonly HashSet<string> StrictXnbModExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { - // XNB files ".xgs", ".xnb", ".xsb", - ".xwb", + ".xwb" + }; - // unpacking artifacts + /// <summary>The extensions for files which an XNB mod may contain, in addition to <see cref="StrictXnbModExtensions"/>.</summary> + private readonly HashSet<string> PotentialXnbModExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase) + { ".json", ".yaml" }; + /// <summary>The name of the marker file added by Vortex to indicate it's managing the folder.</summary> + private readonly string VortexMarkerFileName = "__folder_managed_by_vortex"; + + /// <summary>The name for a mod's configuration JSON file.</summary> + private readonly string ConfigFileName = "config.json"; + /********* ** Public methods @@ -111,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 (files.All(this.IsPotentialXnbFile)) + 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? @@ -270,13 +284,13 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning return subfolders.Any() && !files.Any(); } - /// <summary>Recursively get all relevant files in a folder based on the result of <see cref="IsRelevant"/>.</summary> + /// <summary>Recursively get all files in a folder.</summary> /// <param name="folder">The root folder to search.</param> - private IEnumerable<FileInfo> RecursivelyGetRelevantFiles(DirectoryInfo folder) + private IEnumerable<FileInfo> 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) @@ -284,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; } } @@ -302,14 +316,46 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning return !this.IgnoreFilesystemNames.Any(p => p.IsMatch(entry.Name)); } - /// <summary>Get whether a file is potentially part of an XNB mod.</summary> - /// <param name="entry">The file.</param> - private bool IsPotentialXnbFile(FileInfo entry) + /// <summary>Get whether a set of files looks like an XNB mod.</summary> + /// <param name="files">The files in the mod.</param> + private bool IsXnbMod(IEnumerable<FileInfo> 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 hasXnbFile; + } + + /// <summary>Get whether a set of files looks like an XNB mod.</summary> + /// <param name="files">The files in the mod.</param> + private bool IsEmptyVortexFolder(IEnumerable<FileInfo> 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 this.PotentialXnbModExtensions.Contains(entry.Extension); // use EndsWith to handle cases like image..png + return hasVortexMarker; } /// <summary>Strip newlines from a string.</summary> diff --git a/src/SMAPI.Toolkit/SemanticVersion.cs b/src/SMAPI.Toolkit/SemanticVersion.cs index d58dce0c..2f3e282b 100644 --- a/src/SMAPI.Toolkit/SemanticVersion.cs +++ b/src/SMAPI.Toolkit/SemanticVersion.cs @@ -293,12 +293,12 @@ namespace StardewModdingAPI.Toolkit return string.Compare(this.ToString(), new SemanticVersion(otherMajor, otherMinor, otherPatch, otherPlatformRelease, otherTag).ToString(), StringComparison.OrdinalIgnoreCase); } - return CompareToRaw() switch - { - (< 0) => curOlder, - (> 0) => curNewer, - _ => same - }; + int result = CompareToRaw(); + if (result < 0) + return curOlder; + if (result > 0) + return curNewer; + return same; } /// <summary>Assert that the current version is valid.</summary> diff --git a/src/SMAPI.Toolkit/Serialization/Converters/SemanticVersionConverter.cs b/src/SMAPI.Toolkit/Serialization/Converters/SemanticVersionConverter.cs index 3604956b..cf69104d 100644 --- a/src/SMAPI.Toolkit/Serialization/Converters/SemanticVersionConverter.cs +++ b/src/SMAPI.Toolkit/Serialization/Converters/SemanticVersionConverter.cs @@ -18,10 +18,10 @@ namespace StardewModdingAPI.Toolkit.Serialization.Converters ** Accessors *********/ /// <summary>Get whether this converter can read JSON.</summary> - public override bool CanRead => true; + public override bool CanRead { get; } = true; /// <summary>Get whether this converter can write JSON.</summary> - public override bool CanWrite => true; + public override bool CanWrite { get; } = true; /********* |