// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. #pragma once #include "SerializationFwd.h" #include "ISerializeModifier.h" #include "Engine/Core/Collections/Array.h" #include "Engine/Core/Collections/Dictionary.h" #include "Engine/Scripting/ScriptingObject.h" #include "Engine/Utilities/Encryption.h" struct Version; struct VariantType; template class ScriptingObjectReference; template class SoftObjectReference; template class AssetReference; template class WeakAssetReference; template class SoftAssetReference; // @formatter:off namespace Serialization { inline int32 DeserializeInt(ISerializable::DeserializeStream& stream) { int32 result = 0; if (stream.IsInt()) result = stream.GetInt(); else if (stream.IsFloat()) result = (int32)stream.GetFloat(); else if (stream.IsString()) StringUtils::Parse(stream.GetString(), &result); return result; } // In-build types inline bool ShouldSerialize(const bool& v, const void* otherObj) { return !otherObj || v != *(bool*)otherObj; } inline void Serialize(ISerializable::SerializeStream& stream, const bool& v, const void* otherObj) { stream.Bool(v); } inline void Deserialize(ISerializable::DeserializeStream& stream, bool& v, ISerializeModifier* modifier) { v = stream.GetBool(); } inline bool ShouldSerialize(const int8& v, const void* otherObj) { return !otherObj || v != *(int8*)otherObj; } inline void Serialize(ISerializable::SerializeStream& stream, const int8& v, const void* otherObj) { stream.Int(v); } inline void Deserialize(ISerializable::DeserializeStream& stream, int8& v, ISerializeModifier* modifier) { v = (int8)DeserializeInt(stream); } inline bool ShouldSerialize(const char& v, const void* otherObj) { return !otherObj || v != *(char*)otherObj; } inline void Serialize(ISerializable::SerializeStream& stream, const char& v, const void* otherObj) { stream.Int(v); } inline void Deserialize(ISerializable::DeserializeStream& stream, char& v, ISerializeModifier* modifier) { v = (char)stream.GetInt(); } inline bool ShouldSerialize(const Char& v, const void* otherObj) { return !otherObj || v != *(Char*)otherObj; } inline void Serialize(ISerializable::SerializeStream& stream, const Char& v, const void* otherObj) { stream.Int(v); } inline void Deserialize(ISerializable::DeserializeStream& stream, Char& v, ISerializeModifier* modifier) { v = (Char)stream.GetInt(); } inline bool ShouldSerialize(const int16& v, const void* otherObj) { return !otherObj || v != *(int16*)otherObj; } inline void Serialize(ISerializable::SerializeStream& stream, const int16& v, const void* otherObj) { stream.Int(v); } inline void Deserialize(ISerializable::DeserializeStream& stream, int16& v, ISerializeModifier* modifier) { v = (int16)DeserializeInt(stream); } inline bool ShouldSerialize(const int32& v, const void* otherObj) { return !otherObj || v != *(int32*)otherObj; } inline void Serialize(ISerializable::SerializeStream& stream, const int32& v, const void* otherObj) { stream.Int(v); } inline void Deserialize(ISerializable::DeserializeStream& stream, int32& v, ISerializeModifier* modifier) { v = DeserializeInt(stream); } inline bool ShouldSerialize(const int64& v, const void* otherObj) { return !otherObj || v != *(int64*)otherObj; } inline void Serialize(ISerializable::SerializeStream& stream, const int64& v, const void* otherObj) { stream.Int64(v); } inline void Deserialize(ISerializable::DeserializeStream& stream, int64& v, ISerializeModifier* modifier) { v = stream.GetInt64(); } inline bool ShouldSerialize(const uint8& v, const void* otherObj) { return !otherObj || v != *(uint8*)otherObj; } inline void Serialize(ISerializable::SerializeStream& stream, const uint8& v, const void* otherObj) { stream.Uint(v); } inline void Deserialize(ISerializable::DeserializeStream& stream, uint8& v, ISerializeModifier* modifier) { v = stream.GetUint(); } inline bool ShouldSerialize(const uint16& v, const void* otherObj) { return !otherObj || v != *(uint16*)otherObj; } inline void Serialize(ISerializable::SerializeStream& stream, const uint16& v, const void* otherObj) { stream.Uint(v); } inline void Deserialize(ISerializable::DeserializeStream& stream, uint16& v, ISerializeModifier* modifier) { v = stream.GetUint(); } inline bool ShouldSerialize(const uint32& v, const void* otherObj) { return !otherObj || v != *(uint32*)otherObj; } inline void Serialize(ISerializable::SerializeStream& stream, const uint32& v, const void* otherObj) { stream.Uint(v); } inline void Deserialize(ISerializable::DeserializeStream& stream, uint32& v, ISerializeModifier* modifier) { v = stream.GetUint(); } inline bool ShouldSerialize(const uint64& v, const void* otherObj) { return !otherObj || v != *(uint64*)otherObj; } inline void Serialize(ISerializable::SerializeStream& stream, const uint64& v, const void* otherObj) { stream.Uint64(v); } inline void Deserialize(ISerializable::DeserializeStream& stream, uint64& v, ISerializeModifier* modifier) { v = stream.GetUint64(); } inline bool ShouldSerialize(const float& v, const void* otherObj) { return !otherObj || fabsf(v - *(float*)otherObj) > SERIALIZE_EPSILON; } inline void Serialize(ISerializable::SerializeStream& stream, const float& v, const void* otherObj) { stream.Float(v); } inline void Deserialize(ISerializable::DeserializeStream& stream, float& v, ISerializeModifier* modifier) { v = stream.GetFloat(); } inline bool ShouldSerialize(const double& v, const void* otherObj) { return !otherObj || fabs(v - *(double*)otherObj) > SERIALIZE_EPSILON_DOUBLE; } inline void Serialize(ISerializable::SerializeStream& stream, const double& v, const void* otherObj) { stream.Double(v); } inline void Deserialize(ISerializable::DeserializeStream& stream, double& v, ISerializeModifier* modifier) { v = stream.GetDouble(); } // Enum template inline typename TEnableIf::Value, bool>::Type ShouldSerialize(const T& v, const void* otherObj) { return !otherObj || v != *(T*)otherObj; } template inline typename TEnableIf::Value>::Type Serialize(ISerializable::SerializeStream& stream, const T& v, const void* otherObj) { stream.Uint((uint32)v); } template inline typename TEnableIf::Value>::Type Deserialize(ISerializable::DeserializeStream& stream, T& v, ISerializeModifier* modifier) { v = (T)DeserializeInt(stream); } // Common types FLAXENGINE_API bool ShouldSerialize(const VariantType& v, const void* otherObj); FLAXENGINE_API void Serialize(ISerializable::SerializeStream& stream, const VariantType& v, const void* otherObj); FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, VariantType& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const Variant& v, const void* otherObj); FLAXENGINE_API void Serialize(ISerializable::SerializeStream& stream, const Variant& v, const void* otherObj); FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, Variant& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const Guid& v, const void* otherObj); FLAXENGINE_API void Serialize(ISerializable::SerializeStream& stream, const Guid& v, const void* otherObj); FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, Guid& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const DateTime& v, const void* otherObj); FLAXENGINE_API void Serialize(ISerializable::SerializeStream& stream, const DateTime& v, const void* otherObj); FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, DateTime& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const TimeSpan& v, const void* otherObj); FLAXENGINE_API void Serialize(ISerializable::SerializeStream& stream, const TimeSpan& v, const void* otherObj); FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, TimeSpan& v, ISerializeModifier* modifier); inline bool ShouldSerialize(const String& v, const void* otherObj) { return !otherObj || v != *(String*)otherObj; } inline void Serialize(ISerializable::SerializeStream& stream, const String& v, const void* otherObj) { stream.String(v); } inline void Deserialize(ISerializable::DeserializeStream& stream, String& v, ISerializeModifier* modifier) { v = stream.GetText(); } inline bool ShouldSerialize(const StringAnsi& v, const void* otherObj) { return !otherObj || v != *(StringAnsi*)otherObj; } inline void Serialize(ISerializable::SerializeStream& stream, const StringAnsi& v, const void* otherObj) { stream.String(v); } inline void Deserialize(ISerializable::DeserializeStream& stream, StringAnsi& v, ISerializeModifier* modifier) { v = stream.GetTextAnsi(); } FLAXENGINE_API bool ShouldSerialize(const Version& v, const void* otherObj); FLAXENGINE_API void Serialize(ISerializable::SerializeStream& stream, const Version& v, const void* otherObj); FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, Version& v, ISerializeModifier* modifier); // Math types FLAXENGINE_API bool ShouldSerialize(const Float2& v, const void* otherObj); inline void Serialize(ISerializable::SerializeStream& stream, const Float2& v, const void* otherObj) { stream.Float2(v); } FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, Float2& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const Float3& v, const void* otherObj); inline void Serialize(ISerializable::SerializeStream& stream, const Float3& v, const void* otherObj) { stream.Float3(v); } FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, Float3& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const Float4& v, const void* otherObj); inline void Serialize(ISerializable::SerializeStream& stream, const Float4& v, const void* otherObj) { stream.Float4(v); } FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, Float4& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const Double2& v, const void* otherObj); inline void Serialize(ISerializable::SerializeStream& stream, const Double2& v, const void* otherObj) { stream.Double2(v); } FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, Double2& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const Double3& v, const void* otherObj); inline void Serialize(ISerializable::SerializeStream& stream, const Double3& v, const void* otherObj) { stream.Double3(v); } FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, Double3& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const Double4& v, const void* otherObj); inline void Serialize(ISerializable::SerializeStream& stream, const Double4& v, const void* otherObj) { stream.Double4(v); } FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, Double4& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const Int2& v, const void* otherObj); inline void Serialize(ISerializable::SerializeStream& stream, const Int2& v, const void* otherObj) { stream.Int2(v); } FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, Int2& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const Int3& v, const void* otherObj); inline void Serialize(ISerializable::SerializeStream& stream, const Int3& v, const void* otherObj) { stream.Int3(v); } FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, Int3& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const Int4& v, const void* otherObj); inline void Serialize(ISerializable::SerializeStream& stream, const Int4& v, const void* otherObj) { stream.Int4(v); } FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, Int4& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const Quaternion& v, const void* otherObj); inline void Serialize(ISerializable::SerializeStream& stream, const Quaternion& v, const void* otherObj) { stream.Quaternion(v); } FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, Quaternion& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const Color& v, const void* otherObj); inline void Serialize(ISerializable::SerializeStream& stream, const Color& v, const void* otherObj) { stream.Color(v); } FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, Color& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const Color32& v, const void* otherObj); FLAXENGINE_API void Serialize(ISerializable::SerializeStream& stream, const Color32& v, const void* otherObj); FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, Color32& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const BoundingBox& v, const void* otherObj); inline void Serialize(ISerializable::SerializeStream& stream, const BoundingBox& v, const void* otherObj) { stream.BoundingBox(v); } FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, BoundingBox& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const BoundingSphere& v, const void* otherObj); inline void Serialize(ISerializable::SerializeStream& stream, const BoundingSphere& v, const void* otherObj) { stream.BoundingSphere(v); } FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, BoundingSphere& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const Ray& v, const void* otherObj); inline void Serialize(ISerializable::SerializeStream& stream, const Ray& v, const void* otherObj) { stream.Ray(v); } FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, Ray& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const Rectangle& v, const void* otherObj); inline void Serialize(ISerializable::SerializeStream& stream, const Rectangle& v, const void* otherObj) { stream.Rectangle(v); } FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, Rectangle& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const Transform& v, const void* otherObj); inline void Serialize(ISerializable::SerializeStream& stream, const Transform& v, const void* otherObj) { stream.Transform(v, (const Transform*)otherObj); } FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, Transform& v, ISerializeModifier* modifier); FLAXENGINE_API bool ShouldSerialize(const Matrix& v, const void* otherObj); inline void Serialize(ISerializable::SerializeStream& stream, const Matrix& v, const void* otherObj) { stream.Matrix(v); } FLAXENGINE_API void Deserialize(ISerializable::DeserializeStream& stream, Matrix& v, ISerializeModifier* modifier); // ISerializable inline bool ShouldSerialize(const ISerializable& v, const void* otherObj) { return true; } inline void Serialize(ISerializable::SerializeStream& stream, const ISerializable& v, const void* otherObj) { stream.StartObject(); const_cast(&v)->Serialize(stream, otherObj); stream.EndObject(); } inline void Deserialize(ISerializable::DeserializeStream& stream, ISerializable& v, ISerializeModifier* modifier) { v.Deserialize(stream, modifier); } template inline typename TEnableIf::Value, bool>::Type ShouldSerialize(const ISerializable& v, const void* otherObj) { return true; } template inline typename TEnableIf::Value>::Type Serialize(ISerializable::SerializeStream& stream, const ISerializable& v, const void* otherObj) { stream.StartObject(); const_cast(&v)->Serialize(stream, otherObj); stream.EndObject(); } template inline typename TEnableIf::Value>::Type Deserialize(ISerializable::DeserializeStream& stream, ISerializable& v, ISerializeModifier* modifier) { v.Deserialize(stream, modifier); } // Scripting Object template inline typename TEnableIf::Value, bool>::Type ShouldSerialize(const T*& v, const void* otherObj) { return !otherObj || v != *(T**)otherObj; } template inline typename TEnableIf::Value>::Type Serialize(ISerializable::SerializeStream& stream, const T*& v, const void* otherObj) { stream.Guid(v ? v->GetID() : Guid::Empty); } template inline typename TEnableIf::Value>::Type Deserialize(ISerializable::DeserializeStream& stream, T*& v, ISerializeModifier* modifier) { Guid id; Deserialize(stream, id, modifier); modifier->IdsMapping.TryGet(id, id); v = (T*)::FindObject(id, T::GetStaticClass()); } // Scripting Object Reference template inline bool ShouldSerialize(const ScriptingObjectReference& v, const void* otherObj) { return !otherObj || v.Get() != ((ScriptingObjectReference*)otherObj)->Get(); } template inline void Serialize(ISerializable::SerializeStream& stream, const ScriptingObjectReference& v, const void* otherObj) { stream.Guid(v.GetID()); } template inline void Deserialize(ISerializable::DeserializeStream& stream, ScriptingObjectReference& v, ISerializeModifier* modifier) { Guid id; Deserialize(stream, id, modifier); modifier->IdsMapping.TryGet(id, id); v = id; } // Soft Object Reference template inline bool ShouldSerialize(const SoftObjectReference& v, const void* otherObj) { return !otherObj || v.Get() != ((SoftObjectReference*)otherObj)->Get(); } template inline void Serialize(ISerializable::SerializeStream& stream, const SoftObjectReference& v, const void* otherObj) { stream.Guid(v.GetID()); } template inline void Deserialize(ISerializable::DeserializeStream& stream, SoftObjectReference& v, ISerializeModifier* modifier) { Guid id; Deserialize(stream, id, modifier); modifier->IdsMapping.TryGet(id, id); v = id; } // Asset Reference template inline bool ShouldSerialize(const AssetReference& v, const void* otherObj) { return !otherObj || v.Get() != ((AssetReference*)otherObj)->Get(); } template inline void Serialize(ISerializable::SerializeStream& stream, const AssetReference& v, const void* otherObj) { stream.Guid(v.GetID()); } template inline void Deserialize(ISerializable::DeserializeStream& stream, AssetReference& v, ISerializeModifier* modifier) { Guid id; Deserialize(stream, id, modifier); v = id; } // Weak Asset Reference template inline bool ShouldSerialize(const WeakAssetReference& v, const void* otherObj) { return !otherObj || v.Get() != ((WeakAssetReference*)otherObj)->Get(); } template inline void Serialize(ISerializable::SerializeStream& stream, const WeakAssetReference& v, const void* otherObj) { stream.Guid(v.GetID()); } template inline void Deserialize(ISerializable::DeserializeStream& stream, WeakAssetReference& v, ISerializeModifier* modifier) { Guid id; Deserialize(stream, id, modifier); v = id; } // Soft Asset Reference template inline bool ShouldSerialize(const SoftAssetReference& v, const void* otherObj) { return !otherObj || v.Get() != ((SoftAssetReference*)otherObj)->Get(); } template inline void Serialize(ISerializable::SerializeStream& stream, const SoftAssetReference& v, const void* otherObj) { stream.Guid(v.GetID()); } template inline void Deserialize(ISerializable::DeserializeStream& stream, SoftAssetReference& v, ISerializeModifier* modifier) { Guid id; Deserialize(stream, id, modifier); v = id; } // Array template inline bool ShouldSerialize(const Array& v, const void* otherObj) { if (!otherObj) return true; const auto other = (const Array*)otherObj; if (v.Count() != other->Count()) return true; const T* vPtr = v.Get(); for (int32 i = 0; i < v.Count(); i++) { if (ShouldSerialize(vPtr[i], (const void*)&other->At(i))) return true; } return false; } template inline void Serialize(ISerializable::SerializeStream& stream, const Array& v, const void* otherObj) { stream.StartArray(); const T* vPtr = v.Get(); for (int32 i = 0; i < v.Count(); i++) Serialize(stream, vPtr[i], nullptr); stream.EndArray(); } template inline void Deserialize(ISerializable::DeserializeStream& stream, Array& v, ISerializeModifier* modifier) { if (stream.IsArray()) { const auto& streamArray = stream.GetArray(); v.Resize(streamArray.Size()); T* vPtr = v.Get(); for (int32 i = 0; i < v.Count(); i++) Deserialize(streamArray[i], vPtr[i], modifier); } else if (TIsPODType::Value && stream.IsString()) { // T[] encoded as Base64 const StringAnsiView streamView(stream.GetStringAnsiView()); v.Resize(Encryption::Base64DecodeLength(*streamView, streamView.Length()) / sizeof(T)); Encryption::Base64Decode(*streamView, streamView.Length(), (byte*)v.Get()); } } // Dictionary template inline bool ShouldSerialize(const Dictionary& v, const void* otherObj) { if (!otherObj) return true; const auto other = (const Dictionary*)otherObj; if (v.Count() != other->Count()) return true; for (auto& i : v) { if (!other->ContainsKey(i.Key) || ShouldSerialize(i.Value, (const void*)&other->At(i.Key))) return true; } return false; } template inline void Serialize(ISerializable::SerializeStream& stream, const Dictionary& v, const void* otherObj) { stream.StartArray(); for (auto& i : v) { stream.StartObject(); stream.JKEY("Key"); Serialize(stream, i.Key, nullptr); stream.JKEY("Value"); Serialize(stream, i.Value, nullptr); stream.EndObject(); } stream.EndArray(); } template inline void Deserialize(ISerializable::DeserializeStream& stream, Dictionary& v, ISerializeModifier* modifier) { v.Clear(); if (stream.IsArray()) { const auto& streamArray = stream.GetArray(); const int32 size = streamArray.Size(); v.EnsureCapacity(size * 3); for (int32 i = 0; i < size; i++) { auto& streamItem = streamArray[i]; const auto mKey = SERIALIZE_FIND_MEMBER(streamItem, "Key"); const auto mValue = SERIALIZE_FIND_MEMBER(streamItem, "Value"); if (mKey != streamItem.MemberEnd() && mValue != streamItem.MemberEnd()) { KeyType key; Deserialize(mKey->value, key, modifier); Deserialize(mValue->value, v[key], modifier); } } } else if (stream.IsObject()) { const int32 size = stream.MemberCount(); v.EnsureCapacity(size * 3); for (auto i = stream.MemberBegin(); i != stream.MemberEnd(); ++i) { KeyType key; Deserialize(i->name, key, modifier); Deserialize(i->value, v[key], modifier); } } } } // @formatter:on