/// <summary>Load config values from the content pack.</summary> /// <param name="contentPack">The content pack whose config file to read.</param> /// <param name="config">The config schema.</param> /// <param name="logWarning">The callback to invoke on each validation warning, passed the field name and reason respectively.</param> private void LoadConfigValues(ManagedContentPack contentPack, InvariantDictionary <ConfigField> config, Action <string, string> logWarning) { if (!config.Any()) { return; } // read raw config InvariantDictionary <InvariantHashSet> configValues = new InvariantDictionary <InvariantHashSet>( from entry in (contentPack.ReadJsonFile <InvariantDictionary <string> >(this.Filename) ?? new InvariantDictionary <string>()) let key = entry.Key.Trim() let value = this.ParseCommaDelimitedField(entry.Value) select new KeyValuePair <string, InvariantHashSet>(key, value) ); // remove invalid values foreach (string key in configValues.Keys.ExceptIgnoreCase(config.Keys).ToArray()) { logWarning(key, "no such field supported by this content pack."); configValues.Remove(key); } // inject default values foreach (string key in config.Keys) { ConfigField field = config[key]; if (!configValues.TryGetValue(key, out InvariantHashSet values) || (!field.AllowBlank && !values.Any())) { configValues[key] = field.DefaultValues; } } // parse each field foreach (string key in config.Keys) { // set value ConfigField field = config[key]; field.Value = configValues[key]; // validate allow-multiple if (!field.AllowMultiple && field.Value.Count > 1) { logWarning(key, "field only allows a single value."); field.Value = field.DefaultValues; continue; } // validate allow-values if (field.AllowValues.Any()) { string[] invalidValues = field.Value.ExceptIgnoreCase(field.AllowValues).ToArray(); if (invalidValues.Any()) { logWarning(key, $"found invalid values ({string.Join(", ", invalidValues)}), expected: {string.Join(", ", field.AllowValues)}."); field.Value = field.DefaultValues; } } } }
/// <summary>Read the configuration file for a content pack.</summary> /// <param name="contentPack">The content pack.</param> /// <param name="rawSchema">The raw config schema from the mod's <c>content.json</c>.</param> public InvariantDictionary <ConfigField> Read(ManagedContentPack contentPack, InvariantDictionary <ConfigSchemaFieldConfig> rawSchema) { InvariantDictionary <ConfigField> config = this.LoadConfigSchema(rawSchema, logWarning: (field, reason) => this.LogWarning(contentPack, $"{nameof(ContentConfig.ConfigSchema)} field '{field}'", reason)); this.LoadConfigValues(contentPack, config, logWarning: (field, reason) => this.LogWarning(contentPack, $"{this.Filename} > {field}", reason)); return(config); }
/// <summary>Get the tokens which are defined for a specific content pack. This returns a reference to the list, which can be held for a live view of the tokens. If the content pack isn't currently tracked, this will add it.</summary> /// <param name="pack">The content pack to manage.</param> public ModTokenContext TrackLocalTokens(ManagedContentPack pack) { string scope = pack.Manifest.UniqueID; if (!this.LocalTokens.TryGetValue(pack.Pack, out ModTokenContext localTokens)) { this.LocalTokens[pack.Pack] = localTokens = new ModTokenContext(scope, this); foreach (IValueProvider valueProvider in this.GetLocalValueProviders(pack)) { localTokens.AddLocalToken(new Token(valueProvider, scope)); } } return(localTokens); }
/// <summary>Save the configuration file for a content pack.</summary> /// <param name="contentPack">The content pack.</param> /// <param name="config">The configuration to save.</param> /// <param name="modHelper">The mod helper through which to save the file.</param> public void Save(ManagedContentPack contentPack, InvariantDictionary <ConfigField> config, IModHelper modHelper) { string configPath = contentPack.GetFullPath(this.Filename); // save if settings valid if (config.Any()) { InvariantDictionary <string> data = new InvariantDictionary <string>(config.ToDictionary(p => p.Key, p => string.Join(", ", p.Value.Value))); modHelper.WriteJsonFile(configPath, data); } // delete if no settings else if (File.Exists(configPath)) { File.Delete(configPath); } }
/// <summary>Save the configuration file for a content pack.</summary> /// <param name="contentPack">The content pack.</param> /// <param name="config">The configuration to save.</param> /// <param name="modHelper">The mod helper through which to save the file.</param> public void Save(ManagedContentPack contentPack, InvariantDictionary <ConfigField> config, IModHelper modHelper) { // save if settings valid if (config.Any()) { InvariantDictionary <string> data = new InvariantDictionary <string>(config.ToDictionary(p => p.Key, p => string.Join(", ", p.Value.Value))); contentPack.WriteJsonFile(this.Filename, data); } // delete if no settings else { FileInfo file = new FileInfo(Path.Combine(contentPack.GetFullPath(this.Filename))); if (file.Exists) { file.Delete(); } } }
/// <summary>Get the local value providers with which to initialize a local context.</summary> /// <param name="contentPack">The content pack for which to get tokens.</param> private IEnumerable <IValueProvider> GetLocalValueProviders(ManagedContentPack contentPack) { yield return(new HasFileValueProvider(contentPack.HasFile)); yield return(new TranslationValueProvider(contentPack.Pack.Translation)); }
/// <summary>Get the local value providers with which to initialize a local context.</summary> /// <param name="contentPack">The content pack for which to get tokens.</param> private IEnumerable <IValueProvider> GetLocalValueProviders(ManagedContentPack contentPack) { yield return(new HasFileValueProvider(contentPack.HasFile)); yield return(new RandomValueProvider()); // per-pack for more reproducible selection when troubleshooting }
/********* ** Public methods *********/ /// <summary>Construct an instance.</summary> /// <param name="contentPack">The managed content pack instance.</param> /// <param name="content">The raw content configuration for this content pack.</param> /// <param name="migrator">The migrations to apply for the content pack version.</param> public RawContentPack(ManagedContentPack contentPack, ContentConfig content, IMigration migrator) { this.ManagedPack = contentPack; this.Content = content; this.Migrator = migrator; }