From 90f519a1c64880dbd69b0a5d31d89eab1c4ec36b Mon Sep 17 00:00:00 2001 From: ZakFahey Date: Sat, 1 Aug 2020 10:13:04 -0700 Subject: [PATCH] Overwrite the config if any new fields are missing --- TShockAPI/ConfigFile.cs | 24 +++++++--- TShockAPI/DB/GroupManager.cs | 7 ++- TShockAPI/FileTools.cs | 46 ++++++++++++++++--- .../ServerSideCharacters/ServerSideConfig.cs | 13 +++++- 4 files changed, 72 insertions(+), 18 deletions(-) diff --git a/TShockAPI/ConfigFile.cs b/TShockAPI/ConfigFile.cs index acfeb61a..b65c5402 100644 --- a/TShockAPI/ConfigFile.cs +++ b/TShockAPI/ConfigFile.cs @@ -602,14 +602,21 @@ namespace TShockAPI /// Reads a configuration file from a given path /// /// string path - /// ConfigFile object - public static ConfigFile Read(string path) + /// The path to the config file + /// + /// Whether the config object has any new files in it, meaning that the config file has to be + /// overwritten. + /// + public static ConfigFile Read(string path, out bool anyMissingFields) { if (!File.Exists(path)) + { + anyMissingFields = true; return new ConfigFile(); + } using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { - return Read(fs); + return Read(fs, out anyMissingFields); } } @@ -617,14 +624,17 @@ namespace TShockAPI /// Reads the configuration file from a stream /// /// stream + /// + /// Whether the config object has any new fields in it, meaning that the config file has to be + /// overwritten. + /// /// ConfigFile object - public static ConfigFile Read(Stream stream) + public static ConfigFile Read(Stream stream, out bool anyMissingFields) { using (var sr = new StreamReader(stream)) { - var cf = JsonConvert.DeserializeObject(sr.ReadToEnd()); - if (ConfigRead != null) - ConfigRead(cf); + var cf = FileTools.LoadConfigAndCheckForMissingFields(sr.ReadToEnd(), out anyMissingFields); + ConfigRead?.Invoke(cf); return cf; } } diff --git a/TShockAPI/DB/GroupManager.cs b/TShockAPI/DB/GroupManager.cs index ceb8e433..eae7df43 100644 --- a/TShockAPI/DB/GroupManager.cs +++ b/TShockAPI/DB/GroupManager.cs @@ -389,7 +389,7 @@ namespace TShockAPI.DB } // Read the config file to prevent the possible loss of any unsaved changes - TShock.Config = ConfigFile.Read(FileTools.ConfigPath); + TShock.Config = ConfigFile.Read(FileTools.ConfigPath, out bool writeConfig); if (TShock.Config.DefaultGuestGroupName == oldGroup.Name) { TShock.Config.DefaultGuestGroupName = newGroup.Name; @@ -399,7 +399,10 @@ namespace TShockAPI.DB { TShock.Config.DefaultRegistrationGroupName = newGroup.Name; } - TShock.Config.Write(FileTools.ConfigPath); + if (writeConfig) + { + TShock.Config.Write(FileTools.ConfigPath); + } // We also need to check if any users belong to the old group and automatically apply changes using (var command = db.CreateCommand()) diff --git a/TShockAPI/FileTools.cs b/TShockAPI/FileTools.cs index 314c7c5a..7b421213 100644 --- a/TShockAPI/FileTools.cs +++ b/TShockAPI/FileTools.cs @@ -16,9 +16,13 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; +using System.Linq; using TShockAPI.ServerSideCharacters; namespace TShockAPI @@ -103,23 +107,26 @@ namespace TShockAPI CreateIfNot(MotdPath, MotdFormat); CreateIfNot(WhitelistPath); + bool writeConfig = true; // Default to true if the file doesn't exist if (File.Exists(ConfigPath)) { - TShock.Config = ConfigFile.Read(ConfigPath); - // Add all the missing config properties in the json file + TShock.Config = ConfigFile.Read(ConfigPath, out writeConfig); } - else + if (writeConfig) { + // Add all the missing config properties in the json file TShock.Config.Write(ConfigPath); } + bool writeSSCConfig = true; // Default to true if the file doesn't exist if (File.Exists(ServerSideCharacterConfigPath)) { - TShock.ServerSideCharacterConfig = ServerSideConfig.Read(ServerSideCharacterConfigPath); - // Add all the missing config properties in the json file + TShock.ServerSideCharacterConfig = + ServerSideConfig.Read(ServerSideCharacterConfigPath, out writeSSCConfig); } - else + if (writeSSCConfig) { + // Add all the missing config properties in the json file TShock.ServerSideCharacterConfig = new ServerSideConfig { StartingInventory = @@ -166,5 +173,30 @@ namespace TShockAPI return true; } } + + /// + /// Parse some json text and also return whether any fields are missing from the json + /// + /// The type of the config file object + /// The json text to parse + /// Whether any fields are missing from the config + /// The config object + internal static T LoadConfigAndCheckForMissingFields(string json, out bool anyMissingFields) + { + JObject jObject = JObject.Parse(json); + + anyMissingFields = false; + var configFields = new HashSet(typeof(T).GetFields() + .Where(field => !field.IsStatic) + .Select(field => field.Name)); + var jsonFields = new HashSet(jObject + .Children() + .Select(field => field as JProperty) + .Where(field => field != null) + .Select(field => field.Name)); + anyMissingFields = !configFields.SetEquals(jsonFields); + + return jObject.ToObject(); + } } -} \ No newline at end of file +} diff --git a/TShockAPI/ServerSideCharacters/ServerSideConfig.cs b/TShockAPI/ServerSideCharacters/ServerSideConfig.cs index b1c6f6da..701dce11 100644 --- a/TShockAPI/ServerSideCharacters/ServerSideConfig.cs +++ b/TShockAPI/ServerSideCharacters/ServerSideConfig.cs @@ -46,13 +46,22 @@ namespace TShockAPI.ServerSideCharacters [Description("The starting default inventory for new SSC.")] public List StartingInventory = new List(); - public static ServerSideConfig Read(string path) + /// + /// Reads a server-side configuration file from a given path + /// + /// The path to the config file + /// + /// Whether the config object has any new fields in it, meaning that the config file has to be + /// overwritten. + /// + /// ConfigFile object + public static ServerSideConfig Read(string path, out bool anyMissingFields) { using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) using (var reader = new StreamReader(fileStream)) { string txt = reader.ReadToEnd(); - var config = JsonConvert.DeserializeObject(txt); + var config = FileTools.LoadConfigAndCheckForMissingFields(txt, out anyMissingFields); return config; } }