From d1080a8b2b54c777a446f08d9ecd5b76b4b2561a Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 13 Feb 2017 00:13:29 -0500 Subject: move core JSON logic out of mod helper (#199) This lets SMAPI parse manifest.json files without a mod helper, so we can pass the mod name into the helper. --- src/StardewModdingAPI/Framework/ModHelper.cs | 59 +++++------------ .../Framework/Serialisation/JsonHelper.cs | 73 ++++++++++++++++++++++ src/StardewModdingAPI/Program.cs | 12 ++-- src/StardewModdingAPI/StardewModdingAPI.csproj | 1 + 4 files changed, 96 insertions(+), 49 deletions(-) create mode 100644 src/StardewModdingAPI/Framework/Serialisation/JsonHelper.cs (limited to 'src') diff --git a/src/StardewModdingAPI/Framework/ModHelper.cs b/src/StardewModdingAPI/Framework/ModHelper.cs index 2b562b4f..4a3d5ed5 100644 --- a/src/StardewModdingAPI/Framework/ModHelper.cs +++ b/src/StardewModdingAPI/Framework/ModHelper.cs @@ -1,8 +1,7 @@ using System; using System.IO; -using Newtonsoft.Json; -using StardewModdingAPI.Advanced; using StardewModdingAPI.Framework.Reflection; +using StardewModdingAPI.Framework.Serialisation; namespace StardewModdingAPI.Framework { @@ -12,12 +11,8 @@ namespace StardewModdingAPI.Framework /********* ** Properties *********/ - /// The JSON settings to use when serialising and deserialising files. - private readonly JsonSerializerSettings JsonSettings = new JsonSerializerSettings - { - Formatting = Formatting.Indented, - ObjectCreationHandling = ObjectCreationHandling.Replace // avoid issue where default ICollection values are duplicated each time the config is loaded - }; + /// Encapsulates SMAPI's JSON file parsing. + private readonly JsonHelper JsonHelper; /********* @@ -38,20 +33,24 @@ namespace StardewModdingAPI.Framework *********/ /// Construct an instance. /// The mod directory path. + /// Encapsulate SMAPI's JSON parsing. /// Metadata about loaded mods. - /// An argument is null or invalid. + /// An argument is null or empty. /// The path does not exist on disk. - public ModHelper(string modDirectory, IModRegistry modRegistry) + public ModHelper(string modDirectory, JsonHelper jsonHelper, IModRegistry modRegistry) { // validate - if (modRegistry == null) - throw new ArgumentException("The mod registry cannot be null."); if (string.IsNullOrWhiteSpace(modDirectory)) - throw new ArgumentException("The mod directory cannot be empty."); + throw new ArgumentNullException(nameof(modDirectory)); + if (jsonHelper == null) + throw new ArgumentNullException(nameof(jsonHelper)); + if (modRegistry == null) + throw new ArgumentNullException(nameof(modRegistry)); if (!Directory.Exists(modDirectory)) throw new InvalidOperationException("The specified mod directory does not exist."); // initialise + this.JsonHelper = jsonHelper; this.DirectoryPath = modDirectory; this.ModRegistry = modRegistry; } @@ -88,28 +87,8 @@ namespace StardewModdingAPI.Framework public TModel ReadJsonFile(string path) where TModel : class { - // read file - string fullPath = Path.Combine(this.DirectoryPath, path); - string json; - try - { - json = File.ReadAllText(fullPath); - } - catch (Exception ex) when (ex is DirectoryNotFoundException || ex is FileNotFoundException) - { - return null; - } - - // deserialise model - TModel model = JsonConvert.DeserializeObject(json, this.JsonSettings); - if (model is IConfigFile) - { - var wrapper = (IConfigFile)model; - wrapper.ModHelper = this; - wrapper.FilePath = path; - } - - return model; + path = Path.Combine(this.DirectoryPath, path); + return this.JsonHelper.ReadJsonFile(path, this); } /// Save to a JSON file. @@ -120,15 +99,7 @@ namespace StardewModdingAPI.Framework 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, this.JsonSettings); - File.WriteAllText(path, json); + this.JsonHelper.WriteJsonFile(path, model); } } } diff --git a/src/StardewModdingAPI/Framework/Serialisation/JsonHelper.cs b/src/StardewModdingAPI/Framework/Serialisation/JsonHelper.cs new file mode 100644 index 00000000..3809666f --- /dev/null +++ b/src/StardewModdingAPI/Framework/Serialisation/JsonHelper.cs @@ -0,0 +1,73 @@ +using System; +using System.IO; +using Newtonsoft.Json; +using StardewModdingAPI.Advanced; + +namespace StardewModdingAPI.Framework.Serialisation +{ + /// Encapsulates SMAPI's JSON file parsing. + public class JsonHelper + { + /********* + ** Accessors + *********/ + /// The JSON settings to use when serialising and deserialising files. + private readonly JsonSerializerSettings JsonSettings = new JsonSerializerSettings + { + Formatting = Formatting.Indented, + ObjectCreationHandling = ObjectCreationHandling.Replace // avoid issue where default ICollection values are duplicated each time the config is loaded + }; + + + /********* + ** Public methods + *********/ + /// Read a JSON file. + /// The model type. + /// The absolete file path. + /// The mod helper to inject for instances. + /// Returns the deserialised model, or null if the file doesn't exist or is empty. + public TModel ReadJsonFile(string fullPath, IModHelper modHelper) + where TModel : class + { + // read file + string json; + try + { + json = File.ReadAllText(fullPath); + } + catch (Exception ex) when (ex is DirectoryNotFoundException || ex is FileNotFoundException) + { + return null; + } + + // deserialise model + TModel model = JsonConvert.DeserializeObject(json, this.JsonSettings); + if (model is IConfigFile) + { + var wrapper = (IConfigFile)model; + wrapper.ModHelper = modHelper; + wrapper.FilePath = fullPath; + } + + return model; + } + + /// Save to a JSON file. + /// The model type. + /// The absolete file path. + /// The model to save. + public void WriteJsonFile(string fullPath, TModel model) + where TModel : class + { + // create directory if needed + string dir = Path.GetDirectoryName(fullPath); + if (!Directory.Exists(dir)) + Directory.CreateDirectory(dir); + + // write file + string json = JsonConvert.SerializeObject(model, this.JsonSettings); + File.WriteAllText(fullPath, json); + } + } +} diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index f4518e21..b86e186f 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -15,6 +15,7 @@ using StardewModdingAPI.Events; using StardewModdingAPI.Framework; using StardewModdingAPI.Framework.Logging; using StardewModdingAPI.Framework.Models; +using StardewModdingAPI.Framework.Serialisation; using StardewValley; using Monitor = StardewModdingAPI.Framework.Monitor; @@ -319,6 +320,9 @@ namespace StardewModdingAPI { Program.Monitor.Log("Loading mods..."); + // get JSON helper + JsonHelper jsonHelper = new JsonHelper(); + // get assembly loader AssemblyLoader modAssemblyLoader = new AssemblyLoader(Program.TargetPlatform, Program.Monitor); AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => modAssemblyLoader.ResolveAssembly(e.Name); @@ -353,9 +357,6 @@ namespace StardewModdingAPI return; } - // get helper - IModHelper helper = new ModHelper(directory.FullName, Program.ModRegistry); - // get manifest path string manifestPath = Path.Combine(directory.FullName, "manifest.json"); if (!File.Exists(manifestPath)) @@ -378,7 +379,7 @@ namespace StardewModdingAPI } // deserialise manifest - manifest = helper.ReadJsonFile("manifest.json"); + manifest = jsonHelper.ReadJsonFile(Path.Combine(directory.FullName, "manifest.json"), null); if (manifest == null) { Program.Monitor.Log($"{errorPrefix}: the manifest file does not exist.", LogLevel.Error); @@ -503,8 +504,9 @@ namespace StardewModdingAPI } // inject data + // get helper mod.ModManifest = manifest; - mod.Helper = helper; + mod.Helper = new ModHelper(directory.FullName, jsonHelper, Program.ModRegistry); mod.Monitor = Program.GetSecondaryMonitor(manifest.Name); mod.PathOnDisk = directory.FullName; diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index ae08012d..add6ec40 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -148,6 +148,7 @@ + -- cgit