From f87b6156f4d00403c656a8ccb992b3b579553407 Mon Sep 17 00:00:00 2001 From: Chris <2648373+QuiCM@users.noreply.github.com> Date: Thu, 28 Jan 2021 19:31:09 +1030 Subject: [PATCH] Update config upgrades to be a bit more robust --- TShockAPI/Configuration/TShockConfig.cs | 2 +- TShockAPI/FileTools.cs | 38 ++++++++++++++++--------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/TShockAPI/Configuration/TShockConfig.cs b/TShockAPI/Configuration/TShockConfig.cs index 332b58ba..25b72c31 100644 --- a/TShockAPI/Configuration/TShockConfig.cs +++ b/TShockAPI/Configuration/TShockConfig.cs @@ -600,7 +600,7 @@ namespace TShockAPI.Configuration /// public override TShockSettings ConvertJson(string json, out bool incompleteSettings) { - var settings = FileTools.LoadConfigAndCheckForMissingFields(FileTools.AttemptConfigUpgrade(json), out incompleteSettings); + var settings = FileTools.LoadConfigAndCheckForMissingFields(json, out incompleteSettings); Settings = settings; OnConfigRead?.Invoke(this); diff --git a/TShockAPI/FileTools.cs b/TShockAPI/FileTools.cs index 9c52847b..9c983369 100644 --- a/TShockAPI/FileTools.cs +++ b/TShockAPI/FileTools.cs @@ -172,16 +172,17 @@ namespace TShockAPI return true; } } - + /// /// Looks for a 'Settings' token in the json object. If one is not found, returns a new json object with all tokens of the previous object added /// as children to a root 'Settings' token /// - /// + /// + /// /// - internal static JObject AttemptConfigUpgrade(string json) + internal static JObject AttemptConfigUpgrade(JObject cfg, out bool requiredUpgrade) { - JObject cfg = JObject.Parse(json); + requiredUpgrade = false; if (cfg.SelectToken("Settings") == null) { @@ -190,40 +191,51 @@ namespace TShockAPI { "Settings", cfg } }; cfg = newCfg; + requiredUpgrade = true; } return cfg; } - internal static TSettings LoadConfigAndCheckForMissingFields(string json, out bool anyMissingFields) where TSettings : new() + internal static TSettings LoadConfigAndCheckForMissingFields(string json, out bool writeConfig) where TSettings : new() { - return LoadConfigAndCheckForMissingFields(JObject.Parse(json), out anyMissingFields); + //If an empty file is attempting to be loaded as a config, instead use an empty json object. Otherwise Newtonsoft throws an exception here + if (string.IsNullOrWhiteSpace(json)) + { + json = "{}"; + } + + return LoadConfigAndCheckForMissingFields(JObject.Parse(json), out writeConfig); } /// - /// Parses a JObject into a TSettings object, also emitting a bool indicating if any of the TSetting's fields were missing from the JObject + /// Parses a JObject into a TSettings object, also emitting a bool indicating if the JObject was incomplete /// /// The type of the config file object /// The json object to parse - /// Whether any fields are missing from the config + /// Whether the config needs to be written to disk again /// The config object - internal static TSettings LoadConfigAndCheckForMissingFields(JObject jObject, out bool anyMissingFields) where TSettings : new() + internal static TSettings LoadConfigAndCheckForMissingFields(JObject jObject, out bool writeConfig) where TSettings : new() { - anyMissingFields = false; + JObject cfg = AttemptConfigUpgrade(jObject, out bool requiredUpgrade); var configFields = new HashSet(typeof(TSettings).GetFields() .Where(field => !field.IsStatic) .Select(field => field.Name)); - var jsonFields = new HashSet(jObject.SelectToken("Settings") + var jsonFields = new HashSet(cfg.SelectToken("Settings") .Children() .Select(field => field as JProperty) .Where(field => field != null) .Select(field => field.Name)); - anyMissingFields = !configFields.SetEquals(jsonFields); + bool missingFields = !configFields.SetEquals(jsonFields); - return jObject.SelectToken("Settings").ToObject(); + + //If the config file had to be upgraded or the fields in the given TSettings don't match the config, we'll want the config to be rewritten with the correct data + writeConfig = requiredUpgrade || missingFields; + + return cfg.SelectToken("Settings").ToObject(); } } }