diff options
Diffstat (limited to 'src/StardewModdingAPI/Config.cs')
-rw-r--r-- | src/StardewModdingAPI/Config.cs | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/src/StardewModdingAPI/Config.cs b/src/StardewModdingAPI/Config.cs new file mode 100644 index 00000000..734c04e8 --- /dev/null +++ b/src/StardewModdingAPI/Config.cs @@ -0,0 +1,188 @@ +#if SMAPI_1_x +using System; +using System.IO; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using StardewModdingAPI.Framework; + +namespace StardewModdingAPI +{ + /// <summary>A dynamic configuration class for a mod.</summary> + [Obsolete("This base class is obsolete since SMAPI 1.0. See the latest project README for details.")] + public abstract class Config + { + /********* + ** Properties + *********/ + /// <summary>Manages deprecation warnings.</summary> + private static DeprecationManager DeprecationManager; + + + /********* + ** Accessors + *********/ + /// <summary>The full path to the configuration file.</summary> + [JsonIgnore] + public virtual string ConfigLocation { get; protected internal set; } + + /// <summary>The directory path containing the configuration file.</summary> + [JsonIgnore] + public virtual string ConfigDir => Path.GetDirectoryName(this.ConfigLocation); + + + /********* + ** Public methods + *********/ + /// <summary>Injects types required for backwards compatibility.</summary> + /// <param name="deprecationManager">Manages deprecation warnings.</param> + internal static void Shim(DeprecationManager deprecationManager) + { + Config.DeprecationManager = deprecationManager; + } + + /// <summary>Construct an instance of the config class.</summary> + /// <typeparam name="T">The config class type.</typeparam> + [Obsolete("This base class is obsolete since SMAPI 1.0. See the latest project README for details.")] + public virtual Config Instance<T>() where T : Config => Activator.CreateInstance<T>(); + + /// <summary>Load the config from the JSON file, saving it to disk if needed.</summary> + /// <typeparam name="T">The config class type.</typeparam> + [Obsolete("This base class is obsolete since SMAPI 1.0. See the latest project README for details.")] + public virtual T LoadConfig<T>() where T : Config + { + // validate + if (string.IsNullOrEmpty(this.ConfigLocation)) + { + Log.Error("A config tried to load without specifying a location on the disk."); + return null; + } + + // read or generate config + T returnValue; + if (!File.Exists(this.ConfigLocation)) + { + T config = this.GenerateDefaultConfig<T>(); + config.ConfigLocation = this.ConfigLocation; + returnValue = config; + } + else + { + try + { + T config = JsonConvert.DeserializeObject<T>(File.ReadAllText(this.ConfigLocation)); + config.ConfigLocation = this.ConfigLocation; + returnValue = config.UpdateConfig<T>(); + } + catch (Exception ex) + { + Log.Error($"Invalid JSON ({this.GetType().Name}): {this.ConfigLocation} \n{ex}"); + return this.GenerateDefaultConfig<T>(); + } + } + + returnValue.WriteConfig(); + return returnValue; + } + + /// <summary>Get the default config values.</summary> + [Obsolete("This base class is obsolete since SMAPI 1.0. See the latest project README for details.")] + public virtual T GenerateDefaultConfig<T>() where T : Config + { + return null; + } + + /// <summary>Get the current configuration with missing values defaulted.</summary> + /// <typeparam name="T">The config class type.</typeparam> + [Obsolete("This base class is obsolete since SMAPI 1.0. See the latest project README for details.")] + public virtual T UpdateConfig<T>() where T : Config + { + try + { + // get default + user config + JObject defaultConfig = JObject.FromObject(this.Instance<T>().GenerateDefaultConfig<T>()); + JObject currentConfig = JObject.FromObject(this); + defaultConfig.Merge(currentConfig, new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Replace }); + + // cast json object to config + T config = defaultConfig.ToObject<T>(); + + // update location + config.ConfigLocation = this.ConfigLocation; + + return config; + } + catch (Exception ex) + { + Log.Error($"An error occured when updating a config: {ex}"); + return this as T; + } + } + + + /********* + ** Protected methods + *********/ + /// <summary>Construct an instance.</summary> + protected Config() + { + Config.DeprecationManager.Warn("the Config class", "1.0", DeprecationLevel.PendingRemoval); + Config.DeprecationManager.MarkWarned($"{nameof(Mod)}.{nameof(Mod.BaseConfigPath)}", "1.0"); // typically used to construct config, avoid redundant warnings + } + } + + /// <summary>Provides extension methods for <see cref="Config"/> classes.</summary> + [Obsolete("This base class is obsolete since SMAPI 1.0. See the latest project README for details.")] + public static class ConfigExtensions + { + /// <summary>Initialise the configuration. That includes loading, saving, and merging the config file and in memory at a default state. This method should not be used to reload or to resave a config. NOTE: You MUST set your config EQUAL to the return of this method!</summary> + /// <typeparam name="T">The config class type.</typeparam> + /// <param name="baseConfig">The base configuration to initialise.</param> + /// <param name="configLocation">The base configuration file path.</param> + [Obsolete("This base class is obsolete since SMAPI 1.0. See the latest project README for details.")] + public static T InitializeConfig<T>(this T baseConfig, string configLocation) where T : Config + { + if (baseConfig == null) + baseConfig = Activator.CreateInstance<T>(); + + if (string.IsNullOrEmpty(configLocation)) + { + Log.Error("A config tried to initialize without specifying a location on the disk."); + return null; + } + + baseConfig.ConfigLocation = configLocation; + return baseConfig.LoadConfig<T>(); + } + + /// <summary>Writes the configuration to the JSON file.</summary> + /// <typeparam name="T">The config class type.</typeparam> + /// <param name="baseConfig">The base configuration to initialise.</param> + [Obsolete("This base class is obsolete since SMAPI 1.0. See the latest project README for details.")] + public static void WriteConfig<T>(this T baseConfig) where T : Config + { + if (string.IsNullOrEmpty(baseConfig?.ConfigLocation) || string.IsNullOrEmpty(baseConfig.ConfigDir)) + { + Log.Error("A config attempted to save when it itself or it's location were null."); + return; + } + + string json = JsonConvert.SerializeObject(baseConfig, Formatting.Indented); + if (!Directory.Exists(baseConfig.ConfigDir)) + Directory.CreateDirectory(baseConfig.ConfigDir); + + if (!File.Exists(baseConfig.ConfigLocation) || !File.ReadAllText(baseConfig.ConfigLocation).SequenceEqual(json)) + File.WriteAllText(baseConfig.ConfigLocation, json); + } + + /// <summary>Rereads the JSON file and merges its values with a default config. NOTE: You MUST set your config EQUAL to the return of this method!</summary> + /// <typeparam name="T">The config class type.</typeparam> + /// <param name="baseConfig">The base configuration to initialise.</param> + [Obsolete("This base class is obsolete since SMAPI 1.0. See the latest project README for details.")] + public static T ReloadConfig<T>(this T baseConfig) where T : Config + { + return baseConfig.LoadConfig<T>(); + } + } +} +#endif
\ No newline at end of file |