diff --git a/Source/Engine/Core/Math/Color.cs b/Source/Engine/Core/Math/Color.cs index 711ffb7d9..dbfd70c7e 100644 --- a/Source/Engine/Core/Math/Color.cs +++ b/Source/Engine/Core/Math/Color.cs @@ -11,7 +11,7 @@ namespace FlaxEngine #if FLAX_EDITOR [System.ComponentModel.TypeConverter(typeof(TypeConverters.ColorConverter))] #endif - partial struct Color + partial struct Color : Json.ICustomValueEquals { /// /// The size of the type, in bytes. @@ -201,6 +201,13 @@ namespace FlaxEngine A = values[3]; } + /// + public bool ValueEquals(object other) + { + var o = (Color)other; + return Equals(ref o); + } + /// public override bool Equals(object value) { diff --git a/Source/Engine/Core/Math/Double2.cs b/Source/Engine/Core/Math/Double2.cs index 9594b22cb..51fcf32d5 100644 --- a/Source/Engine/Core/Math/Double2.cs +++ b/Source/Engine/Core/Math/Double2.cs @@ -65,7 +65,7 @@ namespace FlaxEngine #if FLAX_EDITOR [System.ComponentModel.TypeConverter(typeof(TypeConverters.Double2Converter))] #endif - partial struct Double2 : IEquatable, IFormattable + partial struct Double2 : IEquatable, IFormattable, Json.ICustomValueEquals { private static readonly string _formatString = "X:{0:F2} Y:{1:F2}"; @@ -1574,6 +1574,13 @@ namespace FlaxEngine } } + /// + public bool ValueEquals(object other) + { + var o = (Double2)other; + return Equals(ref o); + } + /// /// Determines whether the specified is equal to this instance. /// diff --git a/Source/Engine/Core/Math/Double3.cs b/Source/Engine/Core/Math/Double3.cs index cb26cf071..4dccc1fb3 100644 --- a/Source/Engine/Core/Math/Double3.cs +++ b/Source/Engine/Core/Math/Double3.cs @@ -66,7 +66,7 @@ namespace FlaxEngine #if FLAX_EDITOR [System.ComponentModel.TypeConverter(typeof(TypeConverters.Double3Converter))] #endif - partial struct Double3 : IEquatable, IFormattable + partial struct Double3 : IEquatable, IFormattable, Json.ICustomValueEquals { private static readonly string _formatString = "X:{0:F2} Y:{1:F2} Z:{2:F2}"; @@ -1872,6 +1872,13 @@ namespace FlaxEngine } } + /// + public bool ValueEquals(object other) + { + var o = (Double3)other; + return Equals(ref o); + } + /// /// Determines whether the specified is equal to this instance. /// diff --git a/Source/Engine/Core/Math/Double4.cs b/Source/Engine/Core/Math/Double4.cs index 70d27cb28..bf176e6ff 100644 --- a/Source/Engine/Core/Math/Double4.cs +++ b/Source/Engine/Core/Math/Double4.cs @@ -66,7 +66,7 @@ namespace FlaxEngine #if FLAX_EDITOR [System.ComponentModel.TypeConverter(typeof(TypeConverters.Double4Converter))] #endif - partial struct Double4 : IEquatable, IFormattable + partial struct Double4 : IEquatable, IFormattable, Json.ICustomValueEquals { private static readonly string _formatString = "X:{0:F2} Y:{1:F2} Z:{2:F2} W:{3:F2}"; @@ -1372,6 +1372,13 @@ namespace FlaxEngine } } + /// + public bool ValueEquals(object other) + { + var o = (Double4)other; + return Equals(ref o); + } + /// /// Determines whether the specified is equal to this instance. /// diff --git a/Source/Engine/Core/Math/Float2.cs b/Source/Engine/Core/Math/Float2.cs index 1b70dd0a6..5bb81ec3a 100644 --- a/Source/Engine/Core/Math/Float2.cs +++ b/Source/Engine/Core/Math/Float2.cs @@ -60,7 +60,7 @@ namespace FlaxEngine #if FLAX_EDITOR [System.ComponentModel.TypeConverter(typeof(TypeConverters.Float2Converter))] #endif - partial struct Float2 : IEquatable, IFormattable + partial struct Float2 : IEquatable, IFormattable, Json.ICustomValueEquals { private static readonly string _formatString = "X:{0:F2} Y:{1:F2}"; @@ -1650,6 +1650,13 @@ namespace FlaxEngine } } + /// + public bool ValueEquals(object other) + { + var o = (Float2)other; + return Equals(ref o); + } + /// /// Determines whether the specified is equal to this instance. /// diff --git a/Source/Engine/Core/Math/Float3.cs b/Source/Engine/Core/Math/Float3.cs index 5e8dceed6..50554345b 100644 --- a/Source/Engine/Core/Math/Float3.cs +++ b/Source/Engine/Core/Math/Float3.cs @@ -60,7 +60,7 @@ namespace FlaxEngine #if FLAX_EDITOR [System.ComponentModel.TypeConverter(typeof(TypeConverters.Float3Converter))] #endif - partial struct Float3 : IEquatable, IFormattable + partial struct Float3 : IEquatable, IFormattable, Json.ICustomValueEquals { private static readonly string _formatString = "X:{0:F2} Y:{1:F2} Z:{2:F2}"; @@ -1904,6 +1904,13 @@ namespace FlaxEngine } } + /// + public bool ValueEquals(object other) + { + var o = (Float3)other; + return Equals(ref o); + } + /// /// Determines whether the specified is equal to this instance. /// diff --git a/Source/Engine/Core/Math/Float4.cs b/Source/Engine/Core/Math/Float4.cs index b6eb6dd9e..26abf4b2e 100644 --- a/Source/Engine/Core/Math/Float4.cs +++ b/Source/Engine/Core/Math/Float4.cs @@ -60,7 +60,7 @@ namespace FlaxEngine #if FLAX_EDITOR [System.ComponentModel.TypeConverter(typeof(TypeConverters.Float4Converter))] #endif - partial struct Float4 : IEquatable, IFormattable + partial struct Float4 : IEquatable, IFormattable, Json.ICustomValueEquals { private static readonly string _formatString = "X:{0:F2} Y:{1:F2} Z:{2:F2} W:{3:F2}"; @@ -1412,6 +1412,13 @@ namespace FlaxEngine } } + /// + public bool ValueEquals(object other) + { + var o = (Float4)other; + return Equals(ref o); + } + /// /// Determines whether the specified is equal to this instance. /// diff --git a/Source/Engine/Core/Math/Int2.cs b/Source/Engine/Core/Math/Int2.cs index 4a4107252..32a273307 100644 --- a/Source/Engine/Core/Math/Int2.cs +++ b/Source/Engine/Core/Math/Int2.cs @@ -14,7 +14,7 @@ namespace FlaxEngine #if FLAX_EDITOR [System.ComponentModel.TypeConverter(typeof(TypeConverters.Int2Converter))] #endif - partial struct Int2 : IEquatable, IFormattable + partial struct Int2 : IEquatable, IFormattable, Json.ICustomValueEquals { private static readonly string _formatString = "X:{0} Y:{1}"; @@ -940,6 +940,13 @@ namespace FlaxEngine } } + /// + public bool ValueEquals(object other) + { + var o = (Int2)other; + return Equals(ref o); + } + /// /// Determines whether the specified is equal to this instance. /// diff --git a/Source/Engine/Core/Math/Int3.cs b/Source/Engine/Core/Math/Int3.cs index 78e4600c3..81bb8026e 100644 --- a/Source/Engine/Core/Math/Int3.cs +++ b/Source/Engine/Core/Math/Int3.cs @@ -14,7 +14,7 @@ namespace FlaxEngine #if FLAX_EDITOR [System.ComponentModel.TypeConverter(typeof(TypeConverters.Int3Converter))] #endif - partial struct Int3 : IEquatable, IFormattable + partial struct Int3 : IEquatable, IFormattable, Json.ICustomValueEquals { private static readonly string _formatString = "X:{0} Y:{1} Z:{2}"; @@ -1023,6 +1023,13 @@ namespace FlaxEngine } } + /// + public bool ValueEquals(object other) + { + var o = (Int3)other; + return Equals(ref o); + } + /// /// Determines whether the specified is equal to this instance. /// diff --git a/Source/Engine/Core/Math/Int4.cs b/Source/Engine/Core/Math/Int4.cs index e180ccb31..bbccadab4 100644 --- a/Source/Engine/Core/Math/Int4.cs +++ b/Source/Engine/Core/Math/Int4.cs @@ -14,7 +14,7 @@ namespace FlaxEngine #if FLAX_EDITOR [System.ComponentModel.TypeConverter(typeof(TypeConverters.Int4Converter))] #endif - partial struct Int4 : IEquatable, IFormattable + partial struct Int4 : IEquatable, IFormattable, Json.ICustomValueEquals { private static readonly string _formatString = "X:{0} Y:{1} Z:{2} W:{3}"; @@ -881,6 +881,13 @@ namespace FlaxEngine } } + /// + public bool ValueEquals(object other) + { + var o = (Int4)other; + return Equals(ref o); + } + /// /// Determines whether the specified is equal to this instance. /// diff --git a/Source/Engine/Core/Math/Quaternion.cs b/Source/Engine/Core/Math/Quaternion.cs index d89b71488..cf51fac50 100644 --- a/Source/Engine/Core/Math/Quaternion.cs +++ b/Source/Engine/Core/Math/Quaternion.cs @@ -60,7 +60,7 @@ namespace FlaxEngine #if FLAX_EDITOR [System.ComponentModel.TypeConverter(typeof(TypeConverters.QuaternionConverter))] #endif - partial struct Quaternion : IEquatable, IFormattable + partial struct Quaternion : IEquatable, IFormattable, Json.ICustomValueEquals { private static readonly string _formatString = "X:{0:F2} Y:{1:F2} Z:{2:F2} W:{3:F2}"; @@ -1681,6 +1681,13 @@ namespace FlaxEngine } } + /// + public bool ValueEquals(object other) + { + var o = (Quaternion)other; + return Equals(ref o); + } + /// /// Tests whether one quaternion is near another quaternion. /// diff --git a/Source/Engine/Core/Math/Rectangle.cs b/Source/Engine/Core/Math/Rectangle.cs index 81c689d48..8e3c2b6c4 100644 --- a/Source/Engine/Core/Math/Rectangle.cs +++ b/Source/Engine/Core/Math/Rectangle.cs @@ -6,7 +6,7 @@ using System.Runtime.CompilerServices; namespace FlaxEngine { - partial struct Rectangle : IEquatable + partial struct Rectangle : IEquatable, Json.ICustomValueEquals { /// /// A which represents an empty space. @@ -523,6 +523,13 @@ namespace FlaxEngine } } + /// + public bool ValueEquals(object other) + { + var o = (Rectangle)other; + return Equals(ref o); + } + /// public override string ToString() { diff --git a/Source/Engine/Core/Math/Transform.cs b/Source/Engine/Core/Math/Transform.cs index fc16a501b..90c0c36c9 100644 --- a/Source/Engine/Core/Math/Transform.cs +++ b/Source/Engine/Core/Math/Transform.cs @@ -16,7 +16,7 @@ using System.Runtime.InteropServices; namespace FlaxEngine { [Serializable] - partial struct Transform : IEquatable, IFormattable + partial struct Transform : IEquatable, IFormattable, Json.ICustomValueEquals { private static readonly string _formatString = "Translation:{0} Orientation:{1} Scale:{2}"; @@ -673,6 +673,13 @@ namespace FlaxEngine } } + /// + public bool ValueEquals(object other) + { + var o = (Transform)other; + return Equals(ref o); + } + /// /// Tests whether one transform is near another transform. /// diff --git a/Source/Engine/Core/Math/Vector2.cs b/Source/Engine/Core/Math/Vector2.cs index 8e1599513..3f63c4e9c 100644 --- a/Source/Engine/Core/Math/Vector2.cs +++ b/Source/Engine/Core/Math/Vector2.cs @@ -73,7 +73,7 @@ namespace FlaxEngine #if FLAX_EDITOR [System.ComponentModel.TypeConverter(typeof(TypeConverters.Vector2Converter))] #endif - public unsafe partial struct Vector2 : IEquatable, IFormattable + public unsafe partial struct Vector2 : IEquatable, IFormattable, Json.ICustomValueEquals { private static readonly string _formatString = "X:{0:F2} Y:{1:F2}"; @@ -1774,6 +1774,13 @@ namespace FlaxEngine } } + /// + public bool ValueEquals(object other) + { + var o = (Vector2)other; + return Equals(ref o); + } + /// /// Determines whether the specified is equal to this instance. /// diff --git a/Source/Engine/Core/Math/Vector3.cs b/Source/Engine/Core/Math/Vector3.cs index 5e01a7a6c..388317810 100644 --- a/Source/Engine/Core/Math/Vector3.cs +++ b/Source/Engine/Core/Math/Vector3.cs @@ -73,7 +73,7 @@ namespace FlaxEngine #if FLAX_EDITOR [System.ComponentModel.TypeConverter(typeof(TypeConverters.Vector3Converter))] #endif - public unsafe partial struct Vector3 : IEquatable, IFormattable + public unsafe partial struct Vector3 : IEquatable, IFormattable, Json.ICustomValueEquals { private static readonly string _formatString = "X:{0:F2} Y:{1:F2} Z:{2:F2}"; @@ -2133,6 +2133,13 @@ namespace FlaxEngine } } + /// + public bool ValueEquals(object other) + { + var o = (Vector3)other; + return Equals(ref o); + } + /// /// Determines whether the specified is equal to this instance. /// diff --git a/Source/Engine/Core/Math/Vector4.cs b/Source/Engine/Core/Math/Vector4.cs index 909e35157..776bbd3dc 100644 --- a/Source/Engine/Core/Math/Vector4.cs +++ b/Source/Engine/Core/Math/Vector4.cs @@ -72,7 +72,7 @@ namespace FlaxEngine #if FLAX_EDITOR [System.ComponentModel.TypeConverter(typeof(TypeConverters.Vector4Converter))] #endif - public partial struct Vector4 : IEquatable, IFormattable + public partial struct Vector4 : IEquatable, IFormattable, Json.ICustomValueEquals { private static readonly string _formatString = "X:{0:F2} Y:{1:F2} Z:{2:F2} W:{3:F2}"; @@ -1499,6 +1499,13 @@ namespace FlaxEngine } } + /// + public bool ValueEquals(object other) + { + var o = (Vector4)other; + return Equals(ref o); + } + /// /// Determines whether the specified is equal to this instance. /// diff --git a/Source/Engine/Graphics/Models/CollisionProxy.h b/Source/Engine/Graphics/Models/CollisionProxy.h index eba17cf4e..2ecdce756 100644 --- a/Source/Engine/Graphics/Models/CollisionProxy.h +++ b/Source/Engine/Graphics/Models/CollisionProxy.h @@ -6,7 +6,7 @@ #include "Engine/Core/Math/Transform.h" #include "Engine/Core/Math/Ray.h" #include "Engine/Core/Math/CollisionsHelper.h" -#include "Engine/Core/Math/Packed.h" +#include "Engine/Core/Math/Half.h" #include "Engine/Core/Collections/Array.h" #include "Engine/Graphics/PixelFormat.h" @@ -58,7 +58,7 @@ public: else if (positionsFormat == PixelFormat::R16G16B16A16_Float) { LOOP_BEGIN() -#define GET_POS(idx) (Float3)*(const Half4*)((const byte*)positions + positionsStride * idx) +#define GET_POS(idx) ((const Half4*)((const byte*)positions + positionsStride * idx))->ToFloat3() Triangles.Add({ GET_POS(i0), GET_POS(i1), GET_POS(i2) }); #undef GET_POS LOOP_END() diff --git a/Source/Engine/Level/MeshReference.cs b/Source/Engine/Level/MeshReference.cs index 14ef0c72b..cb87e9769 100644 --- a/Source/Engine/Level/MeshReference.cs +++ b/Source/Engine/Level/MeshReference.cs @@ -13,7 +13,7 @@ namespace FlaxEngine public bool ValueEquals(object other) { var o = (MeshReference)other; - return JsonSerializer.ValueEquals(Actor, o.Actor) && + return JsonSerializer.SceneObjectEquals(Actor, o.Actor) && LODIndex == o.LODIndex && MeshIndex == o.MeshIndex; } diff --git a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp index 0bed02f0b..378b706ed 100644 --- a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp +++ b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp @@ -227,9 +227,9 @@ public: void PrefabInstanceData::CollectPrefabInstances(PrefabInstancesData& prefabInstancesData, const Guid& prefabId, Actor* defaultInstance, Actor* targetActor) { ScopeLock lock(PrefabManager::PrefabsReferencesLocker); - if (PrefabManager::PrefabsReferences.ContainsKey(prefabId)) + if (auto instancesPtr = PrefabManager::PrefabsReferences.TryGet(prefabId)) { - auto& instances = PrefabManager::PrefabsReferences[prefabId]; + auto& instances = *instancesPtr; int32 usedCount = 0; for (int32 instanceIndex = 0; instanceIndex < instances.Count(); instanceIndex++) { diff --git a/Source/Engine/Serialization/JsonSerializer.cs b/Source/Engine/Serialization/JsonSerializer.cs index 4321ffa36..86e4ead8b 100644 --- a/Source/Engine/Serialization/JsonSerializer.cs +++ b/Source/Engine/Serialization/JsonSerializer.cs @@ -270,8 +270,8 @@ namespace FlaxEngine.Json // Special case when saving reference to prefab object and the objects are different but the point to the same prefab object // In that case, skip saving reference as it's defined in prefab (will be populated via IdsMapping during deserialization) - if (objA is SceneObject sceneA && objB is SceneObject sceneB && sceneA && sceneB && sceneA.HasPrefabLink && sceneB.HasPrefabLink) - return sceneA.PrefabObjectID == sceneB.PrefabObjectID; + if (objA is SceneObject sceneObjA && objB is SceneObject sceneObjB && sceneObjA && sceneObjB && sceneObjA.HasPrefabLink && sceneObjB.HasPrefabLink) + return sceneObjA.PrefabObjectID == sceneObjB.PrefabObjectID; // Comparing an Int32 and Int64 both of the same value returns false, make types the same then compare if (objA.GetType() != objB.GetType()) @@ -286,7 +286,6 @@ namespace FlaxEngine.Json type == typeof(Int32) || type == typeof(UInt32) || type == typeof(Int64) || - type == typeof(SByte) || type == typeof(UInt64); } if (IsInteger(objA) && IsInteger(objB)) @@ -301,6 +300,12 @@ namespace FlaxEngine.Json { if (aList.Count != bList.Count) return false; + for (int i = 0; i < aList.Count; i++) + { + if (!ValueEquals(aList[i], bList[i])) + return false; + } + return true; } if (objA is IEnumerable aEnumerable && objB is IEnumerable bEnumerable) { @@ -316,8 +321,29 @@ namespace FlaxEngine.Json return !bEnumerator.MoveNext(); } - if (objA is ICustomValueEquals customValueEquals && objA.GetType() == objB.GetType()) + // Custom comparer + if (objA is ICustomValueEquals customValueEquals) return customValueEquals.ValueEquals(objB); + + // If type contains SceneObject references then it needs to use custom comparision that handles prefab links (see SceneObjectEquals) + if (objA.GetType().IsStructure()) + { + var contract = Settings.ContractResolver.ResolveContract(objA.GetType()); + if (contract is JsonObjectContract objContract) + { + foreach (var property in objContract.Properties) + { + var valueProvider = property.ValueProvider; + var propA = valueProvider.GetValue(objA); + var propB = valueProvider.GetValue(objB); + if (!ValueEquals(propA, propB)) + return false; + } + return true; + } + } + + // Generic fallback return objA.Equals(objB); #endif }