/* * 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 namespace ScriptCanvasFileHandlingCpp { 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 { AZ::Outcome LoadDataFromJson ( ScriptCanvas::ScriptCanvasData& dataTarget , AZStd::string_view source , AZ::SerializeContext& serializeContext) { namespace JSRU = AZ::JsonSerializationUtils; using namespace ScriptCanvas; AZ::JsonDeserializerSettings settings; settings.m_serializeContext = &serializeContext; settings.m_metadata.Create(); auto loadResult = JSRU::LoadObjectFromStringByType ( &dataTarget , azrtti_typeid() , source , &settings); if (!loadResult.IsSuccess()) { return loadResult; } if (auto graphData = dataTarget.ModGraph()) { auto listeners = settings.m_metadata.Find(); AZ_Assert(listeners, "Failed to find SerializationListeners"); ScriptCanvasFileHandlingCpp::CollectNodes(graphData->GetGraphData()->m_nodes, *listeners); for (auto listener : *listeners) { listener->OnDeserialize(); } } else { return AZ::Failure(AZStd::string("Failed to find graph data after loading source")); } return AZ::Success(); } AZ::Outcome LoadFromFile(AZStd::string_view path) { namespace JSRU = AZ::JsonSerializationUtils; using namespace ScriptCanvas; auto fileStringOutcome = AZ::Utils::ReadFile(path); if (!fileStringOutcome) { return AZ::Failure(fileStringOutcome.TakeError()); } const auto& asString = fileStringOutcome.GetValue(); DataPtr scriptCanvasData = AZStd::make_shared(); if (!scriptCanvasData) { return AZ::Failure(AZStd::string("failed to allocate ScriptCanvas::ScriptCanvasData after loading source file")); } AZ::SerializeContext* serializeContext = nullptr; AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext); if (!serializeContext) { return AZ::Failure(AZStd::string("no serialize context available to properly parse source file")); } // attempt JSON deserialization... auto jsonResult = LoadDataFromJson(*scriptCanvasData, AZStd::string_view{ asString.begin(), asString.size() }, *serializeContext); if (!jsonResult.IsSuccess()) { // ...try legacy xml as a failsafe AZ::IO::ByteContainerStream byteStream(&asString); if (!AZ::Utils::LoadObjectFromStreamInPlace ( byteStream , *scriptCanvasData , serializeContext , AZ::ObjectStream::FilterDescriptor(nullptr, AZ::ObjectStream::FILTERFLAG_IGNORE_UNKNOWN_CLASSES))) { return AZ::Failure(AZStd::string::format("XML and JSON load attempts failed: %s", jsonResult.GetError().c_str())); } } if (auto entity = scriptCanvasData->GetScriptCanvasEntity()) { entity->Init(); entity->Activate(); auto graph = entity->FindComponent(); graph->MarkOwnership(*scriptCanvasData); } return AZ::Success(ScriptCanvasEditor::SourceHandle(scriptCanvasData, {}, path)); } AZ::Outcome SaveToStream(const SourceHandle& source, AZ::IO::GenericStream& stream) { namespace JSRU = AZ::JsonSerializationUtils; if (!source.IsValid()) { return AZ::Failure(AZStd::string("no source graph to save")); } if (source.Path().empty()) { return AZ::Failure(AZStd::string("no destination path specified")); } AZ::SerializeContext* serializeContext = nullptr; AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext); if (!serializeContext) { return AZ::Failure(AZStd::string("no serialize context available to properly save source file")); } auto graphData = source.Get()->GetOwnership(); if (!graphData) { return AZ::Failure(AZStd::string("source is missing save container")); } if (graphData->GetEditorGraph() != source.Get()) { return AZ::Failure(AZStd::string("source save container refers to incorrect graph")); } auto saveTarget = graphData->ModGraph(); if (!saveTarget || !saveTarget->GetGraphData()) { return AZ::Failure(AZStd::string("source save container failed to return serializable graph data")); } AZ::JsonSerializerSettings settings; settings.m_metadata.Create(); auto listeners = settings.m_metadata.Find(); AZ_Assert(listeners, "Failed to create SerializationListeners"); ScriptCanvasFileHandlingCpp::CollectNodes(saveTarget->GetGraphData()->m_nodes, *listeners); settings.m_keepDefaults = false; settings.m_serializeContext = serializeContext; for (auto listener : *listeners) { listener->OnSerialize(); } auto saveOutcome = JSRU::SaveObjectToStream(graphData, stream, nullptr, &settings); if (!saveOutcome.IsSuccess()) { AZStd::string result = saveOutcome.TakeError(); return AZ::Failure(AZStd::string("JSON serialization failed to save source: %s", result.c_str())); } return AZ::Success(); } }