From 310a72f775bb29b61b0c39f034578503d6225a4b Mon Sep 17 00:00:00 2001 From: Michael Ripley Date: Wed, 6 Apr 2022 23:10:20 -0500 Subject: [PATCH 1/2] Special handling for old serialized enum values --- NeosModLoader/JsonConverters/EnumConverter.cs | 53 +++++++++++++++++++ .../JsonConverters/NeosPrimitiveConverter.cs | 12 +++-- NeosModLoader/ModConfiguration.cs | 1 + NeosModLoader/ModLoader.cs | 2 +- NeosModLoader/Properties/AssemblyInfo.cs | 4 +- 5 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 NeosModLoader/JsonConverters/EnumConverter.cs diff --git a/NeosModLoader/JsonConverters/EnumConverter.cs b/NeosModLoader/JsonConverters/EnumConverter.cs new file mode 100644 index 0000000..32c4ade --- /dev/null +++ b/NeosModLoader/JsonConverters/EnumConverter.cs @@ -0,0 +1,53 @@ +using Newtonsoft.Json; +using System; + +namespace NeosModLoader.JsonConverters +{ + // serializes and deserializes enums as strings + class EnumConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType.IsEnum; + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + // handle old behavior where enums were serialized as underlying type + Type underlyingType = Enum.GetUnderlyingType(objectType); + if (TryConvert(reader.Value, underlyingType, out object deserialized)) + { + Logger.DebugInternal($"Deserializing a BaseX type: {objectType} from a {reader.Value.GetType()}"); + return deserialized; + } + + // handle new behavior where enums are serialized as strings + if (reader.Value is string serialized) + { + return Enum.Parse(objectType, serialized); + } + + throw new ArgumentException($"Could not deserialize a BaseX type: {objectType} from a {reader.Value.GetType()}. Expected underlying type was {underlyingType}"); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + string serialized = Enum.GetName(value.GetType(), value); + writer.WriteValue(serialized); + } + + private bool TryConvert(object value, Type newType, out object converted) + { + try + { + converted = Convert.ChangeType(value, newType); + return true; + } + catch + { + converted = null; + return false; + } + } + } +} diff --git a/NeosModLoader/JsonConverters/NeosPrimitiveConverter.cs b/NeosModLoader/JsonConverters/NeosPrimitiveConverter.cs index ebef15c..590b9af 100644 --- a/NeosModLoader/JsonConverters/NeosPrimitiveConverter.cs +++ b/NeosModLoader/JsonConverters/NeosPrimitiveConverter.cs @@ -11,13 +11,19 @@ class NeosPrimitiveConverter : JsonConverter public override bool CanConvert(Type objectType) { - return BASEX.Equals(objectType.Assembly) && Coder.IsNeosPrimitive(objectType); + // handle all non-enum Neos Primitives in the BaseX assembly + return !objectType.IsEnum && BASEX.Equals(objectType.Assembly) && Coder.IsNeosPrimitive(objectType); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - string serialized = (string)reader.Value; - return typeof(Coder<>).MakeGenericType(objectType).GetMethod("DecodeFromString").Invoke(null, new object[] { serialized }); + if (reader.Value is string serialized) + { + // use Neos's built-in decoding if the value was serialized as a string + return typeof(Coder<>).MakeGenericType(objectType).GetMethod("DecodeFromString").Invoke(null, new object[] { serialized }); + } + + throw new ArgumentException($"Could not deserialize a BaseX type: {objectType} from a {reader.Value.GetType()}"); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) diff --git a/NeosModLoader/ModConfiguration.cs b/NeosModLoader/ModConfiguration.cs index 412feb3..631c018 100644 --- a/NeosModLoader/ModConfiguration.cs +++ b/NeosModLoader/ModConfiguration.cs @@ -172,6 +172,7 @@ private static JsonSerializer createJsonSerializer() Logger.DebugInternal($"Using {defaultConverters.Count()} default json converters"); converters.AddRange(defaultConverters); } + converters.Add(new EnumConverter()); converters.Add(new NeosPrimitiveConverter()); settings.Converters = converters; return JsonSerializer.Create(settings); diff --git a/NeosModLoader/ModLoader.cs b/NeosModLoader/ModLoader.cs index 766f1ab..fadfad8 100644 --- a/NeosModLoader/ModLoader.cs +++ b/NeosModLoader/ModLoader.cs @@ -12,7 +12,7 @@ public class ModLoader /// /// NeosModLoader's version /// - public static readonly string VERSION = "1.9.0"; + public static readonly string VERSION = "1.9.1"; private static readonly Type NEOS_MOD_TYPE = typeof(NeosMod); private static List LoadedMods = new List(); // used for mod enumeration internal static Dictionary AssemblyLookupMap = new Dictionary(); // used for logging diff --git a/NeosModLoader/Properties/AssemblyInfo.cs b/NeosModLoader/Properties/AssemblyInfo.cs index eefb953..b11e3f2 100644 --- a/NeosModLoader/Properties/AssemblyInfo.cs +++ b/NeosModLoader/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.9.0.0")] -[assembly: AssemblyFileVersion("1.9.0.0")] +[assembly: AssemblyVersion("1.9.1.0")] +[assembly: AssemblyFileVersion("1.9.1.0")] From aa8b0655be6d97617eae4c6b39672dfe2db30b3f Mon Sep 17 00:00:00 2001 From: Michael Ripley Date: Wed, 6 Apr 2022 23:58:12 -0500 Subject: [PATCH 2/2] run code cleanup --- NeosModLoader/SplashChanger.cs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/NeosModLoader/SplashChanger.cs b/NeosModLoader/SplashChanger.cs index 7c4ac22..3f2ced6 100644 --- a/NeosModLoader/SplashChanger.cs +++ b/NeosModLoader/SplashChanger.cs @@ -10,22 +10,27 @@ internal static class SplashChanger { private static bool failed = false; // Returned true means success, false means something went wrong. - internal static bool SetCustom(string text) { + internal static bool SetCustom(string text) + { if (ModLoaderConfiguration.Get().HideVisuals) return true; - try { + try + { // VerboseInit does extra logging, so turning it if off while we change the phase. bool ogVerboseInit = Engine.Current.VerboseInit; Engine.Current.VerboseInit = false; Traverse.Create(Engine.Current) - .Method("UpdateInitPhase", new Type[] {typeof(string), typeof(bool)}) + .Method("UpdateInitPhase", new Type[] { typeof(string), typeof(bool) }) .GetValue("~ NeosModLoader ~", false); Traverse.Create(Engine.Current) - .Method("UpdateInitSubphase", new Type[] {typeof(string), typeof(bool)}) + .Method("UpdateInitSubphase", new Type[] { typeof(string), typeof(bool) }) .GetValue(text, false); Engine.Current.VerboseInit = ogVerboseInit; return true; - } catch (Exception ex) { - if (!failed) { + } + catch (Exception ex) + { + if (!failed) + { Logger.WarnInternal("Splash change failed: " + ex.ToString()); failed = true; }