diff options
author | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2019-09-13 17:22:45 -0400 |
---|---|---|
committer | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2019-09-13 17:22:45 -0400 |
commit | 125bcbee56bf40cf82abc7fdb502f8cbc18546cf (patch) | |
tree | 788997dd4683867b6e32e307c17c855bd7209d98 /src/StardewModdingAPI.Toolkit/Framework | |
parent | 56726073ba65a018312bcd9db7072381073de315 (diff) | |
download | SMAPI-125bcbee56bf40cf82abc7fdb502f8cbc18546cf.tar.gz SMAPI-125bcbee56bf40cf82abc7fdb502f8cbc18546cf.tar.bz2 SMAPI-125bcbee56bf40cf82abc7fdb502f8cbc18546cf.zip |
migrate to new project file format
Diffstat (limited to 'src/StardewModdingAPI.Toolkit/Framework')
24 files changed, 0 insertions, 1592 deletions
diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModEntryModel.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModEntryModel.cs deleted file mode 100644 index 8a9c0a25..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModEntryModel.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi -{ - /// <summary>Metadata about a mod.</summary> - public class ModEntryModel - { - /********* - ** Accessors - *********/ - /// <summary>The mod's unique ID (if known).</summary> - public string ID { get; set; } - - /// <summary>The main version.</summary> - public ModEntryVersionModel Main { get; set; } - - /// <summary>The latest optional version, if newer than <see cref="Main"/>.</summary> - public ModEntryVersionModel Optional { get; set; } - - /// <summary>The latest unofficial version, if newer than <see cref="Main"/> and <see cref="Optional"/>.</summary> - public ModEntryVersionModel Unofficial { get; set; } - - /// <summary>The latest unofficial version for the current Stardew Valley or SMAPI beta, if any (see <see cref="HasBetaInfo"/>).</summary> - public ModEntryVersionModel UnofficialForBeta { get; set; } - - /// <summary>Optional extended data which isn't needed for update checks.</summary> - public ModExtendedMetadataModel Metadata { get; set; } - - /// <summary>Whether a Stardew Valley or SMAPI beta which affects mod compatibility is in progress. If this is true, <see cref="UnofficialForBeta"/> should be used for beta versions of SMAPI instead of <see cref="Unofficial"/>.</summary> - public bool HasBetaInfo { get; set; } - - /// <summary>The errors that occurred while fetching update data.</summary> - public string[] Errors { get; set; } = new string[0]; - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModEntryVersionModel.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModEntryVersionModel.cs deleted file mode 100644 index dadb8c10..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModEntryVersionModel.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi -{ - /// <summary>Metadata about a version.</summary> - public class ModEntryVersionModel - { - /********* - ** Accessors - *********/ - /// <summary>The version number.</summary> - public ISemanticVersion Version { get; set; } - - /// <summary>The mod page URL.</summary> - public string Url { get; set; } - - - /********* - ** Public methods - *********/ - /// <summary>Construct an instance.</summary> - public ModEntryVersionModel() { } - - /// <summary>Construct an instance.</summary> - /// <param name="version">The version number.</param> - /// <param name="url">The mod page URL.</param> - public ModEntryVersionModel(ISemanticVersion version, string url) - { - this.Version = version; - this.Url = url; - } - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs deleted file mode 100644 index 989c18b0..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using StardewModdingAPI.Toolkit.Framework.Clients.Wiki; -using StardewModdingAPI.Toolkit.Framework.ModData; - -namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi -{ - /// <summary>Extended metadata about a mod.</summary> - public class ModExtendedMetadataModel - { - /********* - ** Accessors - *********/ - /**** - ** Mod info - ****/ - /// <summary>The mod's unique ID. A mod may have multiple current IDs in rare cases (e.g. due to parallel releases or unofficial updates).</summary> - public string[] ID { get; set; } = new string[0]; - - /// <summary>The mod's display name.</summary> - public string Name { get; set; } - - /// <summary>The mod ID on Nexus.</summary> - public int? NexusID { get; set; } - - /// <summary>The mod ID in the Chucklefish mod repo.</summary> - public int? ChucklefishID { get; set; } - - /// <summary>The mod ID in the ModDrop mod repo.</summary> - public int? ModDropID { get; set; } - - /// <summary>The GitHub repository in the form 'owner/repo'.</summary> - public string GitHubRepo { get; set; } - - /// <summary>The URL to a non-GitHub source repo.</summary> - public string CustomSourceUrl { get; set; } - - /// <summary>The custom mod page URL (if applicable).</summary> - public string CustomUrl { get; set; } - - - /**** - ** Stable compatibility - ****/ - /// <summary>The compatibility status.</summary> - [JsonConverter(typeof(StringEnumConverter))] - public WikiCompatibilityStatus? CompatibilityStatus { get; set; } - - /// <summary>The human-readable summary of the compatibility status or workaround, without HTML formatitng.</summary> - public string CompatibilitySummary { get; set; } - - /// <summary>The game or SMAPI version which broke this mod, if applicable.</summary> - public string BrokeIn { get; set; } - - - /**** - ** Beta compatibility - ****/ - /// <summary>The compatibility status for the Stardew Valley beta (if any).</summary> - [JsonConverter(typeof(StringEnumConverter))] - public WikiCompatibilityStatus? BetaCompatibilityStatus { get; set; } - - /// <summary>The human-readable summary of the compatibility status or workaround for the Stardew Valley beta (if any), without HTML formatitng.</summary> - public string BetaCompatibilitySummary { get; set; } - - /// <summary>The beta game or SMAPI version which broke this mod, if applicable.</summary> - public string BetaBrokeIn { get; set; } - - - /********* - ** Public methods - *********/ - /// <summary>Construct an instance.</summary> - public ModExtendedMetadataModel() { } - - /// <summary>Construct an instance.</summary> - /// <param name="wiki">The mod metadata from the wiki (if available).</param> - /// <param name="db">The mod metadata from SMAPI's internal DB (if available).</param> - public ModExtendedMetadataModel(WikiModEntry wiki, ModDataRecord db) - { - // wiki data - if (wiki != null) - { - this.ID = wiki.ID; - this.Name = wiki.Name.FirstOrDefault(); - this.NexusID = wiki.NexusID; - this.ChucklefishID = wiki.ChucklefishID; - this.ModDropID = wiki.ModDropID; - this.GitHubRepo = wiki.GitHubRepo; - this.CustomSourceUrl = wiki.CustomSourceUrl; - this.CustomUrl = wiki.CustomUrl; - - this.CompatibilityStatus = wiki.Compatibility.Status; - this.CompatibilitySummary = wiki.Compatibility.Summary; - this.BrokeIn = wiki.Compatibility.BrokeIn; - - this.BetaCompatibilityStatus = wiki.BetaCompatibility?.Status; - this.BetaCompatibilitySummary = wiki.BetaCompatibility?.Summary; - this.BetaBrokeIn = wiki.BetaCompatibility?.BrokeIn; - } - - // internal DB data - if (db != null) - { - this.ID = this.ID.Union(db.FormerIDs).ToArray(); - this.Name = this.Name ?? db.DisplayName; - } - } - - /// <summary>Get update keys based on the metadata.</summary> - public IEnumerable<string> GetUpdateKeys() - { - if (this.NexusID.HasValue) - yield return $"Nexus:{this.NexusID}"; - if (this.ChucklefishID.HasValue) - yield return $"Chucklefish:{this.ChucklefishID}"; - if (this.GitHubRepo != null) - yield return $"GitHub:{this.GitHubRepo}"; - } - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs deleted file mode 100644 index e352e1cc..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Linq; - -namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi -{ - /// <summary>Specifies mods whose update-check info to fetch.</summary> - public class ModSearchModel - { - /********* - ** Accessors - *********/ - /// <summary>The mods for which to find data.</summary> - public ModSearchEntryModel[] Mods { get; set; } - - /// <summary>Whether to include extended metadata for each mod.</summary> - public bool IncludeExtendedMetadata { get; set; } - - - /********* - ** Public methods - *********/ - /// <summary>Construct an empty instance.</summary> - public ModSearchModel() - { - // needed for JSON deserialising - } - - /// <summary>Construct an instance.</summary> - /// <param name="mods">The mods to search.</param> - /// <param name="includeExtendedMetadata">Whether to include extended metadata for each mod.</param> - public ModSearchModel(ModSearchEntryModel[] mods, bool includeExtendedMetadata) - { - this.Mods = mods.ToArray(); - this.IncludeExtendedMetadata = includeExtendedMetadata; - } - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs deleted file mode 100644 index bca47647..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi -{ - /// <summary>Specifies the identifiers for a mod to match.</summary> - public class ModSearchEntryModel - { - /********* - ** Accessors - *********/ - /// <summary>The unique mod ID.</summary> - public string ID { get; set; } - - /// <summary>The namespaced mod update keys (if available).</summary> - public string[] UpdateKeys { get; set; } - - - /********* - ** Public methods - *********/ - /// <summary>Construct an empty instance.</summary> - public ModSearchEntryModel() - { - // needed for JSON deserialising - } - - /// <summary>Construct an instance.</summary> - /// <param name="id">The unique mod ID.</param> - /// <param name="updateKeys">The namespaced mod update keys (if available).</param> - public ModSearchEntryModel(string id, string[] updateKeys) - { - this.ID = id; - this.UpdateKeys = updateKeys ?? new string[0]; - } - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs deleted file mode 100644 index 7c3df384..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using Newtonsoft.Json; -using StardewModdingAPI.Toolkit.Serialisation; - -namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi -{ - /// <summary>Provides methods for interacting with the SMAPI web API.</summary> - public class WebApiClient - { - /********* - ** Fields - *********/ - /// <summary>The base URL for the web API.</summary> - private readonly Uri BaseUrl; - - /// <summary>The API version number.</summary> - private readonly ISemanticVersion Version; - - /// <summary>The JSON serializer settings to use.</summary> - private readonly JsonSerializerSettings JsonSettings = new JsonHelper().JsonSettings; - - - /********* - ** Public methods - *********/ - /// <summary>Construct an instance.</summary> - /// <param name="baseUrl">The base URL for the web API.</param> - /// <param name="version">The web API version.</param> - public WebApiClient(string baseUrl, ISemanticVersion version) - { - this.BaseUrl = new Uri(baseUrl); - this.Version = version; - } - - /// <summary>Get metadata about a set of mods from the web API.</summary> - /// <param name="mods">The mod keys for which to fetch the latest version.</param> - /// <param name="includeExtendedMetadata">Whether to include extended metadata for each mod.</param> - public IDictionary<string, ModEntryModel> GetModInfo(ModSearchEntryModel[] mods, bool includeExtendedMetadata = false) - { - return this.Post<ModSearchModel, ModEntryModel[]>( - $"v{this.Version}/mods", - new ModSearchModel(mods, includeExtendedMetadata) - ).ToDictionary(p => p.ID); - } - - - /********* - ** Private methods - *********/ - /// <summary>Fetch the response from the backend API.</summary> - /// <typeparam name="TBody">The body content type.</typeparam> - /// <typeparam name="TResult">The expected response type.</typeparam> - /// <param name="url">The request URL, optionally excluding the base URL.</param> - /// <param name="content">The body content to post.</param> - private TResult Post<TBody, TResult>(string url, TBody content) - { - // note: avoid HttpClient for Mac compatibility - using (WebClient client = new WebClient()) - { - Uri fullUrl = new Uri(this.BaseUrl, url); - string data = JsonConvert.SerializeObject(content); - - client.Headers["Content-Type"] = "application/json"; - client.Headers["User-Agent"] = $"SMAPI/{this.Version}"; - string response = client.UploadString(fullUrl, data); - return JsonConvert.DeserializeObject<TResult>(response, this.JsonSettings); - } - } - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs deleted file mode 100644 index 3e9b8ea6..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs +++ /dev/null @@ -1,237 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using HtmlAgilityPack; -using Pathoschild.Http.Client; - -namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki -{ - /// <summary>An HTTP client for fetching mod metadata from the wiki.</summary> - public class WikiClient : IDisposable - { - /********* - ** Fields - *********/ - /// <summary>The underlying HTTP client.</summary> - private readonly IClient Client; - - - /********* - ** Public methods - *********/ - /// <summary>Construct an instance.</summary> - /// <param name="userAgent">The user agent for the wiki API.</param> - /// <param name="baseUrl">The base URL for the wiki API.</param> - public WikiClient(string userAgent, string baseUrl = "https://stardewvalleywiki.com/mediawiki/api.php") - { - this.Client = new FluentClient(baseUrl).SetUserAgent(userAgent); - } - - /// <summary>Fetch mods from the compatibility list.</summary> - public async Task<WikiModList> FetchModsAsync() - { - // fetch HTML - ResponseModel response = await this.Client - .GetAsync("") - .WithArguments(new - { - action = "parse", - page = "Modding:Mod_compatibility", - format = "json" - }) - .As<ResponseModel>(); - string html = response.Parse.Text["*"]; - - // parse HTML - var doc = new HtmlDocument(); - doc.LoadHtml(html); - - // fetch game versions - string stableVersion = doc.DocumentNode.SelectSingleNode("div[@class='game-stable-version']")?.InnerText; - string betaVersion = doc.DocumentNode.SelectSingleNode("div[@class='game-beta-version']")?.InnerText; - if (betaVersion == stableVersion) - betaVersion = null; - - // find mod entries - HtmlNodeCollection modNodes = doc.DocumentNode.SelectNodes("table[@id='mod-list']//tr[@class='mod']"); - if (modNodes == null) - throw new InvalidOperationException("Can't parse wiki compatibility list, no mods found."); - - // parse - WikiModEntry[] mods = this.ParseEntries(modNodes).ToArray(); - return new WikiModList - { - StableVersion = stableVersion, - BetaVersion = betaVersion, - Mods = mods - }; - } - - /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary> - public void Dispose() - { - this.Client?.Dispose(); - } - - - /********* - ** Private methods - *********/ - /// <summary>Parse valid mod compatibility entries.</summary> - /// <param name="nodes">The HTML compatibility entries.</param> - private IEnumerable<WikiModEntry> ParseEntries(IEnumerable<HtmlNode> nodes) - { - foreach (HtmlNode node in nodes) - { - // extract fields - string[] names = this.GetAttributeAsCsv(node, "data-name"); - string[] authors = this.GetAttributeAsCsv(node, "data-author"); - string[] ids = this.GetAttributeAsCsv(node, "data-id"); - string[] warnings = this.GetAttributeAsCsv(node, "data-warnings"); - int? nexusID = this.GetAttributeAsNullableInt(node, "data-nexus-id"); - int? chucklefishID = this.GetAttributeAsNullableInt(node, "data-cf-id"); - int? modDropID = this.GetAttributeAsNullableInt(node, "data-moddrop-id"); - string githubRepo = this.GetAttribute(node, "data-github"); - string customSourceUrl = this.GetAttribute(node, "data-custom-source"); - string customUrl = this.GetAttribute(node, "data-url"); - string anchor = this.GetAttribute(node, "id"); - string contentPackFor = this.GetAttribute(node, "data-content-pack-for"); - - // parse stable compatibility - WikiCompatibilityInfo compatibility = new WikiCompatibilityInfo - { - Status = this.GetAttributeAsEnum<WikiCompatibilityStatus>(node, "data-status") ?? WikiCompatibilityStatus.Ok, - BrokeIn = this.GetAttribute(node, "data-broke-in"), - UnofficialVersion = this.GetAttributeAsSemanticVersion(node, "data-unofficial-version"), - UnofficialUrl = this.GetAttribute(node, "data-unofficial-url"), - Summary = this.GetInnerHtml(node, "mod-summary")?.Trim() - }; - - // parse beta compatibility - WikiCompatibilityInfo betaCompatibility = null; - { - WikiCompatibilityStatus? betaStatus = this.GetAttributeAsEnum<WikiCompatibilityStatus>(node, "data-beta-status"); - if (betaStatus.HasValue) - { - betaCompatibility = new WikiCompatibilityInfo - { - Status = betaStatus.Value, - BrokeIn = this.GetAttribute(node, "data-beta-broke-in"), - UnofficialVersion = this.GetAttributeAsSemanticVersion(node, "data-beta-unofficial-version"), - UnofficialUrl = this.GetAttribute(node, "data-beta-unofficial-url"), - Summary = this.GetInnerHtml(node, "mod-beta-summary") - }; - } - } - - // yield model - yield return new WikiModEntry - { - ID = ids, - Name = names, - Author = authors, - NexusID = nexusID, - ChucklefishID = chucklefishID, - ModDropID = modDropID, - GitHubRepo = githubRepo, - CustomSourceUrl = customSourceUrl, - CustomUrl = customUrl, - ContentPackFor = contentPackFor, - Compatibility = compatibility, - BetaCompatibility = betaCompatibility, - Warnings = warnings, - Anchor = anchor - }; - } - } - - /// <summary>Get an attribute value.</summary> - /// <param name="element">The element whose attributes to read.</param> - /// <param name="name">The attribute name.</param> - private string GetAttribute(HtmlNode element, string name) - { - string value = element.GetAttributeValue(name, null); - if (string.IsNullOrWhiteSpace(value)) - return null; - - return WebUtility.HtmlDecode(value); - } - - /// <summary>Get an attribute value and parse it as a comma-delimited list of strings.</summary> - /// <param name="element">The element whose attributes to read.</param> - /// <param name="name">The attribute name.</param> - private string[] GetAttributeAsCsv(HtmlNode element, string name) - { - string raw = this.GetAttribute(element, name); - return !string.IsNullOrWhiteSpace(raw) - ? raw.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(p => p.Trim()).ToArray() - : new string[0]; - } - - /// <summary>Get an attribute value and parse it as an enum value.</summary> - /// <typeparam name="TEnum">The enum type.</typeparam> - /// <param name="element">The element whose attributes to read.</param> - /// <param name="name">The attribute name.</param> - private TEnum? GetAttributeAsEnum<TEnum>(HtmlNode element, string name) where TEnum : struct - { - string raw = this.GetAttribute(element, name); - if (raw == null) - return null; - if (!Enum.TryParse(raw, true, out TEnum value) && Enum.IsDefined(typeof(TEnum), value)) - throw new InvalidOperationException($"Unknown {typeof(TEnum).Name} value '{raw}' when parsing compatibility list."); - return value; - } - - /// <summary>Get an attribute value and parse it as a semantic version.</summary> - /// <param name="element">The element whose attributes to read.</param> - /// <param name="name">The attribute name.</param> - private ISemanticVersion GetAttributeAsSemanticVersion(HtmlNode element, string name) - { - string raw = this.GetAttribute(element, name); - return SemanticVersion.TryParse(raw, out ISemanticVersion version) - ? version - : null; - } - - /// <summary>Get an attribute value and parse it as a nullable int.</summary> - /// <param name="element">The element whose attributes to read.</param> - /// <param name="name">The attribute name.</param> - private int? GetAttributeAsNullableInt(HtmlNode element, string name) - { - string raw = this.GetAttribute(element, name); - if (raw != null && int.TryParse(raw, out int value)) - return value; - return null; - } - - /// <summary>Get the text of an element with the given class name.</summary> - /// <param name="container">The metadata container.</param> - /// <param name="className">The field name.</param> - private string GetInnerHtml(HtmlNode container, string className) - { - return container.Descendants().FirstOrDefault(p => p.HasClass(className))?.InnerHtml; - } - - /// <summary>The response model for the MediaWiki parse API.</summary> - [SuppressMessage("ReSharper", "ClassNeverInstantiated.Local")] - [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")] - private class ResponseModel - { - /// <summary>The parse API results.</summary> - public ResponseParseModel Parse { get; set; } - } - - /// <summary>The inner response model for the MediaWiki parse API.</summary> - [SuppressMessage("ReSharper", "ClassNeverInstantiated.Local")] - [SuppressMessage("ReSharper", "CollectionNeverUpdated.Local")] - [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")] - private class ResponseParseModel - { - /// <summary>The parsed text.</summary> - public IDictionary<string, string> Text { get; set; } - } - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityInfo.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityInfo.cs deleted file mode 100644 index 204acd2b..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityInfo.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki -{ - /// <summary>Compatibility info for a mod.</summary> - public class WikiCompatibilityInfo - { - /********* - ** Accessors - *********/ - /// <summary>The compatibility status.</summary> - public WikiCompatibilityStatus Status { get; set; } - - /// <summary>The human-readable summary of the compatibility status or workaround, without HTML formatting.</summary> - public string Summary { get; set; } - - /// <summary>The game or SMAPI version which broke this mod (if applicable).</summary> - public string BrokeIn { get; set; } - - /// <summary>The version of the latest unofficial update, if applicable.</summary> - public ISemanticVersion UnofficialVersion { get; set; } - - /// <summary>The URL to the latest unofficial update, if applicable.</summary> - public string UnofficialUrl { get; set; } - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityStatus.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityStatus.cs deleted file mode 100644 index a1d2dfae..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityStatus.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki -{ - /// <summary>The compatibility status for a mod.</summary> - public enum WikiCompatibilityStatus - { - /// <summary>The mod is compatible.</summary> - Ok = 0, - - /// <summary>The mod is compatible if you use an optional official download.</summary> - Optional = 1, - - /// <summary>The mod is compatible if you use an unofficial update.</summary> - Unofficial = 2, - - /// <summary>The mod isn't compatible, but the player can fix it or there's a good alternative.</summary> - Workaround = 3, - - /// <summary>The mod isn't compatible.</summary> - Broken = 4, - - /// <summary>The mod is no longer maintained by the author, and an unofficial update or continuation is unlikely.</summary> - Abandoned = 5, - - /// <summary>The mod is no longer needed and should be removed.</summary> - Obsolete = 6 - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs deleted file mode 100644 index cf416cc6..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs +++ /dev/null @@ -1,54 +0,0 @@ -namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki -{ - /// <summary>A mod entry in the wiki list.</summary> - public class WikiModEntry - { - /********* - ** Accessors - *********/ - /// <summary>The mod's unique ID. If the mod has alternate/old IDs, they're listed in latest to newest order.</summary> - public string[] ID { get; set; } - - /// <summary>The mod's display name. If the mod has multiple names, the first one is the most canonical name.</summary> - public string[] Name { get; set; } - - /// <summary>The mod's author name. If the author has multiple names, the first one is the most canonical name.</summary> - public string[] Author { get; set; } - - /// <summary>The mod ID on Nexus.</summary> - public int? NexusID { get; set; } - - /// <summary>The mod ID in the Chucklefish mod repo.</summary> - public int? ChucklefishID { get; set; } - - /// <summary>The mod ID in the ModDrop mod repo.</summary> - public int? ModDropID { get; set; } - - /// <summary>The GitHub repository in the form 'owner/repo'.</summary> - public string GitHubRepo { get; set; } - - /// <summary>The URL to a non-GitHub source repo.</summary> - public string CustomSourceUrl { get; set; } - - /// <summary>The custom mod page URL (if applicable).</summary> - public string CustomUrl { get; set; } - - /// <summary>The name of the mod which loads this content pack, if applicable.</summary> - public string ContentPackFor { get; set; } - - /// <summary>The mod's compatibility with the latest stable version of the game.</summary> - public WikiCompatibilityInfo Compatibility { get; set; } - - /// <summary>The mod's compatibility with the latest beta version of the game (if any).</summary> - public WikiCompatibilityInfo BetaCompatibility { get; set; } - - /// <summary>Whether a Stardew Valley or SMAPI beta which affects mod compatibility is in progress. If this is true, <see cref="BetaCompatibility"/> should be used for beta versions of SMAPI instead of <see cref="Compatibility"/>.</summary> - public bool HasBetaInfo => this.BetaCompatibility != null; - - /// <summary>The human-readable warnings for players about this mod.</summary> - public string[] Warnings { get; set; } - - /// <summary>The link anchor for the mod entry in the wiki compatibility list.</summary> - public string Anchor { get; set; } - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiModList.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiModList.cs deleted file mode 100644 index 0d614f28..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiModList.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki -{ - /// <summary>Metadata from the wiki's mod compatibility list.</summary> - public class WikiModList - { - /********* - ** Accessors - *********/ - /// <summary>The stable game version.</summary> - public string StableVersion { get; set; } - - /// <summary>The beta game version (if any).</summary> - public string BetaVersion { get; set; } - - /// <summary>The mods on the wiki.</summary> - public WikiModEntry[] Mods { get; set; } - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModData/MetadataModel.cs b/src/StardewModdingAPI.Toolkit/Framework/ModData/MetadataModel.cs deleted file mode 100644 index ef6d4dd9..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/ModData/MetadataModel.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; - -namespace StardewModdingAPI.Toolkit.Framework.ModData -{ - /// <summary>The SMAPI predefined metadata.</summary> - internal class MetadataModel - { - /******** - ** Accessors - ********/ - /// <summary>Extra metadata about mods.</summary> - public IDictionary<string, ModDataModel> ModData { get; set; } - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataField.cs b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataField.cs deleted file mode 100644 index b3954693..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataField.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System.Linq; - -namespace StardewModdingAPI.Toolkit.Framework.ModData -{ - /// <summary>A versioned mod metadata field.</summary> - public class ModDataField - { - /********* - ** Accessors - *********/ - /// <summary>The field key.</summary> - public ModDataFieldKey Key { get; } - - /// <summary>The field value.</summary> - public string Value { get; } - - /// <summary>Whether this field should only be applied if it's not already set.</summary> - public bool IsDefault { get; } - - /// <summary>The lowest version in the range, or <c>null</c> for all past versions.</summary> - public ISemanticVersion LowerVersion { get; } - - /// <summary>The highest version in the range, or <c>null</c> for all future versions.</summary> - public ISemanticVersion UpperVersion { get; } - - - /********* - ** Public methods - *********/ - /// <summary>Construct an instance.</summary> - /// <param name="key">The field key.</param> - /// <param name="value">The field value.</param> - /// <param name="isDefault">Whether this field should only be applied if it's not already set.</param> - /// <param name="lowerVersion">The lowest version in the range, or <c>null</c> for all past versions.</param> - /// <param name="upperVersion">The highest version in the range, or <c>null</c> for all future versions.</param> - public ModDataField(ModDataFieldKey key, string value, bool isDefault, ISemanticVersion lowerVersion, ISemanticVersion upperVersion) - { - this.Key = key; - this.Value = value; - this.IsDefault = isDefault; - this.LowerVersion = lowerVersion; - this.UpperVersion = upperVersion; - } - - /// <summary>Get whether this data field applies for the given manifest.</summary> - /// <param name="manifest">The mod manifest.</param> - public bool IsMatch(IManifest manifest) - { - return - manifest?.Version != null // ignore invalid manifest - && (!this.IsDefault || !this.HasFieldValue(manifest, this.Key)) - && (this.LowerVersion == null || !manifest.Version.IsOlderThan(this.LowerVersion)) - && (this.UpperVersion == null || !manifest.Version.IsNewerThan(this.UpperVersion)); - } - - - /********* - ** Private methods - *********/ - /// <summary>Get whether a manifest field has a meaningful value for the purposes of enforcing <see cref="IsDefault"/>.</summary> - /// <param name="manifest">The mod manifest.</param> - /// <param name="key">The field key matching <see cref="ModDataFieldKey"/>.</param> - private bool HasFieldValue(IManifest manifest, ModDataFieldKey key) - { - switch (key) - { - // update key - case ModDataFieldKey.UpdateKey: - return manifest.UpdateKeys != null && manifest.UpdateKeys.Any(p => !string.IsNullOrWhiteSpace(p)); - - // non-manifest fields - case ModDataFieldKey.AlternativeUrl: - case ModDataFieldKey.StatusReasonPhrase: - case ModDataFieldKey.Status: - return false; - - default: - return false; - } - } - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataFieldKey.cs b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataFieldKey.cs deleted file mode 100644 index 09dd0cc5..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataFieldKey.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace StardewModdingAPI.Toolkit.Framework.ModData -{ - /// <summary>The valid field keys.</summary> - public enum ModDataFieldKey - { - /// <summary>A manifest update key.</summary> - UpdateKey, - - /// <summary>An alternative URL the player can check for an updated version.</summary> - AlternativeUrl, - - /// <summary>The mod's predefined compatibility status.</summary> - Status, - - /// <summary>A reason phrase for the <see cref="Status"/>, or <c>null</c> to use the default reason.</summary> - StatusReasonPhrase - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataModel.cs b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataModel.cs deleted file mode 100644 index 18039762..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataModel.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace StardewModdingAPI.Toolkit.Framework.ModData -{ - /// <summary>The raw mod metadata from SMAPI's internal mod list.</summary> - internal class ModDataModel - { - /********* - ** Accessors - *********/ - /// <summary>The mod's current unique ID.</summary> - public string ID { get; set; } - - /// <summary>The former mod IDs (if any).</summary> - /// <remarks> - /// This uses a custom format which uniquely identifies a mod across multiple versions and - /// supports matching other fields if no ID was specified. This doesn't include the latest - /// ID, if any. If the mod's ID changed over time, multiple variants can be separated by the - /// <c>|</c> character. - /// </remarks> - public string FormerIDs { get; set; } - - /// <summary>Maps local versions to a semantic version for update checks.</summary> - public IDictionary<string, string> MapLocalVersions { get; set; } = new Dictionary<string, string>(); - - /// <summary>Maps remote versions to a semantic version for update checks.</summary> - public IDictionary<string, string> MapRemoteVersions { get; set; } = new Dictionary<string, string>(); - - /// <summary>The mod warnings to suppress, even if they'd normally be shown.</summary> - public ModWarning SuppressWarnings { get; set; } - - /// <summary>This field stores properties that aren't mapped to another field before they're parsed into <see cref="Fields"/>.</summary> - [JsonExtensionData] - public IDictionary<string, JToken> ExtensionData { get; set; } - - /// <summary>The versioned field data.</summary> - /// <remarks> - /// This maps field names to values. This should be accessed via <see cref="GetFields"/>. - /// Format notes: - /// - Each key consists of a field name prefixed with any combination of version range - /// and <c>Default</c>, separated by pipes (whitespace trimmed). For example, <c>Name</c> - /// will always override the name, <c>Default | Name</c> will only override a blank - /// name, and <c>~1.1 | Default | Name</c> will override blank names up to version 1.1. - /// - The version format is <c>min~max</c> (where either side can be blank for unbounded), or - /// a single version number. - /// - The field name itself corresponds to a <see cref="ModDataFieldKey"/> value. - /// </remarks> - public IDictionary<string, string> Fields { get; set; } = new Dictionary<string, string>(); - - - /********* - ** Public methods - *********/ - /// <summary>Get a parsed representation of the <see cref="Fields"/>.</summary> - public IEnumerable<ModDataField> GetFields() - { - foreach (KeyValuePair<string, string> pair in this.Fields) - { - // init fields - string packedKey = pair.Key; - string value = pair.Value; - bool isDefault = false; - ISemanticVersion lowerVersion = null; - ISemanticVersion upperVersion = null; - - // parse - string[] parts = packedKey.Split('|').Select(p => p.Trim()).ToArray(); - ModDataFieldKey fieldKey = (ModDataFieldKey)Enum.Parse(typeof(ModDataFieldKey), parts.Last(), ignoreCase: true); - foreach (string part in parts.Take(parts.Length - 1)) - { - // 'default' - if (part.Equals("Default", StringComparison.InvariantCultureIgnoreCase)) - { - isDefault = true; - continue; - } - - // version range - if (part.Contains("~")) - { - string[] versionParts = part.Split(new[] { '~' }, 2); - lowerVersion = versionParts[0] != "" ? new SemanticVersion(versionParts[0]) : null; - upperVersion = versionParts[1] != "" ? new SemanticVersion(versionParts[1]) : null; - continue; - } - - // single version - lowerVersion = new SemanticVersion(part); - upperVersion = new SemanticVersion(part); - } - - yield return new ModDataField(fieldKey, value, isDefault, lowerVersion, upperVersion); - } - } - - /// <summary>Get the former mod IDs.</summary> - public IEnumerable<string> GetFormerIDs() - { - if (this.FormerIDs != null) - { - foreach (string id in this.FormerIDs.Split('|')) - yield return id.Trim(); - } - } - - - /********* - ** Private methods - *********/ - /// <summary>The method invoked after JSON deserialisation.</summary> - /// <param name="context">The deserialisation context.</param> - [OnDeserialized] - private void OnDeserialized(StreamingContext context) - { - if (this.ExtensionData != null) - { - this.Fields = this.ExtensionData.ToDictionary(p => p.Key, p => p.Value.ToString()); - this.ExtensionData = null; - } - } - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecord.cs b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecord.cs deleted file mode 100644 index 794ad2e4..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecord.cs +++ /dev/null @@ -1,147 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace StardewModdingAPI.Toolkit.Framework.ModData -{ - /// <summary>The parsed mod metadata from SMAPI's internal mod list.</summary> - public class ModDataRecord - { - /********* - ** Accessors - *********/ - /// <summary>The mod's default display name.</summary> - public string DisplayName { get; } - - /// <summary>The mod's current unique ID.</summary> - public string ID { get; } - - /// <summary>The former mod IDs (if any).</summary> - public string[] FormerIDs { get; } - - /// <summary>The mod warnings to suppress, even if they'd normally be shown.</summary> - public ModWarning SuppressWarnings { get; set; } - - /// <summary>Maps local versions to a semantic version for update checks.</summary> - public IDictionary<string, string> MapLocalVersions { get; } - - /// <summary>Maps remote versions to a semantic version for update checks.</summary> - public IDictionary<string, string> MapRemoteVersions { get; } - - /// <summary>The versioned field data.</summary> - public ModDataField[] Fields { get; } - - - /********* - ** Public methods - *********/ - /// <summary>Construct an instance.</summary> - /// <param name="displayName">The mod's default display name.</param> - /// <param name="model">The raw data model.</param> - internal ModDataRecord(string displayName, ModDataModel model) - { - this.DisplayName = displayName; - this.ID = model.ID; - this.FormerIDs = model.GetFormerIDs().ToArray(); - this.SuppressWarnings = model.SuppressWarnings; - this.MapLocalVersions = new Dictionary<string, string>(model.MapLocalVersions, StringComparer.InvariantCultureIgnoreCase); - this.MapRemoteVersions = new Dictionary<string, string>(model.MapRemoteVersions, StringComparer.InvariantCultureIgnoreCase); - this.Fields = model.GetFields().ToArray(); - } - - /// <summary>Get whether the mod has (or previously had) the given ID.</summary> - /// <param name="id">The mod ID.</param> - public bool HasID(string id) - { - // try main ID - if (this.ID.Equals(id, StringComparison.InvariantCultureIgnoreCase)) - return true; - - // try former IDs - foreach (string formerID in this.FormerIDs) - { - if (formerID.Equals(id, StringComparison.InvariantCultureIgnoreCase)) - return true; - } - - return false; - } - - /// <summary>Get a semantic local version for update checks.</summary> - /// <param name="version">The remote version to normalise.</param> - public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version) - { - return this.MapLocalVersions != null && this.MapLocalVersions.TryGetValue(version.ToString(), out string newVersion) - ? new SemanticVersion(newVersion) - : version; - } - - /// <summary>Get a semantic remote version for update checks.</summary> - /// <param name="version">The remote version to normalise.</param> - public string GetRemoteVersionForUpdateChecks(string version) - { - // normalise version if possible - if (SemanticVersion.TryParse(version, out ISemanticVersion parsed)) - version = parsed.ToString(); - - // fetch remote version - return this.MapRemoteVersions != null && this.MapRemoteVersions.TryGetValue(version, out string newVersion) - ? newVersion - : version; - } - - /// <summary>Get the possible mod IDs.</summary> - public IEnumerable<string> GetIDs() - { - return this.FormerIDs - .Concat(new[] { this.ID }) - .Where(p => !string.IsNullOrWhiteSpace(p)) - .Select(p => p.Trim()) - .Distinct(); - } - - /// <summary>Get the default update key for this mod, if any.</summary> - public string GetDefaultUpdateKey() - { - string updateKey = this.Fields.FirstOrDefault(p => p.Key == ModDataFieldKey.UpdateKey && p.IsDefault)?.Value; - return !string.IsNullOrWhiteSpace(updateKey) - ? updateKey - : null; - } - - /// <summary>Get a parsed representation of the <see cref="ModDataRecord.Fields"/> which match a given manifest.</summary> - /// <param name="manifest">The manifest to match.</param> - public ModDataRecordVersionedFields GetVersionedFields(IManifest manifest) - { - ModDataRecordVersionedFields parsed = new ModDataRecordVersionedFields { DisplayName = this.DisplayName, DataRecord = this }; - foreach (ModDataField field in this.Fields.Where(field => field.IsMatch(manifest))) - { - switch (field.Key) - { - // update key - case ModDataFieldKey.UpdateKey: - parsed.UpdateKey = field.Value; - break; - - // alternative URL - case ModDataFieldKey.AlternativeUrl: - parsed.AlternativeUrl = field.Value; - break; - - // status - case ModDataFieldKey.Status: - parsed.Status = (ModStatus)Enum.Parse(typeof(ModStatus), field.Value, ignoreCase: true); - parsed.StatusUpperVersion = field.UpperVersion; - break; - - // status reason phrase - case ModDataFieldKey.StatusReasonPhrase: - parsed.StatusReasonPhrase = field.Value; - break; - } - } - - return parsed; - } - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs deleted file mode 100644 index 237f2c66..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs +++ /dev/null @@ -1,54 +0,0 @@ -namespace StardewModdingAPI.Toolkit.Framework.ModData -{ - /// <summary>The versioned fields from a <see cref="ModDataRecord"/> for a specific manifest.</summary> - public class ModDataRecordVersionedFields - { - /********* - ** Accessors - *********/ - /// <summary>The underlying data record.</summary> - public ModDataRecord DataRecord { get; set; } - - /// <summary>The default mod name to display when the name isn't available (e.g. during dependency checks).</summary> - public string DisplayName { get; set; } - - /// <summary>The update key to apply.</summary> - public string UpdateKey { get; set; } - - /// <summary>The alternative URL the player can check for an updated version.</summary> - public string AlternativeUrl { get; set; } - - /// <summary>The predefined compatibility status.</summary> - public ModStatus Status { get; set; } = ModStatus.None; - - /// <summary>A reason phrase for the <see cref="Status"/>, or <c>null</c> to use the default reason.</summary> - public string StatusReasonPhrase { get; set; } - - /// <summary>The upper version for which the <see cref="Status"/> applies (if any).</summary> - public ISemanticVersion StatusUpperVersion { get; set; } - - - /********* - ** Public methods - *********/ - /// <summary>Get a semantic local version for update checks.</summary> - /// <param name="version">The remote version to normalise.</param> - public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version) - { - return this.DataRecord.GetLocalVersionForUpdateChecks(version); - } - - /// <summary>Get a semantic remote version for update checks.</summary> - /// <param name="version">The remote version to normalise.</param> - public ISemanticVersion GetRemoteVersionForUpdateChecks(ISemanticVersion version) - { - if (version == null) - return null; - - string rawVersion = this.DataRecord.GetRemoteVersionForUpdateChecks(version.ToString()); - return rawVersion != null - ? new SemanticVersion(rawVersion) - : version; - } - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDatabase.cs b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDatabase.cs deleted file mode 100644 index a9da884a..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModDatabase.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace StardewModdingAPI.Toolkit.Framework.ModData -{ - /// <summary>Handles access to SMAPI's internal mod metadata list.</summary> - public class ModDatabase - { - /********* - ** Fields - *********/ - /// <summary>The underlying mod data records indexed by default display name.</summary> - private readonly ModDataRecord[] Records; - - /// <summary>Get an update URL for an update key (if valid).</summary> - private readonly Func<string, string> GetUpdateUrl; - - - /********* - ** Public methods - *********/ - /// <summary>Construct an empty instance.</summary> - public ModDatabase() - : this(new ModDataRecord[0], key => null) { } - - /// <summary>Construct an instance.</summary> - /// <param name="records">The underlying mod data records indexed by default display name.</param> - /// <param name="getUpdateUrl">Get an update URL for an update key (if valid).</param> - public ModDatabase(IEnumerable<ModDataRecord> records, Func<string, string> getUpdateUrl) - { - this.Records = records.ToArray(); - this.GetUpdateUrl = getUpdateUrl; - } - - /// <summary>Get all mod data records.</summary> - public IEnumerable<ModDataRecord> GetAll() - { - return this.Records; - } - - /// <summary>Get a mod data record.</summary> - /// <param name="modID">The unique mod ID.</param> - public ModDataRecord Get(string modID) - { - return !string.IsNullOrWhiteSpace(modID) - ? this.Records.FirstOrDefault(p => p.HasID(modID)) - : null; - } - - /// <summary>Get the mod page URL for a mod (if available).</summary> - /// <param name="id">The unique mod ID.</param> - public string GetModPageUrlFor(string id) - { - // get update key - ModDataRecord record = this.Get(id); - ModDataField updateKeyField = record?.Fields.FirstOrDefault(p => p.Key == ModDataFieldKey.UpdateKey); - if (updateKeyField == null) - return null; - - // get update URL - return this.GetUpdateUrl(updateKeyField.Value); - } - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModStatus.cs b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModStatus.cs deleted file mode 100644 index 09da74bf..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModStatus.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace StardewModdingAPI.Toolkit.Framework.ModData -{ - /// <summary>Indicates how SMAPI should treat a mod.</summary> - public enum ModStatus - { - /// <summary>Don't override the status.</summary> - None, - - /// <summary>The mod is obsolete and shouldn't be used, regardless of version.</summary> - Obsolete, - - /// <summary>Assume the mod is not compatible, even if SMAPI doesn't detect any incompatible code.</summary> - AssumeBroken, - - /// <summary>Assume the mod is compatible, even if SMAPI detects incompatible code.</summary> - AssumeCompatible - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModWarning.cs b/src/StardewModdingAPI.Toolkit/Framework/ModData/ModWarning.cs deleted file mode 100644 index d61c427f..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/ModData/ModWarning.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; - -namespace StardewModdingAPI.Toolkit.Framework.ModData -{ - /// <summary>Indicates a detected non-error mod issue.</summary> - [Flags] - public enum ModWarning - { - /// <summary>No issues detected.</summary> - None = 0, - - /// <summary>SMAPI detected incompatible code in the mod, but was configured to load it anyway.</summary> - BrokenCodeLoaded = 1, - - /// <summary>The mod affects the save serializer in a way that may make saves unloadable without the mod.</summary> - ChangesSaveSerialiser = 2, - - /// <summary>The mod patches the game in a way that may impact stability.</summary> - PatchesGame = 4, - - /// <summary>The mod uses the <c>dynamic</c> keyword which won't work on Linux/Mac.</summary> - UsesDynamic = 8, - - /// <summary>The mod references specialised 'unvalided update tick' events which may impact stability.</summary> - UsesUnvalidatedUpdateTick = 16, - - /// <summary>The mod has no update keys set.</summary> - NoUpdateKeys = 32, - - /// <summary>Uses .NET APIs for filesystem access.</summary> - AccessesFilesystem = 64, - - /// <summary>Uses .NET APIs for shell or process access.</summary> - AccessesShell = 128 - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModScanning/ModFolder.cs b/src/StardewModdingAPI.Toolkit/Framework/ModScanning/ModFolder.cs deleted file mode 100644 index bb467b36..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/ModScanning/ModFolder.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using StardewModdingAPI.Toolkit.Serialisation.Models; -using StardewModdingAPI.Toolkit.Utilities; - -namespace StardewModdingAPI.Toolkit.Framework.ModScanning -{ - /// <summary>The info about a mod read from its folder.</summary> - public class ModFolder - { - /********* - ** Accessors - *********/ - /// <summary>A suggested display name for the mod folder.</summary> - public string DisplayName { get; } - - /// <summary>The folder containing the mod's manifest.json.</summary> - public DirectoryInfo Directory { get; } - - /// <summary>The mod manifest.</summary> - public Manifest Manifest { get; } - - /// <summary>The error which occurred parsing the manifest, if any.</summary> - public string ManifestParseError { get; } - - /// <summary>Whether the mod should be loaded by default. This is <c>false</c> if it was found within a folder whose name starts with a dot.</summary> - public bool ShouldBeLoaded { get; } - - - /********* - ** Public methods - *********/ - /// <summary>Construct an instance.</summary> - /// <param name="root">The root folder containing mods.</param> - /// <param name="directory">The folder containing the mod's manifest.json.</param> - /// <param name="manifest">The mod manifest.</param> - /// <param name="manifestParseError">The error which occurred parsing the manifest, if any.</param> - /// <param name="shouldBeLoaded">Whether the mod should be loaded by default. This should be <c>false</c> if it was found within a folder whose name starts with a dot.</param> - public ModFolder(DirectoryInfo root, DirectoryInfo directory, Manifest manifest, string manifestParseError = null, bool shouldBeLoaded = true) - { - // save info - this.Directory = directory; - this.Manifest = manifest; - this.ManifestParseError = manifestParseError; - this.ShouldBeLoaded = shouldBeLoaded; - - // set display name - this.DisplayName = manifest?.Name; - if (string.IsNullOrWhiteSpace(this.DisplayName)) - this.DisplayName = PathUtilities.GetRelativePath(root.FullName, directory.FullName); - } - - /// <summary>Get the update keys for a mod.</summary> - /// <param name="manifest">The mod manifest.</param> - public IEnumerable<string> GetUpdateKeys(Manifest manifest) - { - return - (manifest.UpdateKeys ?? new string[0]) - .Where(p => !string.IsNullOrWhiteSpace(p)) - .ToArray(); - } - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModScanning/ModScanner.cs b/src/StardewModdingAPI.Toolkit/Framework/ModScanning/ModScanner.cs deleted file mode 100644 index 0ab73d56..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/ModScanning/ModScanner.cs +++ /dev/null @@ -1,183 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using StardewModdingAPI.Toolkit.Serialisation; -using StardewModdingAPI.Toolkit.Serialisation.Models; - -namespace StardewModdingAPI.Toolkit.Framework.ModScanning -{ - /// <summary>Scans folders for mod data.</summary> - public class ModScanner - { - /********* - ** Fields - *********/ - /// <summary>The JSON helper with which to read manifests.</summary> - private readonly JsonHelper JsonHelper; - - /// <summary>A list of filesystem entry names to ignore when checking whether a folder should be treated as a mod.</summary> - private readonly HashSet<string> IgnoreFilesystemEntries = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase) - { - ".DS_Store", - "mcs", - "Thumbs.db" - }; - - /// <summary>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.</summary> - private readonly HashSet<string> PotentialXnbModExtensions = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase) - { - ".md", - ".png", - ".txt", - ".xnb" - }; - - - /********* - ** Public methods - *********/ - /// <summary>Construct an instance.</summary> - /// <param name="jsonHelper">The JSON helper with which to read manifests.</param> - public ModScanner(JsonHelper jsonHelper) - { - this.JsonHelper = jsonHelper; - } - - /// <summary>Extract information about all mods in the given folder.</summary> - /// <param name="rootPath">The root folder containing mods.</param> - public IEnumerable<ModFolder> GetModFolders(string rootPath) - { - DirectoryInfo root = new DirectoryInfo(rootPath); - return this.GetModFolders(root, root); - } - - /// <summary>Extract information from a mod folder.</summary> - /// <param name="root">The root folder containing mods.</param> - /// <param name="searchFolder">The folder to search for a mod.</param> - public ModFolder ReadFolder(DirectoryInfo root, DirectoryInfo searchFolder) - { - // find manifest.json - FileInfo manifestFile = this.FindManifest(searchFolder); - - // set appropriate invalid-mod error - if (manifestFile == null) - { - FileInfo[] files = searchFolder.GetFiles("*", SearchOption.AllDirectories).Where(this.IsRelevant).ToArray(); - if (!files.Any()) - return new ModFolder(root, searchFolder, 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."); - } - - // read mod info - Manifest manifest = null; - string manifestError = null; - { - try - { - if (!this.JsonHelper.ReadJsonFileIfExists<Manifest>(manifestFile.FullName, out manifest) || manifest == null) - manifestError = "its manifest is invalid."; - } - catch (SParseException ex) - { - manifestError = $"parsing its manifest failed: {ex.Message}"; - } - catch (Exception ex) - { - manifestError = $"parsing its manifest failed:\n{ex}"; - } - } - - // normalise display fields - if (manifest != null) - { - manifest.Name = this.StripNewlines(manifest.Name); - manifest.Description = this.StripNewlines(manifest.Description); - manifest.Author = this.StripNewlines(manifest.Author); - } - - return new ModFolder(root, manifestFile.Directory, manifest, manifestError); - } - - - /********* - ** Private methods - *********/ - /// <summary>Recursively extract information about all mods in the given folder.</summary> - /// <param name="root">The root mod folder.</param> - /// <param name="folder">The folder to search for mods.</param> - public IEnumerable<ModFolder> GetModFolders(DirectoryInfo root, DirectoryInfo folder) - { - // 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); - - // recurse into subfolders - else if (this.IsModSearchFolder(root, folder)) - { - foreach (DirectoryInfo subfolder in folder.EnumerateDirectories()) - { - foreach (ModFolder match in this.GetModFolders(root, subfolder)) - yield return match; - } - } - - // treat as mod folder - else - yield return this.ReadFolder(root, folder); - } - - /// <summary>Find the manifest for a mod folder.</summary> - /// <param name="folder">The folder to search.</param> - private FileInfo FindManifest(DirectoryInfo folder) - { - while (true) - { - // check for manifest in current folder - FileInfo file = new FileInfo(Path.Combine(folder.FullName, "manifest.json")); - if (file.Exists) - return file; - - // check for single subfolder - FileSystemInfo[] entries = folder.EnumerateFileSystemInfos().Take(2).ToArray(); - if (entries.Length == 1 && entries[0] is DirectoryInfo subfolder) - { - folder = subfolder; - continue; - } - - // not found - return null; - } - } - - /// <summary>Get whether a given folder should be treated as a search folder (i.e. look for subfolders containing mods).</summary> - /// <param name="root">The root mod folder.</param> - /// <param name="folder">The folder to search for mods.</param> - private bool IsModSearchFolder(DirectoryInfo root, DirectoryInfo folder) - { - if (root.FullName == folder.FullName) - return true; - - DirectoryInfo[] subfolders = folder.GetDirectories().Where(this.IsRelevant).ToArray(); - FileInfo[] files = folder.GetFiles().Where(this.IsRelevant).ToArray(); - return subfolders.Any() && !files.Any(); - } - - /// <summary>Get whether a file or folder is relevant when deciding how to process a mod folder.</summary> - /// <param name="entry">The file or folder.</param> - private bool IsRelevant(FileSystemInfo entry) - { - return !this.IgnoreFilesystemEntries.Contains(entry.Name); - } - - /// <summary>Strip newlines from a string.</summary> - /// <param name="input">The input to strip.</param> - private string StripNewlines(string input) - { - return input?.Replace("\r", "").Replace("\n", ""); - } - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/UpdateData/ModRepositoryKey.cs b/src/StardewModdingAPI.Toolkit/Framework/UpdateData/ModRepositoryKey.cs deleted file mode 100644 index f6c402d5..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/UpdateData/ModRepositoryKey.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace StardewModdingAPI.Toolkit.Framework.UpdateData -{ - /// <summary>A mod repository which SMAPI can check for updates.</summary> - public enum ModRepositoryKey - { - /// <summary>An unknown or invalid mod repository.</summary> - Unknown, - - /// <summary>The Chucklefish mod repository.</summary> - Chucklefish, - - /// <summary>A GitHub project containing releases.</summary> - GitHub, - - /// <summary>The ModDrop mod repository.</summary> - ModDrop, - - /// <summary>The Nexus Mods mod repository.</summary> - Nexus - } -} diff --git a/src/StardewModdingAPI.Toolkit/Framework/UpdateData/UpdateKey.cs b/src/StardewModdingAPI.Toolkit/Framework/UpdateData/UpdateKey.cs deleted file mode 100644 index 865ebcf7..00000000 --- a/src/StardewModdingAPI.Toolkit/Framework/UpdateData/UpdateKey.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; - -namespace StardewModdingAPI.Toolkit.Framework.UpdateData -{ - /// <summary>A namespaced mod ID which uniquely identifies a mod within a mod repository.</summary> - public class UpdateKey - { - /********* - ** Accessors - *********/ - /// <summary>The raw update key text.</summary> - public string RawText { get; } - - /// <summary>The mod repository containing the mod.</summary> - public ModRepositoryKey Repository { get; } - - /// <summary>The mod ID within the repository.</summary> - public string ID { get; } - - /// <summary>Whether the update key seems to be valid.</summary> - public bool LooksValid { get; } - - - /********* - ** Public methods - *********/ - /// <summary>Construct an instance.</summary> - /// <param name="rawText">The raw update key text.</param> - /// <param name="repository">The mod repository containing the mod.</param> - /// <param name="id">The mod ID within the repository.</param> - public UpdateKey(string rawText, ModRepositoryKey repository, string id) - { - this.RawText = rawText; - this.Repository = repository; - this.ID = id; - this.LooksValid = - repository != ModRepositoryKey.Unknown - && !string.IsNullOrWhiteSpace(id); - } - - /// <summary>Parse a raw update key.</summary> - /// <param name="raw">The raw update key to parse.</param> - public static UpdateKey Parse(string raw) - { - // split parts - string[] parts = raw?.Split(':'); - if (parts == null || parts.Length != 2) - return new UpdateKey(raw, ModRepositoryKey.Unknown, null); - - // extract parts - string repositoryKey = parts[0].Trim(); - string id = parts[1].Trim(); - if (string.IsNullOrWhiteSpace(id)) - id = null; - - // parse - if (!Enum.TryParse(repositoryKey, true, out ModRepositoryKey repository)) - return new UpdateKey(raw, ModRepositoryKey.Unknown, id); - if (id == null) - return new UpdateKey(raw, repository, null); - - return new UpdateKey(raw, repository, id); - } - - /// <summary>Get a string that represents the current object.</summary> - public override string ToString() - { - return this.LooksValid - ? $"{this.Repository}:{this.ID}" - : this.RawText; - } - } -} |