From e092417b9e9093106609a33aba8863c5ec2c5ddd Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 5 Nov 2016 01:46:52 -0400 Subject: add new config system, mark previous methods obsolete (#159) --- src/StardewModdingAPI/Advanced/ConfigFile.cs | 35 +++++++++ src/StardewModdingAPI/Advanced/IConfigFile.cs | 25 +++++++ src/StardewModdingAPI/Config.cs | 9 +++ src/StardewModdingAPI/Mod.cs | 15 ++-- src/StardewModdingAPI/ModHelper.cs | 98 ++++++++++++++++++++++++++ src/StardewModdingAPI/Program.cs | 4 +- src/StardewModdingAPI/StardewModdingAPI.csproj | 3 + 7 files changed, 184 insertions(+), 5 deletions(-) create mode 100644 src/StardewModdingAPI/Advanced/ConfigFile.cs create mode 100644 src/StardewModdingAPI/Advanced/IConfigFile.cs create mode 100644 src/StardewModdingAPI/ModHelper.cs (limited to 'src/StardewModdingAPI') diff --git a/src/StardewModdingAPI/Advanced/ConfigFile.cs b/src/StardewModdingAPI/Advanced/ConfigFile.cs new file mode 100644 index 00000000..000eaf4c --- /dev/null +++ b/src/StardewModdingAPI/Advanced/ConfigFile.cs @@ -0,0 +1,35 @@ +using System.IO; +using Newtonsoft.Json; + +namespace StardewModdingAPI.Advanced +{ + /// Wraps a configuration file with IO methods for convenience. + public abstract class ConfigFile : IConfigFile + { + /********* + ** Accessors + *********/ + /// Provides methods for interacting with the mod directory, including read/writing the config file. + public ModHelper ModHelper { get; set; } + + /// The file path from which the model was loaded, relative to the mod directory. + public string FilePath { get; set; } + + + /********* + ** Public methods + *********/ + /// Reparse the underlying file and update this model. + public void Reload() + { + string json = File.ReadAllText(Path.Combine(this.ModHelper.DirectoryPath, this.FilePath)); + JsonConvert.PopulateObject(json, this); + } + + /// Save this model to the underlying file. + public void Save() + { + this.ModHelper.WriteJsonFile(this.FilePath, this); + } + } +} \ No newline at end of file diff --git a/src/StardewModdingAPI/Advanced/IConfigFile.cs b/src/StardewModdingAPI/Advanced/IConfigFile.cs new file mode 100644 index 00000000..78fd44a6 --- /dev/null +++ b/src/StardewModdingAPI/Advanced/IConfigFile.cs @@ -0,0 +1,25 @@ +namespace StardewModdingAPI.Advanced +{ + /// Wraps a configuration file with IO methods for convenience. + public interface IConfigFile + { + /********* + ** Accessors + *********/ + /// Provides methods for interacting with the mod directory, including read/writing the config file. + ModHelper ModHelper { get; set; } + + /// The file path from which the model was loaded, relative to the mod directory. + string FilePath { get; set; } + + + /********* + ** Methods + *********/ + /// Reparse the underlying file and update this model. + void Reload(); + + /// Save this model to the underlying file. + void Save(); + } +} diff --git a/src/StardewModdingAPI/Config.cs b/src/StardewModdingAPI/Config.cs index ff8ade90..d811d69d 100644 --- a/src/StardewModdingAPI/Config.cs +++ b/src/StardewModdingAPI/Config.cs @@ -7,6 +7,7 @@ using Newtonsoft.Json.Linq; namespace StardewModdingAPI { /// A dynamic configuration class for a mod. + [Obsolete("This base class is obsolete since SMAPI 1.0. See the latest project README for details.")] public abstract class Config { /********* @@ -26,10 +27,12 @@ namespace StardewModdingAPI *********/ /// Construct an instance of the config class. /// The config class type. + [Obsolete("This base class is obsolete since SMAPI 1.0. See the latest project README for details.")] public virtual Config Instance() where T : Config => Activator.CreateInstance(); /// Load the config from the JSON file, saving it to disk if needed. /// The config class type. + [Obsolete("This base class is obsolete since SMAPI 1.0. See the latest project README for details.")] public virtual T LoadConfig() where T : Config { // validate @@ -67,10 +70,12 @@ namespace StardewModdingAPI } /// Get the default config values. + [Obsolete("This base class is obsolete since SMAPI 1.0. See the latest project README for details.")] public abstract T GenerateDefaultConfig() where T : Config; /// Get the current configuration with missing values defaulted. /// The config class type. + [Obsolete("This base class is obsolete since SMAPI 1.0. See the latest project README for details.")] public virtual T UpdateConfig() where T : Config { try @@ -97,12 +102,14 @@ namespace StardewModdingAPI } /// Provides extension methods for classes. + [Obsolete("This base class is obsolete since SMAPI 1.0. See the latest project README for details.")] public static class ConfigExtensions { /// 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! /// The config class type. /// The base configuration to initialise. /// The base configuration file path. + [Obsolete("This base class is obsolete since SMAPI 1.0. See the latest project README for details.")] public static T InitializeConfig(this T baseConfig, string configLocation) where T : Config { if (baseConfig == null) @@ -121,6 +128,7 @@ namespace StardewModdingAPI /// Writes the configuration to the JSON file. /// The config class type. /// The base configuration to initialise. + [Obsolete("This base class is obsolete since SMAPI 1.0. See the latest project README for details.")] public static void WriteConfig(this T baseConfig) where T : Config { if (string.IsNullOrEmpty(baseConfig?.ConfigLocation) || string.IsNullOrEmpty(baseConfig.ConfigDir)) @@ -140,6 +148,7 @@ namespace StardewModdingAPI /// 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! /// The config class type. /// The base configuration to initialise. + [Obsolete("This base class is obsolete since SMAPI 1.0. See the latest project README for details.")] public static T ReloadConfig(this T baseConfig) where T : Config { return baseConfig.LoadConfig(); diff --git a/src/StardewModdingAPI/Mod.cs b/src/StardewModdingAPI/Mod.cs index e8824fc6..c1cc99d4 100644 --- a/src/StardewModdingAPI/Mod.cs +++ b/src/StardewModdingAPI/Mod.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; namespace StardewModdingAPI { @@ -8,6 +9,9 @@ namespace StardewModdingAPI /********* ** Accessors *********/ + /// Provides methods for interacting with the mod directory, such as read/writing a config file or custom JSON files. + public ModHelper Helper { get; internal set; } + /// The mod's manifest. public Manifest Manifest { get; internal set; } @@ -28,9 +32,12 @@ namespace StardewModdingAPI ** Public methods *********/ /// The entry point for your mod. It will always be called once when the mod loads. - public virtual void Entry(params object[] objects) - { - } + [Obsolete("This overload is obsolete since SMAPI 1.0.")] + public virtual void Entry(params object[] objects) { } + + /// The entry point for your mod. It will always be called once when the mod loads. + /// Provides methods for interacting with the mod directory, such as read/writing a config file or custom JSON files. + public virtual void Entry(ModHelper helper) { } /********* diff --git a/src/StardewModdingAPI/ModHelper.cs b/src/StardewModdingAPI/ModHelper.cs new file mode 100644 index 00000000..bb753170 --- /dev/null +++ b/src/StardewModdingAPI/ModHelper.cs @@ -0,0 +1,98 @@ +using System; +using System.IO; +using Newtonsoft.Json; +using StardewModdingAPI.Advanced; + +namespace StardewModdingAPI +{ + /// Provides methods for interacting with a mod directory. + public class ModHelper + { + /********* + ** Accessors + *********/ + /// The mod directory path. + public string DirectoryPath { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The mod directory path. + public ModHelper(string modDirectory) + { + // validate + if (string.IsNullOrWhiteSpace(modDirectory)) + throw new InvalidOperationException("The mod directory cannot be empty."); + if (!Directory.Exists(modDirectory)) + throw new InvalidOperationException("The specified mod directory does not exist."); + + // initialise + this.DirectoryPath = modDirectory; + } + + /**** + ** Mod config file + ****/ + /// Read the mod's configuration file (and create it if needed). + /// The config class type. This should be a plain class that has public properties for the settings you want. These can be complex types. + public TConfig ReadConfig() + where TConfig : class, new() + { + var config = this.ReadJsonFile("config.json") ?? new TConfig(); + this.WriteConfig(config); // create file or fill in missing fields + return config; + } + + /// Save to the mod's configuration file. + /// The config class type. + /// The config settings to save. + public void WriteConfig(TConfig config) + where TConfig : class, new() + { + this.WriteJsonFile("config.json", config); + } + + /**** + ** Generic JSON files + ****/ + /// Read a JSON file. + /// The model type. + /// The file path relative to the mod directory. + public TModel ReadJsonFile(string path) + where TModel : class + { + string fullPath = Path.Combine(this.DirectoryPath, path); + TModel model = JsonConvert.DeserializeObject(File.ReadAllText(fullPath)); + + if (model is IConfigFile) + { + var wrapper = (IConfigFile)model; + wrapper.ModHelper = this; + wrapper.FilePath = path; + } + + return model; + } + + /// Save to a JSON file. + /// The model type. + /// The file path relative to the mod directory. + /// The model to save. + public void WriteJsonFile(string path, TModel model) + where TModel : class + { + path = Path.Combine(this.DirectoryPath, path); + + // create directory if needed + string dir = Path.GetDirectoryName(path); + if (!Directory.Exists(dir)) + Directory.CreateDirectory(dir); + + // write file + string json = JsonConvert.SerializeObject(model, Formatting.Indented); + File.WriteAllText(path, json); + } + } +} diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 8c38a88b..032f1192 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -314,11 +314,13 @@ namespace StardewModdingAPI Mod modEntry = (Mod)modAssembly.CreateInstance(tar.ToString()); if (modEntry != null) { + modEntry.Helper = new ModHelper(targDir); modEntry.PathOnDisk = targDir; modEntry.Manifest = manifest; Log.Info($"Loaded mod: {modEntry.Manifest.Name} by {modEntry.Manifest.Author}, v{modEntry.Manifest.Version} | {modEntry.Manifest.Description}\n@ {targDll}"); Program.ModsLoaded += 1; - modEntry.Entry(); + modEntry.Entry(); // obsolete + modEntry.Entry(modEntry.Helper); } } else diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index 9e89c9e6..451e5961 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -161,6 +161,8 @@ + + @@ -202,6 +204,7 @@ + -- cgit