diff options
Diffstat (limited to 'src/StardewModdingAPI/Framework')
4 files changed, 59 insertions, 38 deletions
diff --git a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs index 2da10348..3674faec 100644 --- a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs +++ b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs @@ -64,7 +64,7 @@ namespace StardewModdingAPI.Framework.ModLoading dataRecord = ( from mod in dataRecords where - mod.ID.Any(p => p.Matches(key, manifest)) + mod.ID.Matches(key, manifest) && (mod.LowerVersion == null || !manifest.Version.IsOlderThan(mod.LowerVersion)) && (mod.UpperVersion == null || !manifest.Version.IsNewerThan(mod.UpperVersion)) select mod diff --git a/src/StardewModdingAPI/Framework/Models/ModDataID.cs b/src/StardewModdingAPI/Framework/Models/ModDataID.cs index 5b45b507..d19434fa 100644 --- a/src/StardewModdingAPI/Framework/Models/ModDataID.cs +++ b/src/StardewModdingAPI/Framework/Models/ModDataID.cs @@ -1,22 +1,28 @@ using System; +using System.Linq; using Newtonsoft.Json; namespace StardewModdingAPI.Framework.Models { /// <summary>Uniquely identifies a mod in SMAPI's internal data.</summary> + /// <remarks> + /// 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 <c>|</c> + /// 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. + /// </remarks> internal class ModDataID { /********* - ** Accessors + ** Properties *********/ - /// <summary>The unique mod ID.</summary> - public string ID { get; set; } - - /// <summary>The mod name to disambiguate non-unique IDs, or <c>null</c> to ignore the mod name.</summary> - public string Name { get; set; } - - /// <summary>The author name to disambiguate non-unique IDs, or <c>null</c> to ignore the author.</summary> - public string Author { get; set; } + /// <summary>The unique sets of field values which identify this mod.</summary> + private readonly FieldSnapshot[] Snapshots; /********* @@ -26,17 +32,18 @@ namespace StardewModdingAPI.Framework.Models public ModDataID() { } /// <summary>Construct an instance.</summary> - /// <param name="data">The mod ID or a JSON string matching the <see cref="ModDataID"/> fields.</param> + /// <param name="data">The mod identifier string (see remarks on <see cref="ModDataID"/>).</param> public ModDataID(string data) { - // JSON can be stuffed into the ID string as a convenience hack to keep JSON mod lists - // formatted readably. The tradeoff is that the format is a bit more magical, but that's - // probably acceptable since players aren't meant to edit it. It's also fairly clear what - // the JSON strings do, if not necessarily how. - if (data.StartsWith("{")) - JsonConvert.PopulateObject(data, this); - else - this.ID = data; + this.Snapshots = + ( + from string part in data.Split('|') + let str = part.Trim() + select str.StartsWith("{") + ? JsonConvert.DeserializeObject<FieldSnapshot>(str) + : new FieldSnapshot { ID = str } + ) + .ToArray(); } /// <summary>Get whether this ID matches a given mod manifest.</summary> @@ -44,14 +51,35 @@ namespace StardewModdingAPI.Framework.Models /// <param name="manifest">The manifest to check.</param> public bool Matches(string id, IManifest manifest) { - return - this.ID.Equals(id, StringComparison.InvariantCultureIgnoreCase) + return this.Snapshots.Any(snapshot => + snapshot.ID.Equals(id, StringComparison.InvariantCultureIgnoreCase) && ( - this.Author == null - || this.Author.Equals(manifest.Author, StringComparison.InvariantCultureIgnoreCase) - || (manifest.ExtraFields.ContainsKey("Authour") && this.Author.Equals(manifest.ExtraFields["Authour"].ToString(), 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)) ) - && (this.Name == null || this.Name.Equals(manifest.Name, StringComparison.InvariantCultureIgnoreCase)); + && (snapshot.Name == null || snapshot.Name.Equals(manifest.Name, StringComparison.InvariantCultureIgnoreCase)) + ); + } + + + /********* + ** Private models + *********/ + /// <summary>A unique set of fields which identifies the mod.</summary> + private class FieldSnapshot + { + /********* + ** Accessors + *********/ + /// <summary>The unique mod ID.</summary> + public string ID { get; set; } + + /// <summary>The mod name, or <c>null</c> to ignore the mod name.</summary> + public string Name { get; set; } + + /// <summary>The author name, or <c>null</c> to ignore the author.</summary> + public string Author { get; set; } } } } diff --git a/src/StardewModdingAPI/Framework/Models/ModDataRecord.cs b/src/StardewModdingAPI/Framework/Models/ModDataRecord.cs index d40f2c78..8126022d 100644 --- a/src/StardewModdingAPI/Framework/Models/ModDataRecord.cs +++ b/src/StardewModdingAPI/Framework/Models/ModDataRecord.cs @@ -9,9 +9,9 @@ namespace StardewModdingAPI.Framework.Models /********* ** Accessors *********/ - /// <summary>The unique mod IDs.</summary> + /// <summary>The unique mod identifier.</summary> [JsonConverter(typeof(SFieldConverter))] - public ModDataID[] ID { get; set; } + public ModDataID ID { get; set; } /// <summary>The mod name.</summary> public string Name { get; set; } diff --git a/src/StardewModdingAPI/Framework/Serialisation/SFieldConverter.cs b/src/StardewModdingAPI/Framework/Serialisation/SFieldConverter.cs index 59cc1582..d71e138b 100644 --- a/src/StardewModdingAPI/Framework/Serialisation/SFieldConverter.cs +++ b/src/StardewModdingAPI/Framework/Serialisation/SFieldConverter.cs @@ -27,7 +27,7 @@ namespace StardewModdingAPI.Framework.Serialisation return objectType == typeof(ISemanticVersion) || objectType == typeof(IManifestDependency[]) - || objectType == typeof(ModDataID[]); + || objectType == typeof(ModDataID); } /// <summary>Reads the JSON representation of the object.</summary> @@ -83,17 +83,10 @@ namespace StardewModdingAPI.Framework.Serialisation } // mod compatibility ID - if (objectType == typeof(ModDataID[])) + if (objectType == typeof(ModDataID)) { - List<ModDataID> result = new List<ModDataID>(); - foreach (JToken child in JArray.Load(reader).Children()) - { - result.Add(child is JValue value - ? new ModDataID(value.Value<string>()) - : child.ToObject<ModDataID>() - ); - } - return result.ToArray(); + JToken token = JToken.Load(reader); + return new ModDataID(token.Value<string>()); } // unknown |