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(); }