diff --git a/Source/Engine/Core/Config.h b/Source/Engine/Core/Config.h
index 810217050..95319b885 100644
--- a/Source/Engine/Core/Config.h
+++ b/Source/Engine/Core/Config.h
@@ -57,5 +57,5 @@
#define API_PARAM(...)
#define API_TYPEDEF(...)
#define API_INJECT_CODE(...)
-#define API_AUTO_SERIALIZATION(...) public: void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
+#define API_AUTO_SERIALIZATION(...) public: bool ShouldSerialize(const void* otherObj) const override; void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
#define DECLARE_SCRIPTING_TYPE_MINIMAL(type) public: friend class type##Internal; static struct ScriptingTypeInitializer TypeInitializer;
diff --git a/Source/Engine/Core/ISerializable.h b/Source/Engine/Core/ISerializable.h
index c99051fc0..7500eff8b 100644
--- a/Source/Engine/Core/ISerializable.h
+++ b/Source/Engine/Core/ISerializable.h
@@ -36,6 +36,13 @@ public:
///
virtual ~ISerializable() = default;
+ ///
+ /// Compares with other instance to decide whether serialize this instance (eg. any field orp property is modified). Used to skip object serialization if not needed.
+ ///
+ /// The instance of the object (always valid) to compare with to decide whether serialize this instance.
+ /// True if any field or property is modified compared to the other object instance, otherwise false.
+ virtual bool ShouldSerialize(const void* otherObj) const { return true; }
+
///
/// Serializes object to the output stream compared to the values of the other object instance (eg. default class object). If other object is null then serialize all properties.
///
diff --git a/Source/Engine/Serialization/Serialization.h b/Source/Engine/Serialization/Serialization.h
index d3205ad83..9af6d7be1 100644
--- a/Source/Engine/Serialization/Serialization.h
+++ b/Source/Engine/Serialization/Serialization.h
@@ -415,7 +415,7 @@ namespace Serialization
inline bool ShouldSerialize(const ISerializable& v, const void* otherObj)
{
- return true;
+ return !otherObj || v.ShouldSerialize(otherObj);
}
inline void Serialize(ISerializable::SerializeStream& stream, const ISerializable& v, const void* otherObj)
{
@@ -431,7 +431,7 @@ namespace Serialization
template
inline typename TEnableIf::Value, bool>::Type ShouldSerialize(const ISerializable& v, const void* otherObj)
{
- return true;
+ return !otherObj || v.ShouldSerialize(otherObj);
}
template
inline typename TEnableIf::Value>::Type Serialize(ISerializable::SerializeStream& stream, const ISerializable& v, const void* otherObj)
diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs
index 46f0ec245..3bdb16815 100644
--- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs
+++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs
@@ -1892,13 +1892,13 @@ namespace Flax.Build.Bindings
CppAutoSerializeProperties.Clear();
CppIncludeFiles.Add("Engine/Serialization/Serialization.h");
+ // Serialize
contents.AppendLine();
contents.Append($"void {typeNameNative}::Serialize(SerializeStream& stream, const void* otherObj)").AppendLine();
contents.Append('{').AppendLine();
if (baseType != null)
contents.Append($" {baseType.FullNameNative}::Serialize(stream, otherObj);").AppendLine();
contents.Append($" SERIALIZE_GET_OTHER_OBJ({typeNameNative});").AppendLine();
-
if (classInfo != null)
{
foreach (var fieldInfo in classInfo.Fields)
@@ -1910,7 +1910,6 @@ namespace Flax.Build.Bindings
contents.Append($" SERIALIZE{typeHint}({fieldInfo.Name});").AppendLine();
CppAutoSerializeFields.Add(fieldInfo);
}
-
foreach (var propertyInfo in classInfo.Properties)
{
if (propertyInfo.Getter == null || propertyInfo.Setter == null)
@@ -1952,21 +1951,19 @@ namespace Flax.Build.Bindings
CppAutoSerializeFields.Add(fieldInfo);
}
}
-
contents.Append('}').AppendLine();
+ // Deserialize
contents.AppendLine();
contents.Append($"void {typeNameNative}::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)").AppendLine();
contents.Append('{').AppendLine();
if (baseType != null)
contents.Append($" {baseType.FullNameNative}::Deserialize(stream, modifier);").AppendLine();
-
foreach (var fieldInfo in CppAutoSerializeFields)
{
var typeHint = GenerateCppAutoSerializationDefineType(buildData, contents, moduleInfo, typeInfo, fieldInfo.Type, fieldInfo);
contents.Append($" DESERIALIZE{typeHint}({fieldInfo.Name});").AppendLine();
}
-
foreach (var propertyInfo in CppAutoSerializeProperties)
{
contents.AppendLine(" {");
@@ -1978,7 +1975,43 @@ namespace Flax.Build.Bindings
contents.AppendLine(" }");
contents.AppendLine(" }");
}
+ contents.Append('}').AppendLine();
+ // ShouldSerialize
+ contents.AppendLine();
+ contents.Append($"bool {typeNameNative}::ShouldSerialize(const void* otherObj) const").AppendLine();
+ contents.Append('{').AppendLine();
+ if (!typeInfo.IsScriptingObject)
+ {
+ contents.Append($" SERIALIZE_GET_OTHER_OBJ({typeNameNative});").AppendLine();
+ contents.AppendLine(" bool result = false;");
+ if (baseType != null)
+ contents.Append($" result |= {baseType.FullNameNative}::ShouldSerialize(otherObj);").AppendLine();
+ foreach (var fieldInfo in CppAutoSerializeFields)
+ {
+ contents.Append($" result |= Serialization::ShouldSerialize({fieldInfo.Name}, &other->{fieldInfo.Name});").AppendLine();
+ }
+ foreach (var propertyInfo in CppAutoSerializeProperties)
+ {
+ contents.Append(" {");
+ contents.Append(" const auto");
+ if (propertyInfo.Getter.ReturnType.IsConstRef)
+ contents.Append('&');
+ contents.Append($" value = {propertyInfo.Getter.Name}();");
+ contents.Append(" const auto");
+ if (propertyInfo.Getter.ReturnType.IsConstRef)
+ contents.Append('&');
+ contents.Append($" otherValue = other->{propertyInfo.Getter.Name}();");
+ contents.Append(" result |= Serialization::ShouldSerialize(value, &otherValue);").AppendLine();
+ contents.Append('}').AppendLine();
+ }
+ contents.AppendLine(" return result;");
+ }
+ else
+ {
+ // Not needed to generate
+ contents.AppendLine(" return true;");
+ }
contents.Append('}').AppendLine();
}