diff --git a/Source/Engine/Serialization/JsonConverters.cs b/Source/Engine/Serialization/JsonConverters.cs
index 4de09cb5d..c194b766e 100644
--- a/Source/Engine/Serialization/JsonConverters.cs
+++ b/Source/Engine/Serialization/JsonConverters.cs
@@ -37,7 +37,11 @@ namespace FlaxEngine.Json
{
// Skip serialization as reference id for the root object serialization (eg. Script)
var cache = JsonSerializer.Current.Value;
+#if !USE_NETCORE
if (cache != null && cache.IsDuringSerialization && cache.SerializerWriter.SerializeStackSize == 0)
+#else
+ if (cache != null && cache.IsDuringSerialization)
+#endif
{
return false;
}
@@ -142,6 +146,7 @@ namespace FlaxEngine.Json
writer.WriteEndObject();
}
+#if !USE_NETCORE
///
public override void WriteJsonDiff(JsonWriter writer, object value, object other, Newtonsoft.Json.JsonSerializer serializer)
{
@@ -170,6 +175,7 @@ namespace FlaxEngine.Json
}
writer.WriteEndObject();
}
+#endif
///
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
@@ -232,8 +238,10 @@ namespace FlaxEngine.Json
///
public override bool CanWrite => true;
+#if !USE_NETCORE
///
public override bool CanWriteDiff => true;
+#endif
}
///
diff --git a/Source/Engine/Serialization/JsonSerializer.cs b/Source/Engine/Serialization/JsonSerializer.cs
index 29a5951f9..b22f92927 100644
--- a/Source/Engine/Serialization/JsonSerializer.cs
+++ b/Source/Engine/Serialization/JsonSerializer.cs
@@ -1,6 +1,7 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
using System;
+using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Runtime.CompilerServices;
@@ -11,7 +12,7 @@ using FlaxEngine.Json.JsonCustomSerializers;
using FlaxEngine.Utilities;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
-using Newtonsoft.Json.Serialization;
+using Newtonsoft.Json.Linq;
namespace FlaxEngine.Json
{
@@ -23,7 +24,11 @@ namespace FlaxEngine.Json
public StringBuilder StringBuilder;
public StringWriter StringWriter;
public JsonTextWriter JsonWriter;
+#if !USE_NETCORE
public JsonSerializerInternalWriter SerializerWriter;
+#else
+ public /*JsonSerializerInternalWriter*/ object SerializerWriter;
+#endif
public UnmanagedMemoryStream MemoryStream;
public StreamReader Reader;
public bool IsDuringSerialization;
@@ -32,9 +37,18 @@ namespace FlaxEngine.Json
{
JsonSerializer = Newtonsoft.Json.JsonSerializer.CreateDefault(settings);
JsonSerializer.Formatting = Formatting.Indented;
+#if USE_NETCORE
+ Type jsonSerializerInternalWriterType =
+ typeof(Newtonsoft.Json.Serialization.IValueProvider).Assembly.GetType(
+ "Newtonsoft.Json.Serialization.JsonSerializerInternalWriter");
+ System.Reflection.ConstructorInfo ctor = jsonSerializerInternalWriterType.GetConstructors
+ (System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public)[0];
+ SerializerWriter = ctor.Invoke(new object[] { JsonSerializer });
+#else
+ SerializerWriter = new JsonSerializerInternalWriter(JsonSerializer);
+#endif
StringBuilder = new StringBuilder(256);
StringWriter = new StringWriter(StringBuilder, CultureInfo.InvariantCulture);
- SerializerWriter = new JsonSerializerInternalWriter(JsonSerializer);
MemoryStream = new UnmanagedMemoryStream((byte*)0, 0);
Reader = new StreamReader(MemoryStream, Encoding.UTF8, false);
JsonWriter = new JsonTextWriter(StringWriter)
@@ -107,7 +121,72 @@ namespace FlaxEngine.Json
return sceneObjA.PrefabObjectID == sceneObjB.PrefabObjectID;
}*/
- return Newtonsoft.Json.Utilities.MiscellaneousUtils.DefaultValueEquals(objA, objB);
+ // Based on Newtonsoft.Json MiscellaneousUtils-class ValueEquals-method
+ bool DefaultValueEquals(object objA_, object objB_)
+ {
+ bool IsInteger(object value)
+ {
+ var type = value.GetType();
+ return type == typeof(SByte) ||
+ type == typeof(Byte) ||
+ type == typeof(Int16) ||
+ type == typeof(UInt16) ||
+ type == typeof(Int32) ||
+ type == typeof(UInt32) ||
+ type == typeof(Int64) ||
+ type == typeof(SByte) ||
+ type == typeof(UInt64);
+ }
+
+ if (objA_ == objB_)
+ {
+ return true;
+ }
+ if (objA_ == null || objB_ == null)
+ {
+ return false;
+ }
+
+ // comparing an Int32 and Int64 both of the same value returns false
+ // make types the same then compare
+ if (objA_.GetType() != objB_.GetType())
+ {
+ if (IsInteger(objA_) && IsInteger(objB_))
+ {
+ return Convert.ToDecimal(objA_, CultureInfo.CurrentCulture).Equals(Convert.ToDecimal(objB_, CultureInfo.CurrentCulture));
+ }
+ else if ((objA_ is double || objA_ is float || objA_ is decimal) && (objB_ is double || objB_ is float || objB_ is decimal))
+ {
+ return Mathd.NearEqual(Convert.ToDouble(objA_, CultureInfo.CurrentCulture), Convert.ToDouble(objB_, CultureInfo.CurrentCulture));
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Diff on collections
+ if (objA_ is System.Collections.IList aList && objB_ is System.Collections.IList bList)
+ {
+ if (aList.Count != bList.Count)
+ return false;
+ }
+ if (objA_ is System.Collections.IEnumerable aEnumerable && objB_ is System.Collections.IEnumerable bEnumerable)
+ {
+ var aEnumerator = aEnumerable.GetEnumerator();
+ var bEnumerator = bEnumerable.GetEnumerator();
+ while (aEnumerator.MoveNext())
+ {
+ if (!bEnumerator.MoveNext() || !ValueEquals(aEnumerator.Current, bEnumerator.Current))
+ return false;
+ }
+ return !bEnumerator.MoveNext();
+ }
+
+ return objA_.Equals(objB_);
+ }
+
+ return /*Newtonsoft.Json.Utilities.MiscellaneousUtils.*/DefaultValueEquals(objA, objB);
}
///
@@ -124,7 +203,17 @@ namespace FlaxEngine.Json
cache.StringBuilder.Clear();
cache.IsDuringSerialization = true;
+#if !USE_NETCORE
cache.SerializerWriter.Serialize(cache.JsonWriter, obj, type);
+#else
+ Type jsonSerializerInternalWriterType =
+ typeof(Newtonsoft.Json.Serialization.IValueProvider).Assembly.GetType(
+ "Newtonsoft.Json.Serialization.JsonSerializerInternalWriter");
+
+ System.Reflection.MethodInfo Serialize = jsonSerializerInternalWriterType.GetMethod("Serialize",
+ System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
+ Serialize.Invoke(cache.SerializerWriter, new object[] { cache.JsonWriter, obj, type });
+#endif
return cache.StringBuilder.ToString();
}
@@ -143,7 +232,17 @@ namespace FlaxEngine.Json
cache.StringBuilder.Clear();
cache.IsDuringSerialization = true;
+#if !USE_NETCORE
cache.SerializerWriter.Serialize(cache.JsonWriter, obj, type);
+#else
+ Type jsonSerializerInternalWriterType =
+ typeof(Newtonsoft.Json.Serialization.IValueProvider).Assembly.GetType(
+ "Newtonsoft.Json.Serialization.JsonSerializerInternalWriter");
+
+ System.Reflection.MethodInfo Serialize = jsonSerializerInternalWriterType.GetMethod("Serialize",
+ System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
+ Serialize.Invoke(cache.SerializerWriter, new object[] { cache.JsonWriter, obj, type });
+#endif
return cache.StringBuilder.ToString();
}
@@ -157,15 +256,25 @@ namespace FlaxEngine.Json
/// The output json string.
public static string SerializeDiff(object obj, object other, bool isManagedOnly = false)
{
- Type type = obj.GetType();
var cache = isManagedOnly ? CacheManagedOnly.Value : Cache.Value;
Current.Value = cache;
cache.StringBuilder.Clear();
cache.IsDuringSerialization = true;
- cache.SerializerWriter.SerializeDiff(cache.JsonWriter, obj, type, other);
- return cache.StringBuilder.ToString();
+ JObject jObj = JObject.FromObject(obj, cache.JsonSerializer);
+ JObject jOther = JObject.FromObject(other, cache.JsonSerializer);
+ JObject diff = new JObject();
+ foreach (KeyValuePair prop in jObj)
+ {
+ JProperty otherProp = jOther.Property(prop.Key);
+ if (JToken.DeepEquals(prop.Value, otherProp.Value))
+ continue;
+
+ diff.Add(prop.Key, prop.Value);
+ }
+
+ return diff.ToString();
}
///
diff --git a/Source/Engine/UI/UIControl.cs b/Source/Engine/UI/UIControl.cs
index bd1d2e795..9b32774ff 100644
--- a/Source/Engine/UI/UIControl.cs
+++ b/Source/Engine/UI/UIControl.cs
@@ -6,7 +6,9 @@ using System.IO;
using System.Text;
using FlaxEngine.GUI;
using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
+using System.Collections.Generic;
namespace FlaxEngine
{
@@ -340,10 +342,22 @@ namespace FlaxEngine
jsonWriter.StringEscapeHandling = jsonSerializer.StringEscapeHandling;
jsonWriter.Culture = jsonSerializer.Culture;
jsonWriter.DateFormatString = jsonSerializer.DateFormatString;
-
+#if !USE_NETCORE
JsonSerializerInternalWriter serializerWriter = new JsonSerializerInternalWriter(jsonSerializer);
serializerWriter.Serialize(jsonWriter, _control, type);
+#else
+ Type jsonSerializerInternalWriterType =
+ typeof(Newtonsoft.Json.Serialization.IValueProvider).Assembly.GetType(
+ "Newtonsoft.Json.Serialization.JsonSerializerInternalWriter");
+ System.Reflection.ConstructorInfo ctor = jsonSerializerInternalWriterType.GetConstructors
+ (System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public)[0];
+ object serializerWriter = ctor.Invoke(new object[] { jsonSerializer });
+
+ System.Reflection.MethodInfo Serialize = jsonSerializerInternalWriterType.GetMethod("Serialize",
+ System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
+ Serialize.Invoke(serializerWriter, new object[] { jsonWriter, _control, type });
+#endif
}
controlType = type.FullName;
@@ -380,10 +394,25 @@ namespace FlaxEngine
jsonWriter.StringEscapeHandling = jsonSerializer.StringEscapeHandling;
jsonWriter.Culture = jsonSerializer.Culture;
jsonWriter.DateFormatString = jsonSerializer.DateFormatString;
-
+#if !USE_NETCORE
JsonSerializerInternalWriter serializerWriter = new JsonSerializerInternalWriter(jsonSerializer);
serializerWriter.SerializeDiff(jsonWriter, _control, type, other._control);
+#else
+ JObject jObj = JObject.FromObject(_control, jsonSerializer);
+ JObject jOther = JObject.FromObject(other._control, jsonSerializer);
+ JObject diff = new JObject();
+ foreach (KeyValuePair prop in jObj)
+ {
+ JProperty otherProp = jOther.Property(prop.Key);
+ if (JToken.DeepEquals(prop.Value, otherProp.Value))
+ continue;
+
+ diff.Add(prop.Key, prop.Value);
+ }
+
+ diff.WriteTo(jsonWriter);
+#endif
}
controlType = string.Empty;