/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ScriptCanvasAssetHandlerCpp { using namespace ScriptCanvas; 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 ScriptCanvasEditor { ScriptCanvasAssetHandler::ScriptCanvasAssetHandler(AZ::SerializeContext* context) { SetSerializeContext(context); AZ::AssetTypeInfoBus::MultiHandler::BusConnect(GetAssetType()); } ScriptCanvasAssetHandler::~ScriptCanvasAssetHandler() { AZ::AssetTypeInfoBus::MultiHandler::BusDisconnect(); } AZ::Data::AssetPtr ScriptCanvasAssetHandler::CreateAsset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) { (void)type; auto assetData = aznew ScriptCanvasAsset(id); AZ::Entity* scriptCanvasEntity = aznew AZ::Entity("Script Canvas Graph"); SystemRequestBus::Broadcast(&SystemRequests::CreateEditorComponentsOnEntity, scriptCanvasEntity, azrtti_typeid()); assetData->SetScriptCanvasEntity(scriptCanvasEntity); return assetData; } // Override the stream info to force source assets to load into the Editor instead of cached, processed assets. void ScriptCanvasAssetHandler::GetCustomAssetStreamInfoForLoad(AZ::Data::AssetStreamInfo& streamInfo) { //ScriptCanvas files are source assets and should be placed in a source asset directory const char* assetPath = streamInfo.m_streamName.c_str(); if (AzFramework::StringFunc::Path::IsRelative(assetPath)) { AZStd::string watchFolder; bool sourceInfoFound{}; AZ::Data::AssetInfo assetInfo; AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, assetPath, assetInfo, watchFolder); if (sourceInfoFound) { AzFramework::StringFunc::Path::Join(watchFolder.data(), assetInfo.m_relativePath.data(), streamInfo.m_streamName); } } } AZ::Data::AssetHandler::LoadResult ScriptCanvasAssetHandler::LoadAssetData ( const AZ::Data::Asset& assetTarget , AZStd::shared_ptr streamSource , [[maybe_unused]] const AZ::Data::AssetFilterCB& assetLoadFilterCB) { namespace JSRU = AZ::JsonSerializationUtils; using namespace ScriptCanvas; auto* scriptCanvasAssetTarget = assetTarget.GetAs(); AZ_Assert(scriptCanvasAssetTarget, "This should be a ScriptCanvasAsset, as this is the only type we process!"); if (m_serializeContext && streamSource && scriptCanvasAssetTarget) { streamSource->Seek(0U, AZ::IO::GenericStream::ST_SEEK_BEGIN); auto& scriptCanvasDataTarget = scriptCanvasAssetTarget->GetScriptCanvasData(); AZStd::vector byteBuffer; byteBuffer.resize_no_construct(streamSource->GetLength()); AZ::IO::ByteContainerStream byteStreamSource(&byteBuffer); const size_t bytesRead = streamSource->Read(byteBuffer.size(), byteBuffer.data()); scriptCanvasDataTarget.m_scriptCanvasEntity.reset(nullptr); if (bytesRead == streamSource->GetLength()) { byteStreamSource.Seek(0U, AZ::IO::GenericStream::ST_SEEK_BEGIN); AZ::JsonDeserializerSettings settings; settings.m_serializeContext = m_serializeContext; settings.m_metadata.Create(); // attempt JSON deserialization... if (JSRU::LoadObjectFromStreamByType ( &scriptCanvasDataTarget , azrtti_typeid() , byteStreamSource , &settings).IsSuccess()) { if (auto graphData = scriptCanvasAssetTarget->GetScriptCanvasGraph() ? scriptCanvasAssetTarget->GetScriptCanvasGraph()->GetGraphData() : nullptr) { auto listeners = settings.m_metadata.Find(); AZ_Assert(listeners, "Failed to create SerializationListeners"); ScriptCanvasAssetHandlerCpp::CollectNodes(graphData->m_nodes, *listeners); for (auto listener : *listeners) { listener->OnDeserialize(); } return AZ::Data::AssetHandler::LoadResult::LoadComplete; } else { AZ_Warning("ScriptCanvas", false, "ScriptCanvasAssetHandler::LoadAssetData failed to load graph data from JOSON"); } } #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 , scriptCanvasDataTarget , m_serializeContext , AZ::ObjectStream::FilterDescriptor(assetLoadFilterCB, AZ::ObjectStream::FILTERFLAG_IGNORE_UNKNOWN_CLASSES))) { return AZ::Data::AssetHandler::LoadResult::LoadComplete; } } #endif//defined(OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED) } } return AZ::Data::AssetHandler::LoadResult::Error; } bool ScriptCanvasAssetHandler::SaveAssetData(const AZ::Data::Asset& asset, AZ::IO::GenericStream* stream) { return SaveAssetData(asset.GetAs(), stream); } bool ScriptCanvasAssetHandler::SaveAssetData(const ScriptCanvasAsset* assetData, AZ::IO::GenericStream* stream) { return SaveAssetData(assetData, stream, AZ::DataStream::ST_XML); } bool ScriptCanvasAssetHandler::SaveAssetData ( const ScriptCanvasAsset* assetData , AZ::IO::GenericStream* stream , [[maybe_unused]] AZ::DataStream::StreamType streamType) { namespace JSRU = AZ::JsonSerializationUtils; using namespace ScriptCanvas; if (m_serializeContext && stream && assetData && assetData->GetScriptCanvasGraph() && assetData->GetScriptCanvasGraph()->GetGraphData()) { auto graphData = assetData->GetScriptCanvasGraph()->GetGraphData(); AZ::JsonSerializerSettings settings; settings.m_metadata.Create(); auto listeners = settings.m_metadata.Find(); AZ_Assert(listeners, "Failed to create SerializationListeners"); ScriptCanvasAssetHandlerCpp::CollectNodes(graphData->m_nodes, *listeners); settings.m_keepDefaults = false; settings.m_serializeContext = m_serializeContext; for (auto listener : *listeners) { listener->OnSerialize(); } return JSRU::SaveObjectToStream(&assetData->GetScriptCanvasData(), *stream, nullptr, &settings).IsSuccess(); } else { AZ_Error("ScriptCanvas", false, "Saving ScriptCavas assets in the handler requires a valid IO stream, " "asset pointer, and serialize context"); return false; } } void ScriptCanvasAssetHandler::DestroyAsset(AZ::Data::AssetPtr ptr) { delete ptr; } AZ::SerializeContext* ScriptCanvasAssetHandler::GetSerializeContext() const { return m_serializeContext; } void ScriptCanvasAssetHandler::SetSerializeContext(AZ::SerializeContext* context) { m_serializeContext = context; if (m_serializeContext == nullptr) { // use the default app serialize context EBUS_EVENT_RESULT(m_serializeContext, AZ::ComponentApplicationBus, GetSerializeContext); if (!m_serializeContext) { AZ_Error("Script Canvas", false, "ScriptCanvasAssetHandler: No serialize context provided! " "We will not be able to process Graph Asset type"); } } } void ScriptCanvasAssetHandler::GetHandledAssetTypes(AZStd::vector& assetTypes) { assetTypes.push_back(GetAssetType()); } AZ::Data::AssetType ScriptCanvasAssetHandler::GetAssetType() const { return ScriptCanvasAssetHandler::GetAssetTypeStatic(); } const char* ScriptCanvasAssetHandler::GetAssetTypeDisplayName() const { return "Script Canvas"; } AZ::Data::AssetType ScriptCanvasAssetHandler::GetAssetTypeStatic() { return azrtti_typeid(); } void ScriptCanvasAssetHandler::GetAssetTypeExtensions(AZStd::vector& extensions) { ScriptCanvasAsset::Description description; extensions.push_back(description.GetExtensionImpl()); } AZ::Uuid ScriptCanvasAssetHandler::GetComponentTypeId() const { return azrtti_typeid(); } const char* ScriptCanvasAssetHandler::GetGroup() const { return ScriptCanvas::AssetDescription::GetGroup(); } const char* ScriptCanvasAssetHandler::GetBrowserIcon() const { return ScriptCanvas::AssetDescription::GetIconPath(); } }