From d74b710833edd19d2df2c0847a033078fa71a06e Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 1 May 2019 23:31:42 -0400 Subject: add mod type to mod scanner result --- src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs | 7 ++++++- .../Framework/ModScanning/ModScanner.cs | 20 +++++++++++++++----- src/SMAPI.Toolkit/Framework/ModScanning/ModType.cs | 18 ++++++++++++++++++ 3 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 src/SMAPI.Toolkit/Framework/ModScanning/ModType.cs (limited to 'src/SMAPI.Toolkit/Framework') diff --git a/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs b/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs index bb467b36..adfee527 100644 --- a/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs +++ b/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs @@ -18,6 +18,9 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning /// The folder containing the mod's manifest.json. public DirectoryInfo Directory { get; } + /// The mod type. + public ModType Type { get; } + /// The mod manifest. public Manifest Manifest { get; } @@ -34,13 +37,15 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning /// Construct an instance. /// The root folder containing mods. /// The folder containing the mod's manifest.json. + /// The mod type. /// The mod manifest. /// The error which occurred parsing the manifest, if any. /// Whether the mod should be loaded by default. This should be false if it was found within a folder whose name starts with a dot. - public ModFolder(DirectoryInfo root, DirectoryInfo directory, Manifest manifest, string manifestParseError = null, bool shouldBeLoaded = true) + public ModFolder(DirectoryInfo root, DirectoryInfo directory, ModType type, Manifest manifest, string manifestParseError = null, bool shouldBeLoaded = true) { // save info this.Directory = directory; + this.Type = type; this.Manifest = manifest; this.ManifestParseError = manifestParseError; this.ShouldBeLoaded = shouldBeLoaded; diff --git a/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs b/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs index 0ab73d56..507e7be2 100644 --- a/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs +++ b/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs @@ -65,10 +65,10 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning { FileInfo[] files = searchFolder.GetFiles("*", SearchOption.AllDirectories).Where(this.IsRelevant).ToArray(); if (!files.Any()) - return new ModFolder(root, searchFolder, null, "it's an empty folder."); + return new ModFolder(root, searchFolder, ModType.Invalid, null, "it's an empty folder."); if (files.All(file => this.PotentialXnbModExtensions.Contains(file.Extension))) - return new ModFolder(root, searchFolder, null, "it's not a SMAPI mod (see https://smapi.io/xnb for info)."); - return new ModFolder(root, searchFolder, null, "it contains files, but none of them are manifest.json."); + return new ModFolder(root, searchFolder, ModType.Xnb, null, "it's not a SMAPI mod (see https://smapi.io/xnb for info)."); + return new ModFolder(root, searchFolder, ModType.Invalid, null, "it contains files, but none of them are manifest.json."); } // read mod info @@ -98,7 +98,17 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning manifest.Author = this.StripNewlines(manifest.Author); } - return new ModFolder(root, manifestFile.Directory, manifest, manifestError); + // get mod type + ModType type = ModType.Invalid; + if (manifest != null) + { + type = !string.IsNullOrWhiteSpace(manifest.ContentPackFor?.UniqueID) + ? ModType.ContentPack + : ModType.Smapi; + } + + // build result + return new ModFolder(root, manifestFile.Directory, type, manifest, manifestError); } @@ -112,7 +122,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning { // skip if (folder.FullName != root.FullName && folder.Name.StartsWith(".")) - yield return new ModFolder(root, folder, null, "ignored folder because its name starts with a dot.", shouldBeLoaded: false); + yield return new ModFolder(root, folder, ModType.Invalid, null, "ignored folder because its name starts with a dot.", shouldBeLoaded: false); // recurse into subfolders else if (this.IsModSearchFolder(root, folder)) diff --git a/src/SMAPI.Toolkit/Framework/ModScanning/ModType.cs b/src/SMAPI.Toolkit/Framework/ModScanning/ModType.cs new file mode 100644 index 00000000..2ceb9e40 --- /dev/null +++ b/src/SMAPI.Toolkit/Framework/ModScanning/ModType.cs @@ -0,0 +1,18 @@ +namespace StardewModdingAPI.Toolkit.Framework.ModScanning +{ + /// A general mod type. + public enum ModType + { + /// The mod is invalid and its type could not be determined. + Invalid, + + /// A mod which uses SMAPI directly. + Smapi, + + /// A mod which contains files loaded by a SMAPI mod. + ContentPack, + + /// A legacy mod which replaces game files directly. + Xnb + } +} -- cgit From 30cc7ac9161e4cea91c3b566a7edb5e438af98cb Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 1 May 2019 23:45:50 -0400 Subject: consolidate XNB mods when scanning mods --- .../Framework/ModScanning/ModScanner.cs | 27 ++++++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'src/SMAPI.Toolkit/Framework') diff --git a/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs b/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs index 507e7be2..ae0f292f 100644 --- a/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs +++ b/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs @@ -52,6 +52,15 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning return this.GetModFolders(root, root); } + /// Extract information about all mods in the given folder. + /// The root folder containing mods. Only the will be searched, but this field allows it to be treated as a potential mod folder of its own. + /// The mod path to search. + // /// 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. + public IEnumerable GetModFolders(string rootPath, string modPath) + { + return this.GetModFolders(root: new DirectoryInfo(rootPath), folder: new DirectoryInfo(modPath)); + } + /// Extract information from a mod folder. /// The root folder containing mods. /// The folder to search for a mod. @@ -120,17 +129,25 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning /// The folder to search for mods. public IEnumerable GetModFolders(DirectoryInfo root, DirectoryInfo folder) { + bool isRoot = folder.FullName == root.FullName; + // skip - if (folder.FullName != root.FullName && folder.Name.StartsWith(".")) + if (!isRoot && folder.Name.StartsWith(".")) yield return new ModFolder(root, folder, ModType.Invalid, null, "ignored folder because its name starts with a dot.", shouldBeLoaded: false); - // recurse into subfolders + // find mods in subfolders else if (this.IsModSearchFolder(root, folder)) { - foreach (DirectoryInfo subfolder in folder.EnumerateDirectories()) + ModFolder[] subfolders = folder.EnumerateDirectories().SelectMany(sub => this.GetModFolders(root, sub)).ToArray(); + if (!isRoot && subfolders.Length > 1 && subfolders.All(p => p.Type == ModType.Xnb)) + { + // if this isn't the root, and all subfolders are XNB mods, treat the whole folder as one XNB mod + yield return new ModFolder(folder, folder, ModType.Xnb, null, subfolders[0].ManifestParseError); + } + else { - foreach (ModFolder match in this.GetModFolders(root, subfolder)) - yield return match; + foreach (ModFolder subfolder in subfolders) + yield return subfolder; } } -- cgit From 83ae036e09aab6830fcf83ae3065628d4ab91143 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 4 May 2019 13:53:34 -0400 Subject: improve XNB mod and ignore file matching --- .../Framework/ModScanning/ModFolder.cs | 20 ++- .../Framework/ModScanning/ModParseError.cs | 24 ++++ .../Framework/ModScanning/ModScanner.cs | 141 ++++++++++++++++----- src/SMAPI.Toolkit/Framework/ModScanning/ModType.cs | 3 + 4 files changed, 147 insertions(+), 41 deletions(-) create mode 100644 src/SMAPI.Toolkit/Framework/ModScanning/ModParseError.cs (limited to 'src/SMAPI.Toolkit/Framework') diff --git a/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs b/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs index adfee527..4ce17c66 100644 --- a/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs +++ b/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs @@ -25,30 +25,38 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning public Manifest Manifest { get; } /// The error which occurred parsing the manifest, if any. - public string ManifestParseError { get; } + public ModParseError ManifestParseError { get; set; } - /// Whether the mod should be loaded by default. This is false if it was found within a folder whose name starts with a dot. - public bool ShouldBeLoaded { get; } + /// A human-readable message for the , if any. + public string ManifestParseErrorText { get; set; } /********* ** Public methods *********/ + /// Construct an instance. + /// The root folder containing mods. + /// The folder containing the mod's manifest.json. + /// The mod type. + /// The mod manifest. + public ModFolder(DirectoryInfo root, DirectoryInfo directory, ModType type, Manifest manifest) + : this(root, directory, type, manifest, ModParseError.None, null) { } + /// Construct an instance. /// The root folder containing mods. /// The folder containing the mod's manifest.json. /// The mod type. /// The mod manifest. /// The error which occurred parsing the manifest, if any. - /// Whether the mod should be loaded by default. This should be false if it was found within a folder whose name starts with a dot. - public ModFolder(DirectoryInfo root, DirectoryInfo directory, ModType type, Manifest manifest, string manifestParseError = null, bool shouldBeLoaded = true) + /// A human-readable message for the , if any. + public ModFolder(DirectoryInfo root, DirectoryInfo directory, ModType type, Manifest manifest, ModParseError manifestParseError, string manifestParseErrorText) { // save info this.Directory = directory; this.Type = type; this.Manifest = manifest; this.ManifestParseError = manifestParseError; - this.ShouldBeLoaded = shouldBeLoaded; + this.ManifestParseErrorText = manifestParseErrorText; // set display name this.DisplayName = manifest?.Name; diff --git a/src/SMAPI.Toolkit/Framework/ModScanning/ModParseError.cs b/src/SMAPI.Toolkit/Framework/ModScanning/ModParseError.cs new file mode 100644 index 00000000..b10510ff --- /dev/null +++ b/src/SMAPI.Toolkit/Framework/ModScanning/ModParseError.cs @@ -0,0 +1,24 @@ +namespace StardewModdingAPI.Toolkit.Framework.ModScanning +{ + /// Indicates why a mod could not be parsed. + public enum ModParseError + { + /// No parse error. + None, + + /// The folder is empty or contains only ignored files. + EmptyFolder, + + /// The folder is ignored by convention. + IgnoredFolder, + + /// The mod's manifest.json could not be parsed. + ManifestInvalid, + + /// The folder contains non-ignored and non-XNB files, but none of them are manifest.json. + ManifestMissing, + + /// The folder is an XNB mod, which can't be loaded through SMAPI. + XnbMod + } +} diff --git a/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs b/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs index ae0f292f..54cb2b8b 100644 --- a/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs +++ b/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text.RegularExpressions; using StardewModdingAPI.Toolkit.Serialisation; using StardewModdingAPI.Toolkit.Serialisation.Models; @@ -17,20 +18,32 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning private readonly JsonHelper JsonHelper; /// A list of filesystem entry names to ignore when checking whether a folder should be treated as a mod. - private readonly HashSet IgnoreFilesystemEntries = new HashSet(StringComparer.InvariantCultureIgnoreCase) + private readonly HashSet IgnoreFilesystemEntries = new HashSet { - ".DS_Store", - "mcs", - "Thumbs.db" + // OS metadata files + new Regex(@"^__folder_managed_by_vortex$", RegexOptions.Compiled | RegexOptions.IgnoreCase), // Vortex mod manager + new Regex(@"^(?:__MACOSX|\._\.DS_Store|\.DS_Store|mcs)$", RegexOptions.Compiled | RegexOptions.IgnoreCase), // MacOS + new Regex(@"^(?:desktop\.ini|Thumbs\.db)$", RegexOptions.Compiled | RegexOptions.IgnoreCase), // Windows + new Regex(@"\.(?:url|lnk)$", RegexOptions.Compiled | RegexOptions.IgnoreCase), // Windows shortcut files + + // other + new Regex(@"\.(?:bmp|gif|jpeg|jpg|png|psd|tif)$", RegexOptions.Compiled | RegexOptions.IgnoreCase), // image files + new Regex(@"\.(?:md|rtf|txt)$", RegexOptions.Compiled | RegexOptions.IgnoreCase), // text files + new Regex(@"\.(?:backup|bak|old)$", RegexOptions.Compiled | RegexOptions.IgnoreCase) // backup file }; - /// The extensions for files which an XNB mod may contain. If a mod contains *only* these file extensions, it should be considered an XNB mod. + /// 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.InvariantCultureIgnoreCase) { - ".md", - ".png", - ".txt", - ".xnb" + // XNB files + ".xgs", + ".xnb", + ".xsb", + ".xwb", + + // unpacking artifacts + ".json", + ".yaml" }; @@ -72,30 +85,36 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning // set appropriate invalid-mod error if (manifestFile == null) { - FileInfo[] files = searchFolder.GetFiles("*", SearchOption.AllDirectories).Where(this.IsRelevant).ToArray(); + FileInfo[] files = this.RecursivelyGetRelevantFiles(searchFolder).ToArray(); if (!files.Any()) - return new ModFolder(root, searchFolder, ModType.Invalid, null, "it's an empty folder."); - if (files.All(file => this.PotentialXnbModExtensions.Contains(file.Extension))) - return new ModFolder(root, searchFolder, ModType.Xnb, null, "it's not a SMAPI mod (see https://smapi.io/xnb for info)."); - return new ModFolder(root, searchFolder, ModType.Invalid, null, "it contains files, but none of them are manifest.json."); + return new ModFolder(root, searchFolder, ModType.Invalid, null, ModParseError.EmptyFolder, "it's an empty folder."); + if (files.All(this.IsPotentialXnbFile)) + return new ModFolder(root, searchFolder, ModType.Xnb, null, ModParseError.XnbMod, "it's not a SMAPI mod (see https://smapi.io/xnb for info)."); + return new ModFolder(root, searchFolder, ModType.Invalid, null, ModParseError.ManifestMissing, "it contains files, but none of them are manifest.json."); } // read mod info Manifest manifest = null; - string manifestError = null; + ModParseError error = ModParseError.None; + string errorText = null; { try { if (!this.JsonHelper.ReadJsonFileIfExists(manifestFile.FullName, out manifest) || manifest == null) - manifestError = "its manifest is invalid."; + { + error = ModParseError.ManifestInvalid; + errorText = "its manifest is invalid."; + } } catch (SParseException ex) { - manifestError = $"parsing its manifest failed: {ex.Message}"; + error = ModParseError.ManifestInvalid; + errorText = $"parsing its manifest failed: {ex.Message}"; } catch (Exception ex) { - manifestError = $"parsing its manifest failed:\n{ex}"; + error = ModParseError.ManifestInvalid; + errorText = $"parsing its manifest failed:\n{ex}"; } } @@ -117,7 +136,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning } // build result - return new ModFolder(root, manifestFile.Directory, type, manifest, manifestError); + return new ModFolder(root, manifestFile.Directory, type, manifest, error, errorText); } @@ -127,28 +146,30 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning /// Recursively extract information about all mods in the given folder. /// The root mod folder. /// The folder to search for mods. - public IEnumerable GetModFolders(DirectoryInfo root, DirectoryInfo folder) + private IEnumerable GetModFolders(DirectoryInfo root, DirectoryInfo folder) { bool isRoot = folder.FullName == root.FullName; // skip - if (!isRoot && folder.Name.StartsWith(".")) - yield return new ModFolder(root, folder, ModType.Invalid, null, "ignored folder because its name starts with a dot.", shouldBeLoaded: false); - - // find mods in subfolders - else if (this.IsModSearchFolder(root, folder)) + if (!isRoot) { - ModFolder[] subfolders = folder.EnumerateDirectories().SelectMany(sub => this.GetModFolders(root, sub)).ToArray(); - if (!isRoot && subfolders.Length > 1 && subfolders.All(p => p.Type == ModType.Xnb)) + if (folder.Name.StartsWith(".")) { - // if this isn't the root, and all subfolders are XNB mods, treat the whole folder as one XNB mod - yield return new ModFolder(folder, folder, ModType.Xnb, null, subfolders[0].ManifestParseError); - } - else - { - foreach (ModFolder subfolder in subfolders) - yield return subfolder; + yield return new ModFolder(root, folder, ModType.Ignored, null, ModParseError.IgnoredFolder, "ignored folder because its name starts with a dot."); + yield break; } + if (!this.IsRelevant(folder)) + yield break; + } + + // find mods in subfolders + if (this.IsModSearchFolder(root, folder)) + { + IEnumerable subfolders = folder.EnumerateDirectories().SelectMany(sub => this.GetModFolders(root, sub)); + if (!isRoot) + subfolders = this.TryConsolidate(root, folder, subfolders.ToArray()); + foreach (ModFolder subfolder in subfolders) + yield return subfolder; } // treat as mod folder @@ -156,6 +177,26 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning yield return this.ReadFolder(root, folder); } + /// Consolidate adjacent folders into one mod folder, if possible. + /// The folder containing both parent and subfolders. + /// The parent folder to consolidate, if possible. + /// The subfolders to consolidate, if possible. + private IEnumerable TryConsolidate(DirectoryInfo root, DirectoryInfo parentFolder, ModFolder[] subfolders) + { + if (subfolders.Length > 1) + { + // a collection of empty folders + if (subfolders.All(p => p.ManifestParseError == ModParseError.EmptyFolder)) + return new[] { new ModFolder(root, parentFolder, ModType.Invalid, null, ModParseError.EmptyFolder, subfolders[0].ManifestParseErrorText) }; + + // an XNB mod + if (subfolders.All(p => p.Type == ModType.Xnb || p.ManifestParseError == ModParseError.EmptyFolder)) + return new[] { new ModFolder(root, parentFolder, ModType.Xnb, null, ModParseError.XnbMod, subfolders[0].ManifestParseErrorText) }; + } + + return subfolders; + } + /// Find the manifest for a mod folder. /// The folder to search. private FileInfo FindManifest(DirectoryInfo folder) @@ -193,11 +234,41 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning return subfolders.Any() && !files.Any(); } + /// Recursively get all relevant files in a folder based on the result of . + /// The root folder to search. + private IEnumerable RecursivelyGetRelevantFiles(DirectoryInfo folder) + { + foreach (FileSystemInfo entry in folder.GetFileSystemInfos()) + { + if (!this.IsRelevant(entry)) + continue; + + if (entry is FileInfo file) + yield return file; + + if (entry is DirectoryInfo subfolder) + { + foreach (FileInfo subfolderFile in this.RecursivelyGetRelevantFiles(subfolder)) + yield return subfolderFile; + } + } + } + /// Get whether a file or folder is relevant when deciding how to process a mod folder. /// The file or folder. private bool IsRelevant(FileSystemInfo entry) { - return !this.IgnoreFilesystemEntries.Contains(entry.Name); + return !this.IgnoreFilesystemEntries.Any(p => p.IsMatch(entry.Name)); + } + + /// Get whether a file is potentially part of an XNB mod. + /// The file. + private bool IsPotentialXnbFile(FileInfo entry) + { + if (!this.IsRelevant(entry)) + return true; + + return this.PotentialXnbModExtensions.Contains(entry.Extension); // use EndsWith to handle cases like image..png } /// Strip newlines from a string. diff --git a/src/SMAPI.Toolkit/Framework/ModScanning/ModType.cs b/src/SMAPI.Toolkit/Framework/ModScanning/ModType.cs index 2ceb9e40..bc86edb6 100644 --- a/src/SMAPI.Toolkit/Framework/ModScanning/ModType.cs +++ b/src/SMAPI.Toolkit/Framework/ModScanning/ModType.cs @@ -6,6 +6,9 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning /// The mod is invalid and its type could not be determined. Invalid, + /// The folder is ignored by convention. + Ignored, + /// A mod which uses SMAPI directly. Smapi, -- cgit From a7544e5afb4ba7f12d248503106cc8d407c2bad1 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 17 Jun 2019 18:51:12 -0400 Subject: move game detection into toolkit for reuse --- .../Framework/GameScanning/GameScanner.cs | 129 +++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs (limited to 'src/SMAPI.Toolkit/Framework') 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 +{ + /// Finds installed game folders. + public class GameScanner + { + /********* + ** Public methods + *********/ + /// Find all valid Stardew Valley install folders. + /// 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 + Platform platform = EnvironmentUtility.DetectPlatform(); + string executableFilename = EnvironmentUtility.GetExecutableName(platform); + IEnumerable 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 + *********/ + /// The default file paths where Stardew Valley can be installed. + /// The target platform. + /// Derived from the crossplatform mod config: https://github.com/Pathoschild/Stardew.ModBuildConfig. + private IEnumerable 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 registryKeys = new Dictionary + { + [@"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 + /// Get the value of a key in the Windows HKLM registry. + /// The full path of the registry key relative to HKLM. + /// The name of the value. + 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); + } + + /// Get the value of a key in the Windows HKCU registry. + /// The full path of the registry key relative to HKCU. + /// The name of the value. + 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 + } +} -- cgit 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 --- .../Framework/GameScanning/GameScanner.cs | 46 ++++++++++++++++++++-- 1 file changed, 43 insertions(+), 3 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 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 From 48f211f5447ec7580b9f9bba63eab0ec6b1ec5c7 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 14 Jul 2019 17:49:33 -0400 Subject: add metadata links to mod compatibility list --- src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs | 10 ++++++++++ src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs | 6 ++++++ 2 files changed, 16 insertions(+) (limited to 'src/SMAPI.Toolkit/Framework') diff --git a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs index 3e9b8ea6..24aea5e8 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs @@ -127,6 +127,15 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki } } + // parse links + List> metadataLinks = new List>(); + foreach (HtmlNode linkElement in node.Descendants("td").Last().Descendants("a").Skip(1)) // skip anchor link + { + string text = linkElement.InnerText.Trim(); + Uri url = new Uri(linkElement.GetAttributeValue("href", "")); + metadataLinks.Add(Tuple.Create(url, text)); + } + // yield model yield return new WikiModEntry { @@ -143,6 +152,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki Compatibility = compatibility, BetaCompatibility = betaCompatibility, Warnings = warnings, + MetadataLinks = metadataLinks.ToArray(), Anchor = anchor }; } diff --git a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs index cf416cc6..556796c5 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs @@ -1,3 +1,6 @@ +using System; +using System.Collections.Generic; + namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki { /// A mod entry in the wiki list. @@ -48,6 +51,9 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki /// The human-readable warnings for players about this mod. public string[] Warnings { get; set; } + /// Extra metadata links (usually for open pull requests). + public Tuple[] MetadataLinks { get; set; } + /// The link anchor for the mod entry in the wiki compatibility list. public string Anchor { get; set; } } -- cgit From 1bf399ec23368a0666203298768a4b24b63d6a88 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 14 Jul 2019 22:27:00 -0400 Subject: add dev note field to compatibility list --- src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs | 2 ++ src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs | 3 +++ 2 files changed, 5 insertions(+) (limited to 'src/SMAPI.Toolkit/Framework') diff --git a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs index 24aea5e8..ab6a2517 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs @@ -99,6 +99,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki string customUrl = this.GetAttribute(node, "data-url"); string anchor = this.GetAttribute(node, "id"); string contentPackFor = this.GetAttribute(node, "data-content-pack-for"); + string devNote = this.GetAttribute(node, "data-dev-note"); // parse stable compatibility WikiCompatibilityInfo compatibility = new WikiCompatibilityInfo @@ -153,6 +154,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki BetaCompatibility = betaCompatibility, Warnings = warnings, MetadataLinks = metadataLinks.ToArray(), + DevNote = devNote, Anchor = anchor }; } diff --git a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs index 556796c5..fff86891 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs @@ -54,6 +54,9 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki /// Extra metadata links (usually for open pull requests). public Tuple[] MetadataLinks { get; set; } + /// Special notes intended for developers who maintain unofficial updates or submit pull requests. + public string DevNote { get; set; } + /// The link anchor for the mod entry in the wiki compatibility list. public string Anchor { get; set; } } -- cgit From 1d085df5b796e02b3e9e6874bd4e5684e840cb92 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 29 Jul 2019 16:43:25 -0400 Subject: track license info for mod GitHub repos (#651) --- .../Framework/Clients/Wiki/WikiModEntry.cs | 1 - .../Framework/UpdateData/UpdateKey.cs | 32 +++++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) (limited to 'src/SMAPI.Toolkit/Framework') diff --git a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs index fff86891..06c44308 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki { diff --git a/src/SMAPI.Toolkit/Framework/UpdateData/UpdateKey.cs b/src/SMAPI.Toolkit/Framework/UpdateData/UpdateKey.cs index 865ebcf7..3fc1759e 100644 --- a/src/SMAPI.Toolkit/Framework/UpdateData/UpdateKey.cs +++ b/src/SMAPI.Toolkit/Framework/UpdateData/UpdateKey.cs @@ -3,7 +3,7 @@ using System; namespace StardewModdingAPI.Toolkit.Framework.UpdateData { /// A namespaced mod ID which uniquely identifies a mod within a mod repository. - public class UpdateKey + public class UpdateKey : IEquatable { /********* ** Accessors @@ -38,6 +38,12 @@ namespace StardewModdingAPI.Toolkit.Framework.UpdateData && !string.IsNullOrWhiteSpace(id); } + /// Construct an instance. + /// The mod repository containing the mod. + /// The mod ID within the repository. + public UpdateKey(ModRepositoryKey repository, string id) + : this($"{repository}:{id}", repository, id) { } + /// Parse a raw update key. /// The raw update key to parse. public static UpdateKey Parse(string raw) @@ -69,5 +75,29 @@ namespace StardewModdingAPI.Toolkit.Framework.UpdateData ? $"{this.Repository}:{this.ID}" : this.RawText; } + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + public bool Equals(UpdateKey other) + { + return + other != null + && this.Repository == other.Repository + && string.Equals(this.ID, other.ID, StringComparison.InvariantCultureIgnoreCase); + } + + /// Determines whether the specified object is equal to the current object. + /// The object to compare with the current object. + public override bool Equals(object obj) + { + return obj is UpdateKey other && this.Equals(other); + } + + /// Serves as the default hash function. + /// A hash code for the current object. + public override int GetHashCode() + { + return $"{this.Repository}:{this.ID}".ToLower().GetHashCode(); + } } } -- cgit From fd77ae93d59222d70c86aebfc044f3af11063372 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 9 Aug 2019 01:18:05 -0400 Subject: fix typos and inconsistent spelling --- .../Framework/Clients/WebApi/ModExtendedMetadataModel.cs | 4 ++-- src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs | 2 +- src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs | 2 +- src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs | 2 +- src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs | 2 +- src/SMAPI.Toolkit/Framework/ModData/ModDataModel.cs | 4 ++-- src/SMAPI.Toolkit/Framework/ModData/ModDataRecord.cs | 6 +++--- src/SMAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs | 4 ++-- src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs | 4 ++-- src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs | 2 +- src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs | 6 +++--- 11 files changed, 19 insertions(+), 19 deletions(-) (limited to 'src/SMAPI.Toolkit/Framework') diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs index 989c18b0..bd5f71a9 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs @@ -48,7 +48,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi [JsonConverter(typeof(StringEnumConverter))] public WikiCompatibilityStatus? CompatibilityStatus { get; set; } - /// The human-readable summary of the compatibility status or workaround, without HTML formatitng. + /// The human-readable summary of the compatibility status or workaround, without HTML formatting. public string CompatibilitySummary { get; set; } /// The game or SMAPI version which broke this mod, if applicable. @@ -62,7 +62,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi [JsonConverter(typeof(StringEnumConverter))] public WikiCompatibilityStatus? BetaCompatibilityStatus { get; set; } - /// The human-readable summary of the compatibility status or workaround for the Stardew Valley beta (if any), without HTML formatitng. + /// The human-readable summary of the compatibility status or workaround for the Stardew Valley beta (if any), without HTML formatting. public string BetaCompatibilitySummary { get; set; } /// The beta game or SMAPI version which broke this mod, if applicable. diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs index e352e1cc..a2eaad16 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs @@ -21,7 +21,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi /// Construct an empty instance. public ModSearchModel() { - // needed for JSON deserialising + // needed for JSON deserializing } /// Construct an instance. diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs index bca47647..886cd5a1 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs @@ -19,7 +19,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi /// Construct an empty instance. public ModSearchEntryModel() { - // needed for JSON deserialising + // needed for JSON deserializing } /// Construct an instance. diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs index 7c3df384..80c8f62b 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; using Newtonsoft.Json; -using StardewModdingAPI.Toolkit.Serialisation; +using StardewModdingAPI.Toolkit.Serialization; namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi { diff --git a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs index 60c7a682..212c70ef 100644 --- a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs +++ b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs @@ -29,7 +29,7 @@ namespace StardewModdingAPI.Toolkit.Framework.GameScanning IEnumerable paths = this .GetCustomInstallPaths(platform) .Concat(this.GetDefaultInstallPaths(platform)) - .Select(PathUtilities.NormalisePathSeparators) + .Select(PathUtilities.NormalizePathSeparators) .Distinct(StringComparer.InvariantCultureIgnoreCase); // yield valid folders diff --git a/src/SMAPI.Toolkit/Framework/ModData/ModDataModel.cs b/src/SMAPI.Toolkit/Framework/ModData/ModDataModel.cs index 18039762..dd0bd07b 100644 --- a/src/SMAPI.Toolkit/Framework/ModData/ModDataModel.cs +++ b/src/SMAPI.Toolkit/Framework/ModData/ModDataModel.cs @@ -112,8 +112,8 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData /********* ** Private methods *********/ - /// The method invoked after JSON deserialisation. - /// The deserialisation context. + /// The method invoked after JSON deserialization. + /// The deserialization context. [OnDeserialized] private void OnDeserialized(StreamingContext context) { diff --git a/src/SMAPI.Toolkit/Framework/ModData/ModDataRecord.cs b/src/SMAPI.Toolkit/Framework/ModData/ModDataRecord.cs index 794ad2e4..f01ada7c 100644 --- a/src/SMAPI.Toolkit/Framework/ModData/ModDataRecord.cs +++ b/src/SMAPI.Toolkit/Framework/ModData/ModDataRecord.cs @@ -68,7 +68,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData } /// Get a semantic local version for update checks. - /// The remote version to normalise. + /// The remote version to normalize. public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version) { return this.MapLocalVersions != null && this.MapLocalVersions.TryGetValue(version.ToString(), out string newVersion) @@ -77,10 +77,10 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData } /// Get a semantic remote version for update checks. - /// The remote version to normalise. + /// The remote version to normalize. public string GetRemoteVersionForUpdateChecks(string version) { - // normalise version if possible + // normalize version if possible if (SemanticVersion.TryParse(version, out ISemanticVersion parsed)) version = parsed.ToString(); diff --git a/src/SMAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs b/src/SMAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs index 237f2c66..9e22990d 100644 --- a/src/SMAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs +++ b/src/SMAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs @@ -32,14 +32,14 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData ** Public methods *********/ /// Get a semantic local version for update checks. - /// The remote version to normalise. + /// The remote version to normalize. public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version) { return this.DataRecord.GetLocalVersionForUpdateChecks(version); } /// Get a semantic remote version for update checks. - /// The remote version to normalise. + /// The remote version to normalize. public ISemanticVersion GetRemoteVersionForUpdateChecks(ISemanticVersion version) { if (version == null) diff --git a/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs b/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs index d61c427f..e67616d0 100644 --- a/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs +++ b/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs @@ -13,7 +13,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData BrokenCodeLoaded = 1, /// The mod affects the save serializer in a way that may make saves unloadable without the mod. - ChangesSaveSerialiser = 2, + ChangesSaveSerializer = 2, /// The mod patches the game in a way that may impact stability. PatchesGame = 4, @@ -21,7 +21,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData /// The mod uses the dynamic keyword which won't work on Linux/Mac. UsesDynamic = 8, - /// The mod references specialised 'unvalided update tick' events which may impact stability. + /// The mod references specialized 'unvalidated update tick' events which may impact stability. UsesUnvalidatedUpdateTick = 16, /// The mod has no update keys set. diff --git a/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs b/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs index 4ce17c66..d0df09a1 100644 --- a/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs +++ b/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using StardewModdingAPI.Toolkit.Serialisation.Models; +using StardewModdingAPI.Toolkit.Serialization.Models; using StardewModdingAPI.Toolkit.Utilities; namespace StardewModdingAPI.Toolkit.Framework.ModScanning diff --git a/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs b/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs index 54cb2b8b..f11cc1a7 100644 --- a/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs +++ b/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs @@ -3,8 +3,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; -using StardewModdingAPI.Toolkit.Serialisation; -using StardewModdingAPI.Toolkit.Serialisation.Models; +using StardewModdingAPI.Toolkit.Serialization; +using StardewModdingAPI.Toolkit.Serialization.Models; namespace StardewModdingAPI.Toolkit.Framework.ModScanning { @@ -118,7 +118,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning } } - // normalise display fields + // normalize display fields if (manifest != null) { manifest.Name = this.StripNewlines(manifest.Name); -- cgit From 8b09a2776d9c0faf96fa90c923952033ce659477 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 7 Nov 2019 13:51:45 -0500 Subject: add support for CurseForge update keys (#605) --- src/SMAPI.Toolkit/Framework/UpdateData/ModRepositoryKey.cs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/SMAPI.Toolkit/Framework') diff --git a/src/SMAPI.Toolkit/Framework/UpdateData/ModRepositoryKey.cs b/src/SMAPI.Toolkit/Framework/UpdateData/ModRepositoryKey.cs index f6c402d5..765ca334 100644 --- a/src/SMAPI.Toolkit/Framework/UpdateData/ModRepositoryKey.cs +++ b/src/SMAPI.Toolkit/Framework/UpdateData/ModRepositoryKey.cs @@ -9,6 +9,9 @@ namespace StardewModdingAPI.Toolkit.Framework.UpdateData /// The Chucklefish mod repository. Chucklefish, + /// The CurseForge mod repository. + CurseForge, + /// A GitHub project containing releases. GitHub, -- cgit From 0aac0717bf1c46d798ed007d3c7c5c050e07f354 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 8 Nov 2019 13:44:49 -0500 Subject: add CurseForge to mod metadata (#605) --- .../Framework/Clients/WebApi/ModExtendedMetadataModel.cs | 8 ++++++++ src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs | 4 ++++ src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs | 6 ++++++ 3 files changed, 18 insertions(+) (limited to 'src/SMAPI.Toolkit/Framework') diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs index bd5f71a9..8074210c 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs @@ -28,6 +28,12 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi /// The mod ID in the Chucklefish mod repo. public int? ChucklefishID { get; set; } + /// The mod ID in the CurseForge mod repo. + public int? CurseForgeID { get; set; } + + /// The mod key in the CurseForge mod repo (used in mod page URLs). + public string CurseForgeKey { get; set; } + /// The mod ID in the ModDrop mod repo. public int? ModDropID { get; set; } @@ -87,6 +93,8 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi this.Name = wiki.Name.FirstOrDefault(); this.NexusID = wiki.NexusID; this.ChucklefishID = wiki.ChucklefishID; + this.CurseForgeID = wiki.CurseForgeID; + this.CurseForgeKey = wiki.CurseForgeKey; this.ModDropID = wiki.ModDropID; this.GitHubRepo = wiki.GitHubRepo; this.CustomSourceUrl = wiki.CustomSourceUrl; diff --git a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs index ab6a2517..610e14f1 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs @@ -93,6 +93,8 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki string[] warnings = this.GetAttributeAsCsv(node, "data-warnings"); int? nexusID = this.GetAttributeAsNullableInt(node, "data-nexus-id"); int? chucklefishID = this.GetAttributeAsNullableInt(node, "data-cf-id"); + int? curseForgeID = this.GetAttributeAsNullableInt(node, "data-curseforge-id"); + string curseForgeKey = this.GetAttribute(node, "data-curseforge-key"); int? modDropID = this.GetAttributeAsNullableInt(node, "data-moddrop-id"); string githubRepo = this.GetAttribute(node, "data-github"); string customSourceUrl = this.GetAttribute(node, "data-custom-source"); @@ -145,6 +147,8 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki Author = authors, NexusID = nexusID, ChucklefishID = chucklefishID, + CurseForgeID = curseForgeID, + CurseForgeKey = curseForgeKey, ModDropID = modDropID, GitHubRepo = githubRepo, CustomSourceUrl = customSourceUrl, diff --git a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs index 06c44308..51bb2336 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs @@ -23,6 +23,12 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki /// The mod ID in the Chucklefish mod repo. public int? ChucklefishID { get; set; } + /// The mod ID in the CurseForge mod repo. + public int? CurseForgeID { get; set; } + + /// The mod key in the CurseForge mod repo (used in mod page URLs). + public string CurseForgeKey { get; set; } + /// The mod ID in the ModDrop mod repo. public int? ModDropID { get; set; } -- cgit From fd6a719b02d1d45d27509f44f09eefe52124ee20 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 9 Nov 2019 21:18:06 -0500 Subject: overhaul update checks This commit moves the core update-check logic serverside, and adds support for community-defined version mappings. For example, that means false update alerts can now be solved by the community for all players. --- .../Framework/Clients/WebApi/ModEntryModel.cs | 18 ++++++-- .../Clients/WebApi/ModExtendedMetadataModel.cs | 24 +++++++++- .../Framework/Clients/WebApi/ModSeachModel.cs | 36 --------------- .../Clients/WebApi/ModSearchEntryModel.cs | 11 ++++- .../Framework/Clients/WebApi/ModSearchModel.cs | 52 ++++++++++++++++++++++ .../Framework/Clients/WebApi/WebApiClient.cs | 8 +++- .../Framework/Clients/Wiki/WikiClient.cs | 26 +++++++++++ .../Framework/Clients/Wiki/WikiModEntry.cs | 7 +++ .../Framework/ModData/ModDataModel.cs | 6 --- .../Framework/ModData/ModDataRecord.cs | 31 ------------- .../ModData/ModDataRecordVersionedFields.cs | 24 ---------- 11 files changed, 137 insertions(+), 106 deletions(-) delete mode 100644 src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs create mode 100644 src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchModel.cs (limited to 'src