From 5f19e4f2035c36f9c6c882da3767d6f29409db1c Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 27 Jun 2018 00:05:53 -0400 Subject: move mod DB parsing into toolkit (#532) --- src/SMAPI/Framework/ModData/ModDataField.cs | 82 ------------ src/SMAPI/Framework/ModData/ModDataFieldKey.cs | 18 --- src/SMAPI/Framework/ModData/ModDataRecord.cs | 146 --------------------- src/SMAPI/Framework/ModData/ModDatabase.cs | 140 -------------------- src/SMAPI/Framework/ModData/ModStatus.cs | 18 --- src/SMAPI/Framework/ModData/ParsedModDataRecord.cs | 51 ------- 6 files changed, 455 deletions(-) delete mode 100644 src/SMAPI/Framework/ModData/ModDataField.cs delete mode 100644 src/SMAPI/Framework/ModData/ModDataFieldKey.cs delete mode 100644 src/SMAPI/Framework/ModData/ModDataRecord.cs delete mode 100644 src/SMAPI/Framework/ModData/ModDatabase.cs delete mode 100644 src/SMAPI/Framework/ModData/ModStatus.cs delete mode 100644 src/SMAPI/Framework/ModData/ParsedModDataRecord.cs (limited to 'src/SMAPI/Framework/ModData') diff --git a/src/SMAPI/Framework/ModData/ModDataField.cs b/src/SMAPI/Framework/ModData/ModDataField.cs deleted file mode 100644 index df906103..00000000 --- a/src/SMAPI/Framework/ModData/ModDataField.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System.Linq; - -namespace StardewModdingAPI.Framework.ModData -{ - /// A versioned mod metadata field. - internal class ModDataField - { - /********* - ** Accessors - *********/ - /// The field key. - public ModDataFieldKey Key { get; } - - /// The field value. - public string Value { get; } - - /// Whether this field should only be applied if it's not already set. - public bool IsDefault { get; } - - /// The lowest version in the range, or null for all past versions. - public ISemanticVersion LowerVersion { get; } - - /// The highest version in the range, or null for all future versions. - public ISemanticVersion UpperVersion { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The field key. - /// The field value. - /// Whether this field should only be applied if it's not already set. - /// The lowest version in the range, or null for all past versions. - /// The highest version in the range, or null for all future versions. - 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; - } - - /// Get whether this data field applies for the given manifest. - /// The mod manifest. - 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 - *********/ - /// Get whether a manifest field has a meaningful value for the purposes of enforcing . - /// The mod manifest. - /// The field key matching . - 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/SMAPI/Framework/ModData/ModDataFieldKey.cs b/src/SMAPI/Framework/ModData/ModDataFieldKey.cs deleted file mode 100644 index f68f575c..00000000 --- a/src/SMAPI/Framework/ModData/ModDataFieldKey.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace StardewModdingAPI.Framework.ModData -{ - /// The valid field keys. - public enum ModDataFieldKey - { - /// A manifest update key. - UpdateKey, - - /// An alternative URL the player can check for an updated version. - AlternativeUrl, - - /// The mod's predefined compatibility status. - Status, - - /// A reason phrase for the , or null to use the default reason. - StatusReasonPhrase - } -} diff --git a/src/SMAPI/Framework/ModData/ModDataRecord.cs b/src/SMAPI/Framework/ModData/ModDataRecord.cs deleted file mode 100644 index 56275f53..00000000 --- a/src/SMAPI/Framework/ModData/ModDataRecord.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace StardewModdingAPI.Framework.ModData -{ - /// Raw mod metadata from SMAPI's internal mod list. - internal class ModDataRecord - { - /********* - ** Properties - *********/ - /// This field stores properties that aren't mapped to another field before they're parsed into . - [JsonExtensionData] - private IDictionary ExtensionData; - - - /********* - ** Accessors - *********/ - /// The mod's current unique ID. - public string ID { get; set; } - - /// The former mod IDs (if any). - /// - /// 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. Format rules: - /// 1. If the mod's ID changed over time, multiple variants can be separated by the - /// | character. - /// 2. Each variant can take one of two forms: - /// - A simple string matching the mod's UniqueID value. - /// - A JSON structure containing any of four manifest fields (ID, Name, Author, and - /// EntryDll) to match. - /// - public string FormerIDs { get; set; } - - /// Maps local versions to a semantic version for update checks. - public IDictionary MapLocalVersions { get; set; } = new Dictionary(); - - /// Maps remote versions to a semantic version for update checks. - public IDictionary MapRemoteVersions { get; set; } = new Dictionary(); - - /// The versioned field data. - /// - /// This maps field names to values. This should be accessed via . - /// Format notes: - /// - Each key consists of a field name prefixed with any combination of version range - /// and Default, separated by pipes (whitespace trimmed). For example, Name - /// will always override the name, Default | Name will only override a blank - /// name, and ~1.1 | Default | Name will override blank names up to version 1.1. - /// - The version format is min~max (where either side can be blank for unbounded), or - /// a single version number. - /// - The field name itself corresponds to a value. - /// - public IDictionary Fields { get; set; } = new Dictionary(); - - - /********* - ** Public methods - *********/ - /// Get a parsed representation of the . - public IEnumerable GetFields() - { - foreach (KeyValuePair 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); - } - } - - /// Get a semantic local version for update checks. - /// The remote version to normalise. - public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version) - { - return this.MapLocalVersions != null && this.MapLocalVersions.TryGetValue(version.ToString(), out string newVersion) - ? new SemanticVersion(newVersion) - : version; - } - - /// Get a semantic remote version for update checks. - /// The remote version to normalise. - 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; - } - - - /********* - ** Private methods - *********/ - /// The method invoked after JSON deserialisation. - /// The deserialisation context. - [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/SMAPI/Framework/ModData/ModDatabase.cs b/src/SMAPI/Framework/ModData/ModDatabase.cs deleted file mode 100644 index 62f37d9b..00000000 --- a/src/SMAPI/Framework/ModData/ModDatabase.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace StardewModdingAPI.Framework.ModData -{ - /// Handles access to SMAPI's internal mod metadata list. - internal class ModDatabase - { - /********* - ** Properties - *********/ - /// The underlying mod data records indexed by default display name. - private readonly IDictionary Records; - - /// Get an update URL for an update key (if valid). - private readonly Func GetUpdateUrl; - - - /********* - ** Public methods - *********/ - /// Construct an empty instance. - public ModDatabase() - : this(new Dictionary(), key => null) { } - - /// Construct an instance. - /// The underlying mod data records indexed by default display name. - /// Get an update URL for an update key (if valid). - public ModDatabase(IDictionary records, Func getUpdateUrl) - { - this.Records = records; - this.GetUpdateUrl = getUpdateUrl; - } - - /// Get a parsed representation of the which match a given manifest. - /// The manifest to match. - public ParsedModDataRecord GetParsed(IManifest manifest) - { - // get raw record - if (!this.TryGetRaw(manifest?.UniqueID, out string displayName, out ModDataRecord record)) - return null; - - // parse fields - ParsedModDataRecord parsed = new ParsedModDataRecord { DisplayName = displayName, DataRecord = record }; - foreach (ModDataField field in record.GetFields().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; - } - - /// Get the display name for a given mod ID (if available). - /// The unique mod ID. - public string GetDisplayNameFor(string id) - { - return this.TryGetRaw(id, out string displayName, out ModDataRecord _) - ? displayName - : null; - } - - /// Get the mod page URL for a mod (if available). - /// The unique mod ID. - public string GetModPageUrlFor(string id) - { - // get raw record - if (!this.TryGetRaw(id, out string _, out ModDataRecord record)) - return null; - - // get update key - ModDataField updateKeyField = record.GetFields().FirstOrDefault(p => p.Key == ModDataFieldKey.UpdateKey); - if (updateKeyField == null) - return null; - - // get update URL - return this.GetUpdateUrl(updateKeyField.Value); - } - - - /********* - ** Private models - *********/ - /// Get a raw data record. - /// The mod ID to match. - /// The mod's default display name. - /// The raw mod record. - private bool TryGetRaw(string id, out string displayName, out ModDataRecord record) - { - if (!string.IsNullOrWhiteSpace(id)) - { - foreach (var entry in this.Records) - { - displayName = entry.Key; - record = entry.Value; - - // try main ID - if (record.ID != null && record.ID.Equals(id, StringComparison.InvariantCultureIgnoreCase)) - return true; - - // try former IDs - if (record.FormerIDs != null) - { - foreach (string part in record.FormerIDs.Split('|')) - { - if (part.Trim().Equals(id, StringComparison.InvariantCultureIgnoreCase)) - return true; - } - } - } - } - - displayName = null; - record = null; - return false; - } - } -} diff --git a/src/SMAPI/Framework/ModData/ModStatus.cs b/src/SMAPI/Framework/ModData/ModStatus.cs deleted file mode 100644 index 0e1d94d4..00000000 --- a/src/SMAPI/Framework/ModData/ModStatus.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace StardewModdingAPI.Framework.ModData -{ - /// Indicates how SMAPI should treat a mod. - internal enum ModStatus - { - /// Don't override the status. - None, - - /// The mod is obsolete and shouldn't be used, regardless of version. - Obsolete, - - /// Assume the mod is not compatible, even if SMAPI doesn't detect any incompatible code. - AssumeBroken, - - /// Assume the mod is compatible, even if SMAPI detects incompatible code. - AssumeCompatible - } -} diff --git a/src/SMAPI/Framework/ModData/ParsedModDataRecord.cs b/src/SMAPI/Framework/ModData/ParsedModDataRecord.cs deleted file mode 100644 index 3801fac3..00000000 --- a/src/SMAPI/Framework/ModData/ParsedModDataRecord.cs +++ /dev/null @@ -1,51 +0,0 @@ -namespace StardewModdingAPI.Framework.ModData -{ - /// A parsed representation of the fields from a for a specific manifest. - internal class ParsedModDataRecord - { - /********* - ** Accessors - *********/ - /// The underlying data record. - public ModDataRecord DataRecord { get; set; } - - /// The default mod name to display when the name isn't available (e.g. during dependency checks). - public string DisplayName { get; set; } - - /// The update key to apply. - public string UpdateKey { get; set; } - - /// The alternative URL the player can check for an updated version. - public string AlternativeUrl { get; set; } - - /// The predefined compatibility status. - public ModStatus Status { get; set; } = ModStatus.None; - - /// A reason phrase for the , or null to use the default reason. - public string StatusReasonPhrase { get; set; } - - /// The upper version for which the applies (if any). - public ISemanticVersion StatusUpperVersion { get; set; } - - - /********* - ** Public methods - *********/ - /// Get a semantic local version for update checks. - /// The remote version to normalise. - public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version) - { - return this.DataRecord.GetLocalVersionForUpdateChecks(version); - } - - /// Get a semantic remote version for update checks. - /// The remote version to normalise. - public ISemanticVersion GetRemoteVersionForUpdateChecks(string version) - { - string rawVersion = this.DataRecord.GetRemoteVersionForUpdateChecks(version); - return rawVersion != null - ? new SemanticVersion(rawVersion) - : null; - } - } -} -- cgit