diff options
Diffstat (limited to 'src/StardewModdingAPI/Config.cs')
-rw-r--r-- | src/StardewModdingAPI/Config.cs | 176 |
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 |