diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.cpp index 56933e464a..4a02563f3a 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.cpp @@ -213,9 +213,13 @@ namespace AZ void* object, const Uuid& typeId, const rapidjson::Value& value, JsonDeserializerContext& context, ContinuationFlags flags) { bool loadAsNewInstance = (flags & ContinuationFlags::LoadAsNewInstance) == ContinuationFlags::LoadAsNewInstance; + JsonDeserializer::UseTypeDeserializer useCustom = (flags & ContinuationFlags::NoTypeSerializer) == ContinuationFlags::NoTypeSerializer + ? JsonDeserializer::UseTypeDeserializer::No + : JsonDeserializer::UseTypeDeserializer::Yes; + return (flags & ContinuationFlags::ResolvePointer) == ContinuationFlags::ResolvePointer - ? JsonDeserializer::LoadToPointer(object, typeId, value, context) - : JsonDeserializer::Load(object, typeId, value, loadAsNewInstance, context); + ? JsonDeserializer::LoadToPointer(object, typeId, value, useCustom, context) + : JsonDeserializer::Load(object, typeId, value, loadAsNewInstance, useCustom, context); } JsonSerializationResult::ResultCode BaseJsonSerializer::ContinueStoring( @@ -224,11 +228,15 @@ namespace AZ { using namespace JsonSerializationResult; + JsonSerializer::UseTypeSerializer useCustom = (flags & ContinuationFlags::NoTypeSerializer) == ContinuationFlags::NoTypeSerializer + ? JsonSerializer::UseTypeSerializer::No + : JsonSerializer::UseTypeSerializer::Yes; + if ((flags & ContinuationFlags::ReplaceDefault) == ContinuationFlags::ReplaceDefault && !context.ShouldKeepDefaults()) { if ((flags & ContinuationFlags::ResolvePointer) == ContinuationFlags::ResolvePointer) { - return JsonSerializer::StoreFromPointer(output, object, nullptr, typeId, context); + return JsonSerializer::StoreFromPointer(output, object, nullptr, typeId, useCustom, context); } else { @@ -241,19 +249,19 @@ namespace AZ { return result; } - return result.Combine(JsonSerializer::Store(output, object, nullptr, typeId, context)); + return result.Combine(JsonSerializer::Store(output, object, nullptr, typeId, useCustom, context)); } else { void* defaultObjectPtr = AZStd::any_cast(&newDefaultObject); - return JsonSerializer::Store(output, object, defaultObjectPtr, typeId, context); + return JsonSerializer::Store(output, object, defaultObjectPtr, typeId, useCustom, context); } } } return (flags & ContinuationFlags::ResolvePointer) == ContinuationFlags::ResolvePointer ? - JsonSerializer::StoreFromPointer(output, object, defaultObject, typeId, context) : - JsonSerializer::Store(output, object, defaultObject, typeId, context); + JsonSerializer::StoreFromPointer(output, object, defaultObject, typeId, useCustom, context) : + JsonSerializer::Store(output, object, defaultObject, typeId, useCustom, context); } JsonSerializationResult::ResultCode BaseJsonSerializer::LoadTypeId(Uuid& typeId, const rapidjson::Value& input, diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.h b/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.h index fc35bdcf85..12ae01799c 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.h +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.h @@ -162,9 +162,10 @@ namespace AZ None = 0, //! No extra flags. ResolvePointer = 1 << 0, //! The pointer passed in contains a pointer. The (de)serializer will attempt to resolve to an instance. ReplaceDefault = 1 << 1, //! The default value provided for storing will be replaced with a newly created one. - LoadAsNewInstance = 1 << 2 //! Treats the value as if it's a newly created instance. This may trigger serializers marked with + LoadAsNewInstance = 1 << 2, //! Treats the value as if it's a newly created instance. This may trigger serializers marked with //! OperationFlags::InitializeNewInstance. Used for instance by pointers or new instances added to //! an array. + NoTypeSerializer = 1 << 3, //! Ignore the custom/specific serializer for the TypeId }; enum class OperationFlags diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.cpp index 840034e52f..dcc0550107 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.cpp @@ -38,7 +38,8 @@ namespace AZ } JsonSerializationResult::ResultCode JsonDeserializer::Load( - void* object, const Uuid& typeId, const rapidjson::Value& value, bool isNewInstance, JsonDeserializerContext& context) + void* object, const Uuid& typeId, const rapidjson::Value& value, bool isNewInstance, UseTypeDeserializer custom, + JsonDeserializerContext& context) { using namespace AZ::JsonSerializationResult; @@ -48,8 +49,8 @@ namespace AZ "Target object for Json Serialization is pointing to nothing during loading."); } - BaseJsonSerializer* serializer = context.GetRegistrationContext()->GetSerializerForType(typeId); - if (serializer) + if (BaseJsonSerializer* serializer + = (custom == UseTypeDeserializer::Yes ? context.GetRegistrationContext()->GetSerializerForType(typeId) : nullptr)) { return DeserializerDefaultCheck(serializer, object, typeId, value, isNewInstance, context); } @@ -70,8 +71,9 @@ namespace AZ // type itself has not been reflected using EnumBuilder. Treat it as an enum. return LoadEnum(object, *classData, value, context); } - serializer = context.GetRegistrationContext()->GetSerializerForType(classData->m_azRtti->GetGenericTypeId()); - if (serializer) + + if (BaseJsonSerializer* serializer + = context.GetRegistrationContext()->GetSerializerForType(classData->m_azRtti->GetGenericTypeId())) { return DeserializerDefaultCheck(serializer, object, typeId, value, isNewInstance, context); } @@ -101,7 +103,7 @@ namespace AZ } JsonSerializationResult::ResultCode JsonDeserializer::LoadToPointer(void* object, const Uuid& typeId, - const rapidjson::Value& value, JsonDeserializerContext& context) + const rapidjson::Value& value, UseTypeDeserializer useCustom, JsonDeserializerContext& context) { using namespace JsonSerializationResult; @@ -134,7 +136,7 @@ namespace AZ const SerializeContext::ClassData* resolvedClassData = context.GetSerializeContext()->FindClassData(resolvedTypeId); if (resolvedClassData) { - status = JsonDeserializer::Load(*objectPtr, resolvedTypeId, value, true, context); + status = JsonDeserializer::Load(*objectPtr, resolvedTypeId, value, true, useCustom, context); *objectPtr = resolvedClassData->m_azRtti->Cast(*objectPtr, typeId); @@ -171,11 +173,11 @@ namespace AZ } AZ_Assert(classElement.m_azRtti->GetTypeId() == classElement.m_typeId, "Type id mismatch during deserialization of a json file. (%s vs %s)"); - return LoadToPointer(object, classElement.m_typeId, value, context); + return LoadToPointer(object, classElement.m_typeId, value, UseTypeDeserializer::Yes, context); } else { - return Load(object, classElement.m_typeId, value, false, context); + return Load(object, classElement.m_typeId, value, false, UseTypeDeserializer::Yes, context); } } diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.h b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.h index ea236fe93c..d0a07b1a74 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.h +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.h @@ -28,6 +28,11 @@ namespace AZ FullyProcessed, ContinueProcessing }; + enum class UseTypeDeserializer : bool + { + No, + Yes + }; enum class TypeIdDetermination : u8 { ExplicitTypeId, // Type id was explicitly defined using "$type". @@ -55,10 +60,11 @@ namespace AZ JsonDeserializer(JsonDeserializer&& rhs) = delete; static JsonSerializationResult::ResultCode Load( - void* object, const Uuid& typeId, const rapidjson::Value& value, bool isNewInstance, JsonDeserializerContext& context); + void* object, const Uuid& typeId, const rapidjson::Value& value, bool isNewInstance, UseTypeDeserializer useCustom, + JsonDeserializerContext& context); static JsonSerializationResult::ResultCode LoadToPointer(void* object, const Uuid& typeId, const rapidjson::Value& value, - JsonDeserializerContext& context); + UseTypeDeserializer useCustom, JsonDeserializerContext& context); static JsonSerializationResult::ResultCode LoadWithClassElement(void* object, const rapidjson::Value& value, const SerializeContext::ClassElement& classElement, JsonDeserializerContext& context); diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerialization.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerialization.cpp index 8ade30cc6c..bc07f684f6 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerialization.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerialization.cpp @@ -245,7 +245,7 @@ namespace AZ { StackedString path(StackedString::Format::JsonPointer); JsonDeserializerContext context(settings); - result = JsonDeserializer::Load(object, objectType, root, false, context); + result = JsonDeserializer::Load(object, objectType, root, false, JsonDeserializer::UseTypeDeserializer::Yes, context); } return result; } @@ -322,7 +322,7 @@ namespace AZ JsonSerializerContext context(settings, allocator); StackedString path(StackedString::Format::ContextPath); - result = JsonSerializer::Store(output, object, defaultObject, objectType, context); + result = JsonSerializer::Store(output, object, defaultObject, objectType, JsonSerializer::UseTypeSerializer::Yes, context); } return result; } diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerializer.cpp index 1fa0dd3c44..80a81181e5 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerializer.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerializer.cpp @@ -20,7 +20,7 @@ namespace AZ { JsonSerializationResult::ResultCode JsonSerializer::Store(rapidjson::Value& output, const void* object, const void* defaultObject, - const Uuid& typeId, JsonSerializerContext& context) + const Uuid& typeId, UseTypeSerializer custom, JsonSerializerContext& context) { using namespace JsonSerializationResult; @@ -32,8 +32,8 @@ namespace AZ // First check if there's a generic serializer registered for this. This makes it possible to use serializers that // are not (directly) registered with the Serialize Context. - auto serializer = context.GetRegistrationContext()->GetSerializerForType(typeId); - if (serializer) + if (BaseJsonSerializer* serializer + = (custom == UseTypeSerializer::Yes ? context.GetRegistrationContext()->GetSerializerForType(typeId) : nullptr)) { // Start by setting the object to be an explicit default. output.SetObject(); @@ -57,17 +57,18 @@ namespace AZ "No factory available to create a default object for comparison."); } void* defaultObjectPtr = AZStd::any_cast(&defaultObjectInstance); - ResultCode conversionResult = StoreWithClassData(output, object, defaultObjectPtr, *classData, StoreTypeId::No, context); + ResultCode conversionResult = StoreWithClassData(output, object, defaultObjectPtr, *classData, StoreTypeId::No + , UseTypeSerializer::Yes, context); return ResultCode::Combine(result, conversionResult); } else { - return StoreWithClassData(output, object, defaultObject, *classData, StoreTypeId::No, context); + return StoreWithClassData(output, object, defaultObject, *classData, StoreTypeId::No, custom, context); } } JsonSerializationResult::ResultCode JsonSerializer::StoreFromPointer(rapidjson::Value& output, const void* object, - const void* defaultObject, const Uuid& typeId, JsonSerializerContext& context) + const void* defaultObject, const Uuid& typeId, UseTypeSerializer custom, JsonSerializerContext& context) { using namespace JsonSerializationResult; @@ -85,19 +86,21 @@ namespace AZ AZ_Assert(classData->m_azRtti->GetTypeId() == typeId, "Type id mismatch in '%s' during serialization to a json file. (%s vs %s)", classData->m_name, classData->m_azRtti->GetTypeId().ToString().c_str(), typeId.ToString().c_str()); - return StoreWithClassDataFromPointer(output, object, defaultObject, *classData, context); + return StoreWithClassDataFromPointer(output, object, defaultObject, *classData, custom, context); } JsonSerializationResult::ResultCode JsonSerializer::StoreWithClassData(rapidjson::Value& node, const void* object, const void* defaultObject, const SerializeContext::ClassData& classData, StoreTypeId storeTypeId, - JsonSerializerContext& context) + UseTypeSerializer custom, JsonSerializerContext& context) { using namespace JsonSerializationResult; // Start by setting the object to be an explicit default. node.SetObject(); - auto serializer = context.GetRegistrationContext()->GetSerializerForType(classData.m_typeId); + auto serializer = custom == UseTypeSerializer::Yes + ? context.GetRegistrationContext()->GetSerializerForType(classData.m_typeId) : nullptr; + if (serializer) { ResultCode result = serializer->Store(node, object, defaultObject, classData.m_typeId, context); @@ -153,7 +156,7 @@ namespace AZ } JsonSerializationResult::ResultCode JsonSerializer::StoreWithClassDataFromPointer(rapidjson::Value& output, const void* object, - const void* defaultObject, const SerializeContext::ClassData& classData, JsonSerializerContext& context) + const void* defaultObject, const SerializeContext::ClassData& classData, UseTypeSerializer custom, JsonSerializerContext& context) { using namespace JsonSerializationResult; @@ -176,7 +179,7 @@ namespace AZ } else { - return StoreWithClassData(output, object, defaultObject, *resolvedClassData, storeTypeId, context); + return StoreWithClassData(output, object, defaultObject, *resolvedClassData, storeTypeId, custom, context); } } @@ -221,8 +224,8 @@ namespace AZ { rapidjson::Value value; ResultCode result = classElement.m_flags & SerializeContext::ClassElement::FLG_POINTER ? - StoreWithClassDataFromPointer(value, object, defaultObject, *elementClassData, context): - StoreWithClassData(value, object, defaultObject, *elementClassData, StoreTypeId::No, context); + StoreWithClassDataFromPointer(value, object, defaultObject, *elementClassData, UseTypeSerializer::Yes, context): + StoreWithClassData(value, object, defaultObject, *elementClassData, StoreTypeId::No, UseTypeSerializer::Yes, context); if (result.GetProcessing() != Processing::Halted) { if (parentNode.IsObject()) diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerializer.h b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerializer.h index 0ccf020cee..22dd768ec5 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerializer.h +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerializer.h @@ -26,6 +26,11 @@ namespace AZ No, Yes }; + enum class UseTypeSerializer : bool + { + No, + Yes + }; enum class ResolvePointerResult { FullyProcessed, @@ -41,16 +46,18 @@ namespace AZ JsonSerializer(JsonSerializer&& rhs) = delete; static JsonSerializationResult::ResultCode Store(rapidjson::Value& output, const void* object, const void* defaultObject, - const Uuid& typeId, JsonSerializerContext& context); + const Uuid& typeId, UseTypeSerializer useCustom, JsonSerializerContext& context); static JsonSerializationResult::ResultCode StoreFromPointer(rapidjson::Value& output, const void* object, const void* defaultObject, - const Uuid& typeId, JsonSerializerContext& context); + const Uuid& typeId, UseTypeSerializer custom, JsonSerializerContext& context); static JsonSerializationResult::ResultCode StoreWithClassData(rapidjson::Value& node, const void* object, const void* defaultObject, - const SerializeContext::ClassData& classData, StoreTypeId storeTypeId, JsonSerializerContext& context); + const SerializeContext::ClassData& classData, StoreTypeId storeTypeId, UseTypeSerializer custom, + JsonSerializerContext& context); static JsonSerializationResult::ResultCode StoreWithClassDataFromPointer(rapidjson::Value& output, const void* object, - const void* defaultObject, const SerializeContext::ClassData& classData, JsonSerializerContext& context); + const void* defaultObject, const SerializeContext::ClassData& classData, UseTypeSerializer custom, + JsonSerializerContext& context); static JsonSerializationResult::ResultCode StoreWithClassElement(rapidjson::Value& parentNode, const void* object, const void* defaultObject, const SerializeContext::ClassElement& classElement, JsonSerializerContext& context); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Serialization/Json/JsonUtils.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Serialization/Json/JsonUtils.cpp index 89cf667958..49a902de54 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Serialization/Json/JsonUtils.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Serialization/Json/JsonUtils.cpp @@ -333,7 +333,7 @@ namespace AZ // validate class name auto classData = loadSettings.m_serializeContext->FindClassData(classId); - if (azstricmp(classData->m_name, className) != 0) + if (!classData || azstricmp(classData->m_name, className) != 0) { return AZ::Failure(AZStd::string::format("Try to load class %s from class %s data", classData->m_name, className)); } diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAsset.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAsset.cpp index adada5791e..8d9f575586 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAsset.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAsset.cpp @@ -114,11 +114,13 @@ namespace ScriptCanvasEditor ScriptCanvas::ScriptCanvasData& ScriptCanvasAsset::GetScriptCanvasData() { + AZ_Assert(m_data != nullptr, "data not initialized"); return *m_data; } const ScriptCanvas::ScriptCanvasData& ScriptCanvasAsset::GetScriptCanvasData() const { + AZ_Assert(m_data != nullptr, "data not initialized"); return *m_data; } } diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHandler.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHandler.cpp index ee78a71772..9af12facca 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHandler.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHandler.cpp @@ -76,7 +76,7 @@ namespace ScriptCanvasEditor AZ::Data::AssetHandler::LoadResult ScriptCanvasAssetHandler::LoadAssetData ( const AZ::Data::Asset& assetTarget , AZStd::shared_ptr streamSource - , const AZ::Data::AssetFilterCB& assetLoadFilterCB) + , [[maybe_unused]] const AZ::Data::AssetFilterCB& assetLoadFilterCB) { namespace JSRU = AZ::JsonSerializationUtils; using namespace ScriptCanvas; @@ -86,30 +86,43 @@ namespace ScriptCanvasEditor if (scriptCanvasAssetTarget && m_serializeContext && streamSource) { - AZ::JsonDeserializerSettings settings; - // more mapping stuff - settings.m_serializeContext = m_serializeContext; streamSource->Seek(0U, AZ::IO::GenericStream::ST_SEEK_BEGIN); - // presume JSON serialization... - if (JSRU::LoadObjectFromStreamByType - ( scriptCanvasAssetTarget - , azrtti_typeid() - , *streamSource - , &settings).IsSuccess()) - { - return AZ::Data::AssetHandler::LoadResult::LoadComplete; - } - else - { - // ...if there is a failure, check if it is saved in the old format - streamSource->Seek(0U, AZ::IO::GenericStream::ST_SEEK_BEGIN); - // tolerate unknown classes in the editor. Let the asset processor warn about bad nodes... - bool loadSuccess = AZ::Utils::LoadObjectFromStreamInPlace(*streamSource, scriptCanvasAssetTarget->GetScriptCanvasData() - , m_serializeContext - , AZ::ObjectStream::FilterDescriptor(assetLoadFilterCB, AZ::ObjectStream::FILTERFLAG_IGNORE_UNKNOWN_CLASSES)); + auto& scriptCanvasDataTarget = scriptCanvasAssetTarget->GetScriptCanvasData(); + AZStd::vector byteBuffer(streamSource->GetLength()); + AZ::IO::ByteContainerStream byteStreamSource(&byteBuffer); + const size_t bytesRead = streamSource->Read(byteBuffer.size(), byteBuffer.data()); - return loadSuccess ? AZ::Data::AssetHandler::LoadResult::LoadComplete : AZ::Data::AssetHandler::LoadResult::Error; + if (bytesRead == streamSource->GetLength()) + { + byteStreamSource.Seek(0U, AZ::IO::GenericStream::ST_SEEK_BEGIN); + AZ::JsonDeserializerSettings settings; + // \todo more mapping stuff needs to go in the settings + settings.m_serializeContext = m_serializeContext; + byteStreamSource.Seek(0U, AZ::IO::GenericStream::ST_SEEK_BEGIN); + // attempt JSON deserialization... + if (JSRU::LoadObjectFromStreamByType + ( &scriptCanvasDataTarget + , azrtti_typeid() + , byteStreamSource + , &settings).IsSuccess()) + { + return AZ::Data::AssetHandler::LoadResult::LoadComplete; + } +#if defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED) + else + { + // ...if there is a failure, check if it is saved in the old format + byteStreamSource.Seek(0U, AZ::IO::GenericStream::ST_SEEK_BEGIN); + // tolerate unknown classes in the editor. Let the asset processor warn about bad nodes... + if (AZ::Utils::LoadObjectFromStreamInPlace(byteStreamSource, scriptCanvasAssetTarget->GetScriptCanvasData() + , m_serializeContext + , AZ::ObjectStream::FilterDescriptor(assetLoadFilterCB, AZ::ObjectStream::FILTERFLAG_IGNORE_UNKNOWN_CLASSES))) + { + return AZ::Data::AssetHandler::LoadResult::LoadComplete; + } + } } +#endif } return AZ::Data::AssetHandler::LoadResult::Error; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasGrammar_Header.jinja b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasGrammar_Header.jinja index 00c23b9f35..ebf647c7e9 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasGrammar_Header.jinja +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasGrammar_Header.jinja @@ -43,9 +43,19 @@ SPDX-License-Identifier: Apache-2.0 OR MIT namespace {{attribute_Namespace}} { {% endif %} - {% set className = Class.attrib['Name'] %} -{% set baseClass = Class.attrib['Base'] %} +{% if Class.attrib['Base'] is defined %} +{% if Class.attrib['Base'].split(';')|length > 1 %} +{% set baseClass = Class.attrib['Base'].split(';')[0] %} +{% set baseClasses = ", ".join(Class.attrib['Base'].split(';')) %} +{% else %} +{% set baseClass = Class.attrib['Base'] %} +{% set baseClasses = Class.attrib['Base'] %} +{% endif %} +{% else %} +{% set baseClass = "ScriptCanvas::Node" %} +{% set baseClasses = "ScriptCanvas::Node" %} +{% endif %} ///////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -66,7 +76,7 @@ namespace {{attribute_Namespace}} // You must #include the generated header into the source header #define SCRIPTCANVAS_NODE_{{ className }} \ public: \ - AZ_COMPONENT({{ className }}, "{{ classUuid }}"{% if baseClass is defined %}, {{ baseClass }}{% endif %}); \ + AZ_COMPONENT({{ className }}, "{{ classUuid }}", {{ baseClasses}} ); \ static void Reflect(AZ::ReflectContext* reflection); \ void ConfigureSlots() override; \ bool RequiresDynamicSlotOrdering() const override; \ diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasGrammar_Source.jinja b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasGrammar_Source.jinja index 205e6ebd8c..18b7fac688 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasGrammar_Source.jinja +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasGrammar_Source.jinja @@ -26,12 +26,22 @@ SPDX-License-Identifier: Apache-2.0 OR MIT #include "{{ xml.attrib['Include'] }}" {% for Class in xml.iter('Class') %} +{% if Class.attrib['Base'] is defined %} +{% if Class.attrib['Base'].split(';')|length > 1 %} +{% set baseClass = Class.attrib['Base'].split(';')[0] %} +{% set baseClasses = ", ".join(Class.attrib['Base'].split(';')) %} +{% else %} +{% set baseClass = Class.attrib['Base'] %} +{% set baseClasses = Class.attrib['Base'] %} +{% endif %} +{% else %} +{% set baseClass = "ScriptCanvas::Node" %} +{% set baseClasses = "ScriptCanvas::Node" %} +{% endif %} void {{ Class.attrib['QualifiedName'] }}::ConfigureSlots() { -{% if Class.attrib['Base'] is defined %} - {{ Class.attrib['Base'] }}::ConfigureSlots(); + {{ baseClass }}::ConfigureSlots(); -{% endif %} {% for Property in Class.iter('Property') %} {% if Property.attrib['IsInput'] | booleanTrue %} // {{ Property.attrib['Name'] }} @@ -194,13 +204,11 @@ void {{ Class.attrib['QualifiedName'] }}::Reflect(AZ::ReflectContext* context) {% endfor %} {% endif %} -{% if Class.attrib['Base'] is defined %} - static_assert((std::is_base_of::value), "Script Canvas nodes require the first base class to be derived from ScriptCanvas::Node"); + static_assert((std::is_base_of::value), "Script Canvas nodes require the first base class to be derived from ScriptCanvas::Node"); -{% endif %} if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) { - serializeContext->Class<{{ Class.attrib['QualifiedName'] }}{% if Class.attrib['Base'] is defined %}, {{ Class.attrib['Base'] }}{% endif %}>() + serializeContext->Class<{{ Class.attrib['QualifiedName'] }}, {{ baseClass }}>() {% if Class.attrib['EventHandler'] is defined %} ->EventHandler<{{ Class.attrib['EventHandler'] }}>() {% endif %} diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h index 5e4d11ac65..76542d6097 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h @@ -24,6 +24,8 @@ #include #include +#define OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED + namespace AZ { class Entity; @@ -94,7 +96,7 @@ namespace ScriptCanvas struct VersionData { - AZ_TYPE_INFO(VersionData, "{14C629F6-467B-46FE-8B63-48FDFCA42175}"); + AZ_TYPE_INFO(VersionData, "{52036892-DA63-4199-AC6A-9BAFE6B74EFC}"); static void Reflect(AZ::ReflectContext* context); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.cpp index e4569af820..c36110ef92 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.cpp @@ -2041,7 +2041,27 @@ namespace ScriptCanvas } } - void Datum::OnWriteEnd() + void Datum::OnSerializeBegin() + { + if (m_type.GetType() == Data::eType::BehaviorContextObject) + { + if (BehaviorContextObjectPtr ptr = (*AZStd::any_cast(&m_storage.value))) + { + ptr->OnSerializeBegin(); + } + else + { + AZ_Error("ScriptCanvas", false, AZStd::string::format("Datum type (%s) failed to serialized, did not store BehaviorContextObjectPtr properly", m_type.GetAZType().ToString().c_str()).c_str()); + } + } + } + + void Datum::OnReadBegin() + { + OnSerializeBegin(); + } + + void Datum::OnDeserialize() { if (m_type.GetType() == Data::eType::BehaviorContextObject) { @@ -2059,11 +2079,16 @@ namespace ScriptCanvas } else { - AZ_Error("Script Canvas", false, AZStd::string::format("Datum type (%s) de-serialized, but no such class found in the behavior context", m_type.GetAZType().ToString().c_str()).c_str()); + AZ_Error("ScriptCanvas", false, AZStd::string::format("Datum type (%s) de-serialized, but no such class found in the behavior context", m_type.GetAZType().ToString().c_str()).c_str()); } } } + void Datum::OnWriteEnd() + { + OnSerializeEnd(); + } + void Datum::Reflect(AZ::ReflectContext* reflection) { if (auto serializeContext = azrtti_cast(reflection)) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.h index 4cbc25b500..3ad09e2297 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.h @@ -8,14 +8,15 @@ #pragma once +#include #include #include #include #include +#include +#include #include #include -#include -#include namespace AZ { @@ -33,11 +34,12 @@ namespace ScriptCanvas /// A Datum is used to provide generic storage for all data types in ScriptCanvas, and provide a common interface to accessing, modifying, and displaying them /// in the editor, regardless of their actual ScriptCanvas or BehaviorContext type. class Datum final + : public SerializationListener { friend class AZ::DatumSerializer; public: - AZ_TYPE_INFO(Datum, "{8B836FC0-98A8-4A81-8651-35C7CA125451}"); + AZ_RTTI(Datum, "{8B836FC0-98A8-4A81-8651-35C7CA125451}", SerializationListener); AZ_CLASS_ALLOCATOR(Datum, AZ::SystemAllocator, 0); enum class eOriginality : int @@ -237,6 +239,13 @@ namespace ScriptCanvas class SerializeContextEventHandler : public AZ::SerializeContext::IEventHandler { public: + /// Called after we are done writing to the instance pointed by classPtr. + void OnReadBegin(void* classPtr) override + { + Datum* datum = reinterpret_cast(classPtr); + datum->OnReadBegin(); + } + /// Called after we are done writing to the instance pointed by classPtr. void OnWriteEnd(void* classPtr) override { @@ -341,6 +350,10 @@ namespace ScriptCanvas void OnDatumEdited(); + void OnSerializeBegin() override; + + void OnDeserialize() override; + void OnReadBegin(); void OnWriteEnd(); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/GraphData.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/GraphData.cpp index 9bed478d74..d8fd409147 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/GraphData.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/GraphData.cpp @@ -25,9 +25,7 @@ namespace ScriptCanvas /// Called to rebuild the Endpoint map void OnWriteEnd(void* classPtr) override { - auto* graphData = reinterpret_cast(classPtr); - graphData->BuildEndpointMap(); - graphData->LoadDependentAssets(); + reinterpret_cast(classPtr)->OnDeserialized(); } }; @@ -215,4 +213,10 @@ namespace ScriptCanvas m_dependentAssets.clear(); } + + void GraphData::OnDeserialized() + { + BuildEndpointMap(); + LoadDependentAssets(); + } } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/GraphData.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/GraphData.h index f09098ca17..cdd23bbdda 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/GraphData.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/GraphData.h @@ -37,6 +37,7 @@ namespace ScriptCanvas void BuildEndpointMap(); void Clear(bool deleteData = false); void LoadDependentAssets(); + void OnDeserialized(); using NodeContainer = AZStd::unordered_set; using ConnectionContainer = AZStd::vector; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.cpp index 6e87e52f87..5af59fc166 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.cpp @@ -67,7 +67,7 @@ namespace ScriptCanvas void OnWriteEnd(void* objectPtr) override { auto node = reinterpret_cast(objectPtr); - node->RebuildInternalState(); + node->OnDeserialize(); } }; @@ -2616,6 +2616,11 @@ namespace ScriptCanvas } } + void Node::OnDeserialize() + { + RebuildInternalState(); + } + void Node::OnEndpointConnected(const Endpoint& endpoint) { const SlotId& currentSlotId = EndpointNotificationBus::GetCurrentBusId()->GetSlotId(); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h index bf3e17156b..298eff5222 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h @@ -14,25 +14,23 @@ #include #include #include - +#include #include #include #include #include -#include #include #include #include +#include #include +#include #include +#include #include #include -#include #include -#include - -#include - +#include #define SCRIPT_CANVAS_CALL_ON_INDEX_SEQUENCE(lambdaInterior)\ int dummy[]{ 0, ( lambdaInterior , 0)... };\ @@ -401,6 +399,7 @@ namespace ScriptCanvas , public DatumNotificationBus::Handler , public NodeRequestBus::Handler , public EndpointNotificationBus::MultiHandler + , public SerializationListener { friend class Graph; friend class RuntimeComponent; @@ -472,7 +471,7 @@ namespace ScriptCanvas public: - AZ_COMPONENT(Node, "{52B454AE-FA7E-4FE9-87D3-A1CAB235C691}"); + AZ_COMPONENT(Node, "{52B454AE-FA7E-4FE9-87D3-A1CAB235C691}", SerializationListener); static void Reflect(AZ::ReflectContext* reflection); Node(); @@ -821,6 +820,7 @@ namespace ScriptCanvas ////////////////////////////////////////////////////////////////////////// protected: + void OnDeserialize() override; virtual void OnReconfigurationBegin() {} virtual void OnReconfigurationEnd() {} diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/SerializationListener.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/SerializationListener.h new file mode 100644 index 0000000000..d53e66f21b --- /dev/null +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/SerializationListener.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +namespace ScriptCanvas +{ + class SerializationListener + { + public: + AZ_RTTI(SerializationListener, "{CA4EE281-30B3-4928-BCD8-9305CE75E463}"); + virtual ~SerializationListener() = 0 {} + + virtual void OnSerializeBegin() {} + virtual void OnSerializeEnd() {} + + virtual void OnDeserialize() {} + }; + + using SerializationListeners = AZStd::vector; +} diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Data/BehaviorContextObject.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Data/BehaviorContextObject.cpp index 09d356a2f0..2abeec6266 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Data/BehaviorContextObject.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Data/BehaviorContextObject.cpp @@ -17,7 +17,7 @@ namespace ScriptCanvas { - void BehaviorContextObject::OnReadBegin() + void BehaviorContextObject::OnSerializeBegin() { if (!IsOwned()) { @@ -25,18 +25,12 @@ namespace ScriptCanvas } } - void BehaviorContextObject::OnWriteEnd() - { - // Id Remapping invokes this method as well, not just serializing from an ObjectStream - } - void BehaviorContextObject::Reflect(AZ::ReflectContext* reflection) { if (auto serializeContext = azrtti_cast(reflection)) { serializeContext->Class() ->Version(0) - ->EventHandler() ->Field("m_flags", &BehaviorContextObject::m_flags) ->Field("m_object", &BehaviorContextObject::m_object) ; @@ -55,24 +49,11 @@ namespace ScriptCanvas } } - void BehaviorContextObject::SerializeContextEventHandler::OnReadBegin(void* classPtr) - { - BehaviorContextObject* object = reinterpret_cast(classPtr); - object->OnReadBegin(); - } - - void BehaviorContextObject::SerializeContextEventHandler::OnWriteEnd(void* classPtr) - { - BehaviorContextObject* object = reinterpret_cast(classPtr); - object->OnWriteEnd(); - } - BehaviorContextObjectPtr BehaviorContextObject::CloneObject(const AZ::BehaviorClass& behaviorClass) { if (SystemRequestBus::HasHandlers()) { AZStd::vector buffer; - { bool wasOwned = IsOwned(); m_flags |= Flags::Owned; @@ -87,7 +68,6 @@ namespace ScriptCanvas } AZ::IO::ByteContainerStream> readStream(&buffer); - BehaviorContextObject* newObject = CreateDefault(behaviorClass); AZ::Utils::LoadObjectFromStreamInPlace(readStream, (*newObject)); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Data/BehaviorContextObject.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Data/BehaviorContextObject.h index ca4500eccc..8cb04801fc 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Data/BehaviorContextObject.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Data/BehaviorContextObject.h @@ -29,6 +29,7 @@ namespace ScriptCanvas class BehaviorContextObject final { friend struct AZStd::IntrusivePtrCountPolicy; + friend class Datum; public: AZ_TYPE_INFO(BehaviorContextObject, "{B735214D-5182-4536-B748-61EC83C1F007}"); @@ -69,16 +70,6 @@ namespace ScriptCanvas Reference = 1 << 3, }; - class SerializeContextEventHandler : public AZ::SerializeContext::IEventHandler - { - public: - /// Called right before we start reading from the instance pointed by classPtr. - void OnReadBegin(void* classPtr) override; - - /// Called after we are done writing to the instance pointed by classPtr. - void OnWriteEnd(void* classPtr) override; - }; - template static AZ::BehaviorObject InvokeConstructor(const AZ::BehaviorClass& behaviorClass, void* resultPtr, Args&&... args); @@ -128,9 +119,7 @@ namespace ScriptCanvas AZ_FORCE_INLINE bool IsOwned() const; - void OnReadBegin(); - - void OnWriteEnd(); + void OnSerializeBegin(); AZ_FORCE_INLINE void add_ref(); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/EBusEventHandler.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/EBusEventHandler.cpp index af583738da..bfcb629225 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/EBusEventHandler.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/EBusEventHandler.cpp @@ -602,13 +602,21 @@ namespace ScriptCanvas } } - void EBusEventHandler::OnWriteEnd() + void EBusEventHandler::OnDeserialize() { AZStd::lock_guard lock(m_mutex); if (!m_ebus) { CreateHandler(m_ebusName); } + + /// \note Call super() anti-pattern https://en.wikipedia.org/wiki/Call_super + Node::OnDeserialize(); + } + + void EBusEventHandler::OnWriteEnd() + { + OnDeserialize(); } NodeTypeIdentifier EBusEventHandler::GetOutputNodeType(const SlotId& slotId) const diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/EBusEventHandler.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/EBusEventHandler.h index eb905b7c90..b36636fe1c 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/EBusEventHandler.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/EBusEventHandler.h @@ -138,6 +138,8 @@ namespace ScriptCanvas void SetAutoConnectToGraphOwner(bool enabled); + void OnDeserialize(); + void OnWriteEnd(); AZStd::string GetNodeName() const override diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.cpp index 9701e346be..5a732a1185 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.cpp @@ -313,6 +313,7 @@ namespace ScriptCanvas } PopulateNodeType(); + m_warnOnMissingFunction = true; } bool Method::InitializeOverloaded([[maybe_unused]] const NamespacePath& namespaces, AZStd::string_view className, AZStd::string_view methodName) @@ -739,10 +740,11 @@ namespace ScriptCanvas return TupleType{ nullptr, MethodType::Count, EventType::Count, nullptr }; } - void Method::OnWriteEnd() + void Method::OnDeserialize() { AZStd::lock_guard lock(m_mutex); + m_warnOnMissingFunction = true; const AZ::BehaviorClass* bcClass{}; const AZ::BehaviorMethod* method{}; EventType eventType; @@ -758,13 +760,20 @@ namespace ScriptCanvas { AZ_Warning("ScriptCanvas", !m_warnOnMissingFunction, "method node failed to deserialize properly"); } - } if (m_resultSlotIDs.empty()) { m_resultSlotIDs.emplace_back(SlotId{}); } + + /// \note Call super() anti-pattern https://en.wikipedia.org/wiki/Call_super + Node::OnDeserialize(); + } + + void Method::OnWriteEnd() + { + OnDeserialize(); } bool Method::BranchesOnResult() const diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.h index 41d4adcb84..b44539d915 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.h @@ -22,7 +22,6 @@ namespace AZ namespace ScriptCanvas { - AZ::Outcome IsExposable(const AZ::BehaviorMethod& method); Grammar::FunctionPrototype ToSignature(const AZ::BehaviorMethod& method); @@ -31,7 +30,8 @@ namespace ScriptCanvas { namespace Core { - class Method : public Node + class Method + : public Node { public: AZ_COMPONENT(Method, "{E42861BD-1956-45AE-8DD7-CCFC1E3E5ACF}", Node); @@ -107,6 +107,8 @@ namespace ScriptCanvas SlotId GetBusSlotId() const; + void OnDeserialize(); + void OnWriteEnd(); virtual bool IsMethodOverloaded() const { return false; } @@ -180,7 +182,7 @@ namespace ScriptCanvas AZStd::vector m_inputSlots; AZStd::vector m_resultSlotIDs; AZStd::recursive_mutex m_mutex; // post-serialization - bool m_warnOnMissingFunction = true; + bool m_warnOnMissingFunction = false; Method(const Method&) = delete; }; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/MethodOverloaded.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/MethodOverloaded.cpp index c902d279bc..f20f79a6b1 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/MethodOverloaded.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/MethodOverloaded.cpp @@ -397,20 +397,16 @@ namespace ScriptCanvas return signature; } - void MethodOverloaded::OnReadBegin() - { - } - - void MethodOverloaded::OnReadEnd() - { - } - void MethodOverloaded::OnWriteBegin() { - SetWarnOnMissingFunction(false); } void MethodOverloaded::OnWriteEnd() + { + OnDeserialize(); + } + + void MethodOverloaded::OnDeserialize() { AZStd::lock_guard lock(GetMutex()); @@ -462,6 +458,9 @@ namespace ScriptCanvas } SetWarnOnMissingFunction(true); + + /// \note Call super() anti-pattern https://en.wikipedia.org/wiki/Call_super + Node::OnDeserialize(); } void MethodOverloaded::SetupMethodData(const AZ::BehaviorMethod* behaviorMethod, const AZ::BehaviorClass* behaviorClass) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/MethodOverloaded.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/MethodOverloaded.h index c15b8f718c..a4d7ea83d8 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/MethodOverloaded.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/MethodOverloaded.h @@ -92,12 +92,13 @@ namespace ScriptCanvas Grammar::FunctionPrototype GetInputSignature() const; // SerializeContextReadWriteHandler - void OnReadBegin(); - void OnReadEnd(); + void OnReadBegin() {} + void OnReadEnd() {} void OnWriteBegin(); void OnWriteEnd(); - //// + + void OnDeserialize() override; void SetupMethodData(const AZ::BehaviorMethod* lookupMethod, const AZ::BehaviorClass* lookupClass); void ConfigureContracts(); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Serialization/DatumSerializer.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Serialization/DatumSerializer.cpp index 003ef05774..aecf0f3db7 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Serialization/DatumSerializer.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Serialization/DatumSerializer.cpp @@ -85,7 +85,7 @@ namespace AZ AZ_Assert(azrtti_typeidm_datumLabel)>() == azrtti_typeid() , "m_datumLabel type changed and won't load properly"); - result.Combine( ContinueLoadingFromJsonObjectField + result.Combine(ContinueLoadingFromJsonObjectField ( &label , azrtti_typeidm_datumLabel)>() , inputValue @@ -95,6 +95,7 @@ namespace AZ Datum copy(scType, Datum::eOriginality::Original, AZStd::any_cast(&storage), scType.GetAZType()); copy.SetLabel(label); *outputDatum = copy; + outputDatum->OnDeserialize(); return context.Report(result, result.GetProcessing() != JSR::Processing::Halted ? "DatumSerializer Load finished loading Datum" @@ -124,7 +125,9 @@ namespace AZ ( JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, "DatumSerializer Store used defaults for Datum"); } } - + + const_cast(inputScriptDataPtr)->OnSerializeBegin(); + JSR::ResultCode result(JSR::Tasks::WriteValue); outputValue.SetObject(); @@ -162,7 +165,7 @@ namespace AZ , inputScriptDataPtr->GetType().GetAZType() , context)); } // datum storage end - + result.Combine(ContinueStoringToJsonObjectField ( outputValue , "label" @@ -171,9 +174,9 @@ namespace AZ , azrtti_typeidm_datumLabel)>() , context)); + const_cast(inputScriptDataPtr)->OnSerializeEnd(); return context.Report(result, result.GetProcessing() != JSR::Processing::Halted ? "DatumSerializer Store finished saving Datum" : "DatumSerializer Store failed to save Datum"); } - } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Serialization/GraphDataSerializer.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Serialization/GraphDataSerializer.cpp new file mode 100644 index 0000000000..ff284fce85 --- /dev/null +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Serialization/GraphDataSerializer.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include + +using namespace ScriptCanvas; + +namespace GraphDataSerializerCpp +{ + void CollectNodes(const GraphData::NodeContainer& container, SerializationListeners& listeners) + { + for (auto& nodeEntity : container) + { + if (nodeEntity) + { + if (auto listener = azrtti_cast(AZ::EntityUtils::FindFirstDerivedComponent(nodeEntity))) + { + listeners.push_back(listener); + } + } + } + } +} + +namespace AZ +{ + AZ_CLASS_ALLOCATOR_IMPL(GraphDataSerializer, SystemAllocator, 0); + + JsonSerializationResult::Result GraphDataSerializer::Load + ( void* outputValue + , [[maybe_unused]] const Uuid& outputValueTypeId + , const rapidjson::Value& inputValue + , JsonDeserializerContext& context) + { + namespace JSR = JsonSerializationResult; + + AZ_Assert(outputValueTypeId == azrtti_typeid() + , "RuntimeVariableSerializer Load against output typeID that was not GraphData"); + AZ_Assert(outputValue, "RuntimeVariableSerializer Load against null output"); + context.GetMetadata().Add(SerializationListeners()); + JSR::ResultCode result(JSR::Tasks::ReadField); + result.Combine(ContinueLoading(outputValue, outputValueTypeId, inputValue, context, ContinuationFlags::NoTypeSerializer)); + auto listeners = context.GetMetadata().Find(); + AZ_Assert(listeners, "Failed to create SerializationListeners"); + GraphDataSerializerCpp::CollectNodes(reinterpret_cast(outputValue)->m_nodes, *listeners); + + for (auto listener : *listeners) + { + listener->OnDeserialize(); + } + + reinterpret_cast(outputValue)->OnDeserialized(); + + return context.Report(result, result.GetProcessing() != JSR::Processing::Halted + ? "GraphDataSerializer Load finished loading GraphData" + : "GraphDataSerializer Load failed to load GraphData"); + } + + JsonSerializationResult::Result GraphDataSerializer::Store + ( rapidjson::Value& outputValue + , const void* inputValue + , const void* defaultValue + , [[maybe_unused]] const Uuid& valueTypeId + , JsonSerializerContext& context) + { + namespace JSR = JsonSerializationResult; + + AZ_Assert(valueTypeId == azrtti_typeid() + , "RuntimeVariableSerializer Store against output typeID that was not GraphData"); + AZ_Assert(inputValue, "RuntimeVariableSerializer Store against null output"); + context.GetMetadata().Add(SerializationListeners()); + auto listeners = context.GetMetadata().Find(); + GraphDataSerializerCpp::CollectNodes(reinterpret_cast(inputValue)->m_nodes, *listeners); + + for (auto listener : *listeners) + { + listener->OnSerializeBegin(); + } + + JSR::ResultCode result(JSR::Tasks::WriteValue); + result.Combine(ContinueStoring(outputValue, inputValue, defaultValue, valueTypeId, context, ContinuationFlags::NoTypeSerializer)); + + for (auto listener : *listeners) + { + listener->OnSerializeEnd(); + } + + return context.Report(result, result.GetProcessing() != JSR::Processing::Halted + ? "GraphDataSerializer::Store finished storing GraphData" + : "GraphDataSerializer::Store failed to store GraphData"); + } +} diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Serialization/GraphDataSerializer.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Serialization/GraphDataSerializer.h new file mode 100644 index 0000000000..e7f91eccb3 --- /dev/null +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Serialization/GraphDataSerializer.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include + +namespace AZ +{ + class GraphDataSerializer + : public BaseJsonSerializer + { + public: + AZ_RTTI(GraphDataSerializer, "{2DFF5794-785F-4434-9314-52BB3EF1D00E}", BaseJsonSerializer); + AZ_CLASS_ALLOCATOR_DECL; + + private: + JsonSerializationResult::Result Load + ( void* outputValue + , const Uuid& outputValueTypeId + , const rapidjson::Value& inputValue + , JsonDeserializerContext& context) override; + + JsonSerializationResult::Result Store + ( rapidjson::Value& outputValue + , const void* inputValue + , const void* defaultValue + , const Uuid& valueTypeId, JsonSerializerContext& context) override; + }; +} diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Serialization/RuntimeVariableSerializer.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Serialization/RuntimeVariableSerializer.cpp index 763206df38..e03a5e4096 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Serialization/RuntimeVariableSerializer.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Serialization/RuntimeVariableSerializer.cpp @@ -50,6 +50,7 @@ namespace AZ } result.Combine(ContinueLoadingFromJsonObjectField(AZStd::any_cast(&outputVariable->value), typeId, inputValue, "value", context)); + return context.Report(result, result.GetProcessing() != JSR::Processing::Halted ? "RuntimeVariableSerializer Load finished loading RuntimeVariable" : "RuntimeVariableSerializer Load failed to load RuntimeVariable"); diff --git a/Gems/ScriptCanvas/Code/Source/SystemComponent.cpp b/Gems/ScriptCanvas/Code/Source/SystemComponent.cpp index 0a82b8cf2a..9069592755 100644 --- a/Gems/ScriptCanvas/Code/Source/SystemComponent.cpp +++ b/Gems/ScriptCanvas/Code/Source/SystemComponent.cpp @@ -7,7 +7,6 @@ */ #include - #include #include #include @@ -23,8 +22,9 @@ #include #include #include -#include #include +#include +#include #include #include @@ -59,6 +59,7 @@ namespace ScriptCanvas { void SystemComponent::Reflect(AZ::ReflectContext* context) { + VersionData::Reflect(context); Nodeable::Reflect(context); ReflectLibraries(context); @@ -88,13 +89,9 @@ namespace ScriptCanvas if (AZ::JsonRegistrationContext* jsonContext = azrtti_cast(context)) { - jsonContext->Serializer() - ->HandlesType() - ; - - jsonContext->Serializer() - ->HandlesType() - ; + jsonContext->Serializer()->HandlesType(); + jsonContext->Serializer()->HandlesType(); + jsonContext->Serializer()->HandlesType(); } #if defined(SC_EXECUTION_TRACE_ENABLED)