Merge remote-tracking branch 'origin/master' into 1.10

# Conflicts:
#	Source/Engine/Graphics/Materials/MaterialShader.h
This commit is contained in:
Wojtek Figat
2025-02-18 09:19:59 +01:00
133 changed files with 2253 additions and 654 deletions

View File

@@ -1,6 +1,7 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Runtime.CompilerServices;
@@ -23,7 +24,7 @@ namespace FlaxEngine.Json
: base(sb, formatProvider)
{
Encoding = encoding;
}
}
}
partial class JsonSerializer
@@ -174,7 +175,7 @@ namespace FlaxEngine.Json
internal static JsonSerializerSettings CreateDefaultSettings(bool isManagedOnly)
{
//Newtonsoft.Json.Utilities.MiscellaneousUtils.ValueEquals = ValueEquals;
Newtonsoft.Json.Utilities.MiscellaneousUtils.ValueEquals = ValueEquals;
if (SerializationBinder is null)
SerializationBinder = new();
var settings = new JsonSerializerSettings
@@ -234,8 +235,66 @@ namespace FlaxEngine.Json
/// <returns>True if both objects are equal, otherwise false.</returns>
public static bool ValueEquals(object objA, object objB)
{
#if false
// Use default value comparision used by C# json serialization library
return Newtonsoft.Json.Utilities.MiscellaneousUtils.ValueEquals(objA, objB);
#else
// Based on Newtonsoft.Json MiscellaneousUtils.ValueEquals but with customization for prefab object references diff
if (objA == objB)
return true;
if (objA == null || objB == null)
return false;
// 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.HasPrefabLink && sceneB.HasPrefabLink)
return sceneA.PrefabObjectID == sceneB.PrefabObjectID;
// Comparing an Int32 and Int64 both of the same value returns false, make types the same then compare
if (objA.GetType() != objB.GetType())
{
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 (IsInteger(objA) && IsInteger(objB))
return Convert.ToDecimal(objA, CultureInfo.CurrentCulture).Equals(Convert.ToDecimal(objB, CultureInfo.CurrentCulture));
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));
return false;
}
// Diff on collections
if (objA is IList aList && objB is IList bList)
{
if (aList.Count != bList.Count)
return false;
}
if (objA is IEnumerable aEnumerable && objB is IEnumerable bEnumerable)
{
var aEnumerator = aEnumerable.GetEnumerator();
var bEnumerator = bEnumerable.GetEnumerator();
using var aEnumerator1 = aEnumerator as IDisposable;
using var bEnumerator1 = bEnumerator as IDisposable;
while (aEnumerator.MoveNext())
{
if (!bEnumerator.MoveNext() || !ValueEquals(aEnumerator.Current, bEnumerator.Current))
return false;
}
return !bEnumerator.MoveNext();
}
return objA.Equals(objB);
#endif
}
/// <summary>

View File

@@ -41,7 +41,7 @@ void ChangeIds(rapidjson_flax::Value& obj, rapidjson_flax::Document& document, c
'0','0','0','0','0','0','0','0','0','0',
'0','0','0','0','0','0','0','0','0','0',
'0','0'
// @formatter:on
// @formatter:on
};
static const char* digits = "0123456789abcdef";
uint32 n = value.A;

View File

@@ -23,6 +23,7 @@
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ScriptingObjectReference.h"
#include "Engine/Content/Asset.h"
#include "Engine/Level/SceneObject.h"
#include "Engine/Utilities/Encryption.h"
void ISerializable::DeserializeIfExists(DeserializeStream& stream, const char* memberName, ISerializeModifier* modifier)
@@ -789,4 +790,16 @@ void Serialization::Deserialize(ISerializable::DeserializeStream& stream, Matrix
DESERIALIZE_HELPER(stream, "M44", v.M44, 0);
}
bool Serialization::ShouldSerialize(const SceneObject* v, const SceneObject* other)
{
bool result = v != other;
if (result && v && other && v->HasPrefabLink() && other->HasPrefabLink())
{
// 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)
result &= v->GetPrefabObjectID() != other->GetPrefabObjectID();
}
return result;
}
#undef DESERIALIZE_HELPER

View File

@@ -22,6 +22,13 @@ class WeakAssetReference;
template<typename T>
class SoftAssetReference;
// Clang fails to properly resolve TIsBaseOf<SceneObject, T> without SceneObject defined
#ifdef _MSC_VER
class SceneObject;
#else
#include "Engine/Level/SceneObject.h"
#endif
// @formatter:off
namespace Serialization
@@ -441,10 +448,12 @@ namespace Serialization
// Scripting Object
FLAXENGINE_API bool ShouldSerialize(const SceneObject* v, const SceneObject* other);
template<typename T>
inline typename TEnableIf<TIsBaseOf<ScriptingObject, T>::Value, bool>::Type ShouldSerialize(const T*& v, const void* otherObj)
{
return !otherObj || v != *(T**)otherObj;
return !otherObj || v != *(const T**)otherObj;
}
template<typename T>
inline typename TEnableIf<TIsBaseOf<ScriptingObject, T>::Value>::Type Serialize(ISerializable::SerializeStream& stream, const T*& v, const void* otherObj)
@@ -460,12 +469,18 @@ namespace Serialization
v = (T*)::FindObject(id, T::GetStaticClass());
}
template<typename T>
inline typename TEnableIf<TIsBaseOf<SceneObject, T>::Value, bool>::Type ShouldSerialize(const T*& v, const void* otherObj)
{
return !otherObj || ShouldSerialize((const SceneObject*)v, *(const SceneObject**)otherObj);
}
// Scripting Object Reference
template<typename T>
inline bool ShouldSerialize(const ScriptingObjectReference<T>& v, const void* otherObj)
{
return !otherObj || v.Get() != ((ScriptingObjectReference<T>*)otherObj)->Get();
return !otherObj || ShouldSerialize(v.Get(), ((ScriptingObjectReference<T>*)otherObj)->Get());
}
template<typename T>
inline void Serialize(ISerializable::SerializeStream& stream, const ScriptingObjectReference<T>& v, const void* otherObj)
@@ -486,7 +501,7 @@ namespace Serialization
template<typename T>
inline bool ShouldSerialize(const SoftObjectReference<T>& v, const void* otherObj)
{
return !otherObj || v.Get() != ((SoftObjectReference<T>*)otherObj)->Get();
return !otherObj || ShouldSerialize(v.Get(), ((SoftObjectReference<T>*)otherObj)->Get());
}
template<typename T>
inline void Serialize(ISerializable::SerializeStream& stream, const SoftObjectReference<T>& v, const void* otherObj)