summaryrefslogtreecommitdiff
path: root/src/StardewModdingAPI/Config.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/StardewModdingAPI/Config.cs')
-rw-r--r--src/StardewModdingAPI/Config.cs176
1 files changed, 176 insertions, 0 deletions
diff --git a/src/StardewModdingAPI/Config.cs b/src/StardewModdingAPI/Config.cs
new file mode 100644
index 00000000..c5b7beca
--- /dev/null
+++ b/src/StardewModdingAPI/Config.cs
@@ -0,0 +1,176 @@
+/*
+ Copyright 2016 Zoey (Zoryn)
+*/
+
+using System;
+using System.IO;
+using System.Linq;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+namespace StardewModdingAPI
+{
+ public class Config
+ {
+ [JsonIgnore]
+ public virtual string ConfigLocation { get; protected internal set; }
+
+ [JsonIgnore]
+ public virtual string ConfigDir => Path.GetDirectoryName(ConfigLocation);
+
+ public virtual Config Instance<T>() where T : Config => Activator.CreateInstance<T>();
+
+ /// <summary>
+ /// Loads the config from the json blob on disk, updating and re-writing to the disk if needed.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <returns></returns>
+ public virtual T LoadConfig<T>() where T : Config
+ {
+ if (string.IsNullOrEmpty(ConfigLocation))
+ {
+ Log.AsyncR("A config tried to load without specifying a location on the disk.");
+ return null;
+ }
+
+ T ret = null;
+
+ if (!File.Exists(ConfigLocation))
+ {
+ //no config exists, generate default values
+ var c = GenerateDefaultConfig<T>();
+ c.ConfigLocation = ConfigLocation;
+ ret = c;
+ }
+ else
+ {
+ try
+ {
+ //try to load the config from a json blob on disk
+ var c = JsonConvert.DeserializeObject<T>(File.ReadAllText(ConfigLocation), new JsonSerializerSettings {ContractResolver = new JsonResolver()});
+
+ c.ConfigLocation = ConfigLocation;
+
+ //update the config with default values if needed
+ ret = c.UpdateConfig<T>();
+
+ c = null;
+ }
+ catch (Exception ex)
+ {
+ Log.AsyncR($"Invalid JSON ({GetType().Name}): {ConfigLocation} \n{ex}");
+ return GenerateDefaultConfig<T>();
+ }
+ }
+
+ ret.WriteConfig();
+ return ret;
+ }
+
+ /// <summary>
+ /// MUST be implemented in inheriting class!
+ /// </summary>
+ public virtual T GenerateDefaultConfig<T>() where T : Config
+ {
+ return null;
+ }
+
+ /// <summary>
+ /// Merges a default-value config with the user-config on disk.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <returns></returns>
+ public virtual T UpdateConfig<T>() where T : Config
+ {
+ try
+ {
+ //default config
+ var b = JObject.FromObject(Instance<T>().GenerateDefaultConfig<T>(), new JsonSerializer {ContractResolver = new JsonResolver()});
+
+ //user config
+ var u = JObject.FromObject(this, new JsonSerializer {ContractResolver = new JsonResolver()});
+
+ //overwrite default values with user values
+ b.Merge(u, new JsonMergeSettings {MergeArrayHandling = MergeArrayHandling.Replace});
+
+ //cast json object to config
+ var c = b.ToObject<T>();
+
+ //re-write the location on disk to the object
+ c.ConfigLocation = ConfigLocation;
+
+ return c;
+ }
+ catch (Exception ex)
+ {
+ Log.AsyncR("An error occured when updating a config: " + ex);
+ return this as T;
+ }
+ }
+ }
+
+ public static class ConfigExtensions
+ {
+ /// <summary>
+ /// Initializes an instance of any class that inherits from Config.
+ /// This method performs the loading, saving, and merging of the config on the disk and in memory at a default state.
+ /// This method should not be used to re-load or to re-save a config.
+ /// NOTE: You MUST set your config EQUAL to the return of this method!
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="baseConfig"></param>
+ /// <param name="configLocation"></param>
+ /// <returns></returns>
+ public static T InitializeConfig<T>(this T baseConfig, string configLocation) where T : Config
+ {
+ if (baseConfig == null)
+ {
+ baseConfig = Activator.CreateInstance<T>();
+ /*
+ Log.AsyncR("A config tried to initialize whilst being null.");
+ return null;
+ */
+ }
+
+ if (string.IsNullOrEmpty(configLocation))
+ {
+ Log.AsyncR("A config tried to initialize without specifying a location on the disk.");
+ return null;
+ }
+
+ baseConfig.ConfigLocation = configLocation;
+ var c = baseConfig.LoadConfig<T>();
+
+ return c;
+ }
+
+ /// <summary>
+ /// Writes a config to a json blob on the disk specified in the config's properties.
+ /// </summary>
+ public static void WriteConfig<T>(this T baseConfig) where T : Config
+ {
+ if (string.IsNullOrEmpty(baseConfig?.ConfigLocation) || string.IsNullOrEmpty(baseConfig.ConfigDir))
+ {
+ Log.AsyncR("A config attempted to save when it itself or it's location were null.");
+ return;
+ }
+
+ var s = JsonConvert.SerializeObject(baseConfig, typeof(T), Formatting.Indented, new JsonSerializerSettings {ContractResolver = new JsonResolver()});
+
+ if (!Directory.Exists(baseConfig.ConfigDir))
+ Directory.CreateDirectory(baseConfig.ConfigDir);
+
+ if (!File.Exists(baseConfig.ConfigLocation) || !File.ReadAllText(baseConfig.ConfigLocation).SequenceEqual(s))
+ File.WriteAllText(baseConfig.ConfigLocation, s);
+ }
+
+ /// <summary>
+ /// Re-reads the json blob on the disk and merges its values with a default config.
+ /// NOTE: You MUST set your config EQUAL to the return of this method!
+ /// </summary>
+ public static T ReloadConfig<T>(this T baseConfig) where T : Config
+ {
+ return baseConfig.LoadConfig<T>();
+ }
+ }
+} \ No newline at end of file