From b5fa5fa68e6082d45883e9a82b84566f86fee1ab Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 4 Aug 2023 10:11:58 +0200 Subject: [PATCH] Add `SerializableScriptingObject` for easier serialization of scripting objects in gameplay or content --- Source/Engine/Animations/AnimEvent.cpp | 70 ------------------- Source/Engine/Animations/AnimEvent.h | 9 +-- Source/Engine/Animations/Animations.cpp | 11 +++ Source/Engine/Scripting/ScriptingObject.cpp | 61 ++++++++++++++++ .../Scripting/SerializableScriptingObject.h | 18 +++++ 5 files changed, 92 insertions(+), 77 deletions(-) delete mode 100644 Source/Engine/Animations/AnimEvent.cpp create mode 100644 Source/Engine/Scripting/SerializableScriptingObject.h diff --git a/Source/Engine/Animations/AnimEvent.cpp b/Source/Engine/Animations/AnimEvent.cpp deleted file mode 100644 index e46a99c62..000000000 --- a/Source/Engine/Animations/AnimEvent.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. - -#include "AnimEvent.h" -#include "Engine/Scripting/BinaryModule.h" -#include "Engine/Scripting/Internal/ManagedSerialization.h" -#include "Engine/Serialization/SerializationFwd.h" -#include "Engine/Serialization/Serialization.h" - -AnimEvent::AnimEvent(const SpawnParams& params) - : ScriptingObject(params) -{ -} - -void AnimEvent::Serialize(SerializeStream& stream, const void* otherObj) -{ - SERIALIZE_GET_OTHER_OBJ(AnimEvent); - -#if !COMPILE_WITHOUT_CSHARP - // Handle C# objects data serialization - if (EnumHasAnyFlags(Flags, ObjectFlags::IsManagedType)) - { - stream.JKEY("V"); - if (other) - { - ManagedSerialization::SerializeDiff(stream, GetOrCreateManagedInstance(), other->GetOrCreateManagedInstance()); - } - else - { - ManagedSerialization::Serialize(stream, GetOrCreateManagedInstance()); - } - } -#endif - - // Handle custom scripting objects data serialization - if (EnumHasAnyFlags(Flags, ObjectFlags::IsCustomScriptingType)) - { - stream.JKEY("D"); - _type.Module->SerializeObject(stream, this, other); - } -} - -void AnimEvent::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) -{ -#if !COMPILE_WITHOUT_CSHARP - // Handle C# objects data serialization - if (EnumHasAnyFlags(Flags, ObjectFlags::IsManagedType)) - { - auto* const v = SERIALIZE_FIND_MEMBER(stream, "V"); - if (v != stream.MemberEnd() && v->value.IsObject() && v->value.MemberCount() != 0) - { - ManagedSerialization::Deserialize(v->value, GetOrCreateManagedInstance()); - } - } -#endif - - // Handle custom scripting objects data serialization - if (EnumHasAnyFlags(Flags, ObjectFlags::IsCustomScriptingType)) - { - auto* const v = SERIALIZE_FIND_MEMBER(stream, "D"); - if (v != stream.MemberEnd() && v->value.IsObject() && v->value.MemberCount() != 0) - { - _type.Module->DeserializeObject(v->value, this, modifier); - } - } -} - -AnimContinuousEvent::AnimContinuousEvent(const SpawnParams& params) - : AnimEvent(params) -{ -} diff --git a/Source/Engine/Animations/AnimEvent.h b/Source/Engine/Animations/AnimEvent.h index 2028501ea..4ed7eab48 100644 --- a/Source/Engine/Animations/AnimEvent.h +++ b/Source/Engine/Animations/AnimEvent.h @@ -2,8 +2,7 @@ #pragma once -#include "Engine/Scripting/ScriptingObject.h" -#include "Engine/Core/ISerializable.h" +#include "Engine/Scripting/SerializableScriptingObject.h" #if USE_EDITOR #include "Engine/Core/Math/Color.h" #endif @@ -14,7 +13,7 @@ class Animation; /// /// The animation notification event triggered during animation playback. /// -API_CLASS(Abstract) class FLAXENGINE_API AnimEvent : public ScriptingObject, public ISerializable +API_CLASS(Abstract) class FLAXENGINE_API AnimEvent : public SerializableScriptingObject { DECLARE_SCRIPTING_TYPE(AnimEvent); @@ -35,10 +34,6 @@ API_CLASS(Abstract) class FLAXENGINE_API AnimEvent : public ScriptingObject, pub API_FUNCTION() virtual void OnEvent(AnimatedModel* actor, Animation* anim, float time, float deltaTime) { } - - // [ISerializable] - void Serialize(SerializeStream& stream, const void* otherObj) override; - void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; }; /// diff --git a/Source/Engine/Animations/Animations.cpp b/Source/Engine/Animations/Animations.cpp index 3c80cadbe..7dd2834bf 100644 --- a/Source/Engine/Animations/Animations.cpp +++ b/Source/Engine/Animations/Animations.cpp @@ -1,6 +1,7 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. #include "Animations.h" +#include "AnimEvent.h" #include "Engine/Engine/Engine.h" #include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Level/Actors/AnimatedModel.h" @@ -52,6 +53,16 @@ TaskGraphSystem* Animations::System = nullptr; Delegate Animations::DebugFlow; #endif +AnimEvent::AnimEvent(const SpawnParams& params) + : SerializableScriptingObject(params) +{ +} + +AnimContinuousEvent::AnimContinuousEvent(const SpawnParams& params) + : AnimEvent(params) +{ +} + bool AnimationsService::Init() { Animations::System = New(); diff --git a/Source/Engine/Scripting/ScriptingObject.cpp b/Source/Engine/Scripting/ScriptingObject.cpp index 9ece58f2a..c22616cd5 100644 --- a/Source/Engine/Scripting/ScriptingObject.cpp +++ b/Source/Engine/Scripting/ScriptingObject.cpp @@ -1,6 +1,7 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. #include "ScriptingObject.h" +#include "SerializableScriptingObject.h" #include "Scripting.h" #include "BinaryModule.h" #include "Engine/Level/Actor.h" @@ -10,12 +11,14 @@ #include "Engine/Content/Content.h" #include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Threading/ThreadLocal.h" +#include "Engine/Serialization/SerializationFwd.h" #include "ManagedCLR/MAssembly.h" #include "ManagedCLR/MClass.h" #include "ManagedCLR/MUtils.h" #include "ManagedCLR/MField.h" #include "ManagedCLR/MCore.h" #include "Internal/InternalCalls.h" +#include "Internal/ManagedSerialization.h" #include "FlaxEngine.Gen.h" #define ScriptingObject_unmanagedPtr "__unmanagedPtr" @@ -24,6 +27,64 @@ // TODO: don't leak memory (use some kind of late manual GC for those wrapper objects) Dictionary ScriptingObjectsInterfaceWrappers; +SerializableScriptingObject::SerializableScriptingObject(const SpawnParams& params) + : ScriptingObject(params) +{ +} + +void SerializableScriptingObject::Serialize(SerializeStream& stream, const void* otherObj) +{ + SERIALIZE_GET_OTHER_OBJ(SerializableScriptingObject); + +#if !COMPILE_WITHOUT_CSHARP + // Handle C# objects data serialization + if (EnumHasAnyFlags(Flags, ObjectFlags::IsManagedType)) + { + stream.JKEY("V"); + if (other) + { + ManagedSerialization::SerializeDiff(stream, GetOrCreateManagedInstance(), other->GetOrCreateManagedInstance()); + } + else + { + ManagedSerialization::Serialize(stream, GetOrCreateManagedInstance()); + } + } +#endif + + // Handle custom scripting objects data serialization + if (EnumHasAnyFlags(Flags, ObjectFlags::IsCustomScriptingType)) + { + stream.JKEY("D"); + _type.Module->SerializeObject(stream, this, other); + } +} + +void SerializableScriptingObject::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) +{ +#if !COMPILE_WITHOUT_CSHARP + // Handle C# objects data serialization + if (EnumHasAnyFlags(Flags, ObjectFlags::IsManagedType)) + { + auto* const v = SERIALIZE_FIND_MEMBER(stream, "V"); + if (v != stream.MemberEnd() && v->value.IsObject() && v->value.MemberCount() != 0) + { + ManagedSerialization::Deserialize(v->value, GetOrCreateManagedInstance()); + } + } +#endif + + // Handle custom scripting objects data serialization + if (EnumHasAnyFlags(Flags, ObjectFlags::IsCustomScriptingType)) + { + auto* const v = SERIALIZE_FIND_MEMBER(stream, "D"); + if (v != stream.MemberEnd() && v->value.IsObject() && v->value.MemberCount() != 0) + { + _type.Module->DeserializeObject(v->value, this, modifier); + } + } +} + ScriptingObject::ScriptingObject(const SpawnParams& params) : _gcHandle(0) , _type(params.Type) diff --git a/Source/Engine/Scripting/SerializableScriptingObject.h b/Source/Engine/Scripting/SerializableScriptingObject.h new file mode 100644 index 000000000..8cd20af0b --- /dev/null +++ b/Source/Engine/Scripting/SerializableScriptingObject.h @@ -0,0 +1,18 @@ +// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Engine/Scripting/ScriptingObject.h" +#include "Engine/Core/ISerializable.h" + +/// +/// Base class for scripting objects that contain in-built serialization via ISerializable interface. +/// +API_CLASS() class FLAXENGINE_API SerializableScriptingObject : public ScriptingObject, public ISerializable +{ + DECLARE_SCRIPTING_TYPE(SerializableScriptingObject); + + // [ISerializable] + void Serialize(SerializeStream& stream, const void* otherObj) override; + void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; +};