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; } } }