From 929dccb75a1405737975d76648e015a3e7c00177 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 7 Oct 2017 23:07:10 -0400 Subject: reorganise repo structure --- src/SMAPI/Framework/Models/Manifest.cs | 47 +++++++++++++ src/SMAPI/Framework/Models/ManifestDependency.cs | 34 ++++++++++ src/SMAPI/Framework/Models/ModCompatibility.cs | 55 +++++++++++++++ src/SMAPI/Framework/Models/ModDataID.cs | 85 ++++++++++++++++++++++++ src/SMAPI/Framework/Models/ModDataRecord.cs | 63 ++++++++++++++++++ src/SMAPI/Framework/Models/ModStatus.cs | 18 +++++ src/SMAPI/Framework/Models/SConfig.cs | 27 ++++++++ 7 files changed, 329 insertions(+) create mode 100644 src/SMAPI/Framework/Models/Manifest.cs create mode 100644 src/SMAPI/Framework/Models/ManifestDependency.cs create mode 100644 src/SMAPI/Framework/Models/ModCompatibility.cs create mode 100644 src/SMAPI/Framework/Models/ModDataID.cs create mode 100644 src/SMAPI/Framework/Models/ModDataRecord.cs create mode 100644 src/SMAPI/Framework/Models/ModStatus.cs create mode 100644 src/SMAPI/Framework/Models/SConfig.cs (limited to 'src/SMAPI/Framework/Models') diff --git a/src/SMAPI/Framework/Models/Manifest.cs b/src/SMAPI/Framework/Models/Manifest.cs new file mode 100644 index 00000000..b85787e5 --- /dev/null +++ b/src/SMAPI/Framework/Models/Manifest.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using StardewModdingAPI.Framework.Serialisation; + +namespace StardewModdingAPI.Framework.Models +{ + /// A manifest which describes a mod for SMAPI. + internal class Manifest : IManifest + { + /********* + ** Accessors + *********/ + /// The mod name. + public string Name { get; set; } + + /// A brief description of the mod. + public string Description { get; set; } + + /// The mod author's name. + public string Author { get; set; } + + /// The mod version. + [JsonConverter(typeof(SFieldConverter))] + public ISemanticVersion Version { get; set; } + + /// The minimum SMAPI version required by this mod, if any. + [JsonConverter(typeof(SFieldConverter))] + public ISemanticVersion MinimumApiVersion { get; set; } + + /// The name of the DLL in the directory that has the method. + public string EntryDll { get; set; } + + /// The other mods that must be loaded before this mod. + [JsonConverter(typeof(SFieldConverter))] + public IManifestDependency[] Dependencies { get; set; } + + /// The namespaced mod IDs to query for updates (like Nexus:541). + public string[] UpdateKeys { get; set; } + + /// The unique mod ID. + public string UniqueID { get; set; } + + /// Any manifest fields which didn't match a valid field. + [JsonExtensionData] + public IDictionary ExtraFields { get; set; } + } +} diff --git a/src/SMAPI/Framework/Models/ManifestDependency.cs b/src/SMAPI/Framework/Models/ManifestDependency.cs new file mode 100644 index 00000000..5646b335 --- /dev/null +++ b/src/SMAPI/Framework/Models/ManifestDependency.cs @@ -0,0 +1,34 @@ +namespace StardewModdingAPI.Framework.Models +{ + /// A mod dependency listed in a mod manifest. + internal class ManifestDependency : IManifestDependency + { + /********* + ** Accessors + *********/ + /// The unique mod ID to require. + public string UniqueID { get; set; } + + /// The minimum required version (if any). + public ISemanticVersion MinimumVersion { get; set; } + + /// Whether the dependency must be installed to use the mod. + public bool IsRequired { get; set; } + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The unique mod ID to require. + /// The minimum required version (if any). + /// Whether the dependency must be installed to use the mod. + public ManifestDependency(string uniqueID, string minimumVersion, bool required = true) + { + this.UniqueID = uniqueID; + this.MinimumVersion = !string.IsNullOrWhiteSpace(minimumVersion) + ? new SemanticVersion(minimumVersion) + : null; + this.IsRequired = required; + } + } +} diff --git a/src/SMAPI/Framework/Models/ModCompatibility.cs b/src/SMAPI/Framework/Models/ModCompatibility.cs new file mode 100644 index 00000000..54737e6c --- /dev/null +++ b/src/SMAPI/Framework/Models/ModCompatibility.cs @@ -0,0 +1,55 @@ +using System; + +namespace StardewModdingAPI.Framework.Models +{ + /// Specifies the compatibility of a given mod version range. + internal class ModCompatibility + { + /********* + ** Accessors + *********/ + /// 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; } + + /// The mod compatibility. + public ModStatus Status { get; } + + /// The reason phrase to show in log output, or null to use the default value. + /// For example, "this version is incompatible with the latest version of the game". + public string ReasonPhrase { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// A version range, which consists of two version strings separated by a '~' character. Either side can be left blank for an unbounded range. + /// The mod compatibility. + /// The reason phrase to show in log output, or null to use the default value. + public ModCompatibility(string versionRange, ModStatus status, string reasonPhrase) + { + // extract version strings + string[] versions = versionRange.Split('~'); + if (versions.Length != 2) + throw new FormatException($"Could not parse '{versionRange}' as a version range. It must have two version strings separated by a '~' character (either side can be left blank for an unbounded range)."); + + // initialise + this.LowerVersion = !string.IsNullOrWhiteSpace(versions[0]) ? new SemanticVersion(versions[0]) : null; + this.UpperVersion = !string.IsNullOrWhiteSpace(versions[1]) ? new SemanticVersion(versions[1]) : null; + this.Status = status; + this.ReasonPhrase = reasonPhrase; + } + + /// Get whether a given version is contained within this compatibility range. + /// The version to check. + public bool MatchesVersion(ISemanticVersion version) + { + return + (this.LowerVersion == null || !version.IsOlderThan(this.LowerVersion)) + && (this.UpperVersion == null || !version.IsNewerThan(this.UpperVersion)); + } + } +} diff --git a/src/SMAPI/Framework/Models/ModDataID.cs b/src/SMAPI/Framework/Models/ModDataID.cs new file mode 100644 index 00000000..d19434fa --- /dev/null +++ b/src/SMAPI/Framework/Models/ModDataID.cs @@ -0,0 +1,85 @@ +using System; +using System.Linq; +using Newtonsoft.Json; + +namespace StardewModdingAPI.Framework.Models +{ + /// Uniquely identifies a mod in SMAPI's internal data. + /// + /// This represents a custom format which uniquely identifies a mod across all versions, even + /// if its field values change or it doesn't specify a unique ID. This is mapped to a string + /// with the following format: + /// + /// 1. If the mod's identifier 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 three manifest fields (ID, Name, and Author) to match. + /// + internal class ModDataID + { + /********* + ** Properties + *********/ + /// The unique sets of field values which identify this mod. + private readonly FieldSnapshot[] Snapshots; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + public ModDataID() { } + + /// Construct an instance. + /// The mod identifier string (see remarks on ). + public ModDataID(string data) + { + this.Snapshots = + ( + from string part in data.Split('|') + let str = part.Trim() + select str.StartsWith("{") + ? JsonConvert.DeserializeObject(str) + : new FieldSnapshot { ID = str } + ) + .ToArray(); + } + + /// Get whether this ID matches a given mod manifest. + /// The mod's unique ID, or a substitute ID if it isn't set in the manifest. + /// The manifest to check. + public bool Matches(string id, IManifest manifest) + { + return this.Snapshots.Any(snapshot => + snapshot.ID.Equals(id, StringComparison.InvariantCultureIgnoreCase) + && ( + snapshot.Author == null + || snapshot.Author.Equals(manifest.Author, StringComparison.InvariantCultureIgnoreCase) + || (manifest.ExtraFields.ContainsKey("Authour") && snapshot.Author.Equals(manifest.ExtraFields["Authour"].ToString(), StringComparison.InvariantCultureIgnoreCase)) + ) + && (snapshot.Name == null || snapshot.Name.Equals(manifest.Name, StringComparison.InvariantCultureIgnoreCase)) + ); + } + + + /********* + ** Private models + *********/ + /// A unique set of fields which identifies the mod. + private class FieldSnapshot + { + /********* + ** Accessors + *********/ + /// The unique mod ID. + public string ID { get; set; } + + /// The mod name, or null to ignore the mod name. + public string Name { get; set; } + + /// The author name, or null to ignore the author. + public string Author { get; set; } + } + } +} diff --git a/src/SMAPI/Framework/Models/ModDataRecord.cs b/src/SMAPI/Framework/Models/ModDataRecord.cs new file mode 100644 index 00000000..c6a12188 --- /dev/null +++ b/src/SMAPI/Framework/Models/ModDataRecord.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using StardewModdingAPI.Framework.Serialisation; + +namespace StardewModdingAPI.Framework.Models +{ + /// Metadata about a mod from SMAPI's internal data. + internal class ModDataRecord + { + /********* + ** Accessors + *********/ + /// The unique mod identifier. + [JsonConverter(typeof(SFieldConverter))] + public ModDataID ID { get; set; } + + /// A value to inject into field if it's not already set. + public string[] UpdateKeys { get; set; } + + /// The URL where the player can get an unofficial or alternative version of the mod if the official version isn't compatible. + public string AlternativeUrl { get; set; } + + /// The compatibility of given mod versions (if any). + [JsonConverter(typeof(SFieldConverter))] + public ModCompatibility[] Compatibility { get; set; } = new ModCompatibility[0]; + + /// Map local versions to a semantic version for update checks. + public IDictionary MapLocalVersions { get; set; } = new Dictionary(); + + /// Map remote versions to a semantic version for update checks. + public IDictionary MapRemoteVersions { get; set; } = new Dictionary(); + + + /********* + ** Public methods + *********/ + /// Get the compatibility record for a given version, if any. + /// The mod version to check. + public ModCompatibility GetCompatibility(ISemanticVersion version) + { + return this.Compatibility.FirstOrDefault(p => p.MatchesVersion(version)); + } + + /// Get a semantic local version for update checks. + /// The local version to normalise. + public string GetLocalVersionForUpdateChecks(string version) + { + return this.MapLocalVersions != null && this.MapLocalVersions.TryGetValue(version, out string newVersion) + ? newVersion + : version; + } + + /// Get a semantic remote version for update checks. + /// The remote version to normalise. + public string GetRemoteVersionForUpdateChecks(string version) + { + return this.MapRemoteVersions != null && this.MapRemoteVersions.TryGetValue(version, out string newVersion) + ? newVersion + : version; + } + } +} diff --git a/src/SMAPI/Framework/Models/ModStatus.cs b/src/SMAPI/Framework/Models/ModStatus.cs new file mode 100644 index 00000000..343ccb7e --- /dev/null +++ b/src/SMAPI/Framework/Models/ModStatus.cs @@ -0,0 +1,18 @@ +namespace StardewModdingAPI.Framework.Models +{ + /// 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/Models/SConfig.cs b/src/SMAPI/Framework/Models/SConfig.cs new file mode 100644 index 00000000..401e1a3a --- /dev/null +++ b/src/SMAPI/Framework/Models/SConfig.cs @@ -0,0 +1,27 @@ +namespace StardewModdingAPI.Framework.Models +{ + /// The SMAPI configuration settings. + internal class SConfig + { + /******** + ** Accessors + ********/ + /// Whether to enable development features. + public bool DeveloperMode { get; set; } + + /// Whether to check for newer versions of SMAPI and mods on startup. + public bool CheckForUpdates { get; set; } + + /// SMAPI's GitHub project name, used to perform update checks. + public string GitHubProjectName { get; set; } + + /// The base URL for SMAPI's web API, used to perform update checks. + public string WebApiBaseUrl { get; set; } + + /// Whether SMAPI should log more information about the game context. + public bool VerboseLogging { get; set; } + + /// Extra metadata about mods. + public ModDataRecord[] ModData { get; set; } + } +} -- cgit