From 0b646ac69334208ace26dfb25457242c9d59ab49 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Thu, 14 Oct 2021 09:06:54 -0700 Subject: [PATCH 001/128] initial scriptcanvas source handle Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Utils/Utils.cpp | 5 +- .../Builder/ScriptCanvasBuilderWorker.cpp | 116 ++++----- .../Code/Builder/ScriptCanvasBuilderWorker.h | 5 +- .../Assets/ScriptCanvasAssetHandler.cpp | 46 +--- .../Assets/ScriptCanvasFileHandling.cpp | 129 ++++++++++ .../Editor/Assets/ScriptCanvasMemoryAsset.h | 1 - .../Code/Editor/Components/EditorGraph.cpp | 19 ++ .../Assets/ScriptCanvasAssetHandler.h | 5 - .../Assets/ScriptCanvasBaseAssetData.cpp | 14 +- .../Assets/ScriptCanvasBaseAssetData.h | 6 +- .../Assets/ScriptCanvasFileHandling.h | 35 +++ .../Assets/ScriptCanvasSourceFileHandle.cpp | 61 +++++ .../Assets/ScriptCanvasSourceFileHandle.h | 47 ++++ .../Include/ScriptCanvas/Bus/RequestBus.h | 2 +- .../ScriptCanvas/Components/EditorGraph.h | 2 + .../Code/Editor/View/Windows/MainWindow.cpp | 239 ++++++++++-------- .../Code/Editor/View/Windows/MainWindow.h | 95 ++++--- .../Asset/ScriptCanvasAssetBase.h | 3 +- .../Code/Include/ScriptCanvas/Core/Core.h | 24 ++ .../Code/Include/ScriptCanvas/Core/Graph.h | 4 +- .../Code/scriptcanvasgem_editor_files.cmake | 4 + 21 files changed, 579 insertions(+), 283 deletions(-) create mode 100644 Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp create mode 100644 Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h create mode 100644 Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.cpp create mode 100644 Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.h diff --git a/Code/Framework/AzCore/AzCore/Utils/Utils.cpp b/Code/Framework/AzCore/AzCore/Utils/Utils.cpp index 2031d14d08..1534374a90 100644 --- a/Code/Framework/AzCore/AzCore/Utils/Utils.cpp +++ b/Code/Framework/AzCore/AzCore/Utils/Utils.cpp @@ -165,13 +165,12 @@ namespace AZ::Utils } Container fileContent; - fileContent.resize(length); + fileContent.resize_no_construct(length); AZ::IO::SizeType bytesRead = file.Read(length, fileContent.data()); file.Close(); // Resize again just in case bytesRead is less than length for some reason - fileContent.resize(bytesRead); - + fileContent.resize_no_construct(bytesRead); return AZ::Success(AZStd::move(fileContent)); } diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp index f474c10532..7a7dbfff0b 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp @@ -16,9 +16,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -44,54 +46,73 @@ namespace ScriptCanvasBuilder AzFramework::StringFunc::Path::ConstructFull(request.m_watchFolder.data(), request.m_sourceFile.data(), fullPath, false); AzFramework::StringFunc::Path::Normalize(fullPath); - if (!m_editorAssetHandler) + AZ::Data::Asset asset; + const ScriptCanvasEditor::Graph* sourceGraph = nullptr; + const ScriptCanvas::GraphData* graphData = nullptr; + + ScriptCanvasEditor::SourceHandle sourceHandle; + + auto sourceOutcome = ScriptCanvasEditor::LoadFromFile(fullPath); + if (sourceOutcome.IsSuccess()) { - AZ_Error(s_scriptCanvasBuilder, false, R"(CreateJobs for %s failed because the ScriptCanvas Editor Asset handler is missing.)", fullPath.data()); + sourceHandle = sourceOutcome.TakeValue(); + sourceGraph = sourceHandle.Get(); + graphData = sourceGraph->GetGraphDataConst(); } - - AZStd::shared_ptr assetDataStream = AZStd::make_shared(); - - AZ::IO::FileIOStream stream(fullPath.c_str(), AZ::IO::OpenMode::ModeRead); - if (!AZ::IO::RetryOpenStream(stream)) + +#if defined(EDITOR_ASSET_SUPPORT_ENABLED) + if (graphData == nullptr) { - AZ_Warning(s_scriptCanvasBuilder, false, "CreateJobs for \"%s\" failed because the source file could not be opened.", fullPath.data()); - return; - } + if (!m_editorAssetHandler) + { + AZ_Error(s_scriptCanvasBuilder, false, R"(CreateJobs for %s failed because the ScriptCanvas Editor Asset handler is missing.)", fullPath.data()); + } - // Read the asset into a memory buffer, then hand ownership of the buffer to assetDataStream - { - AZ::IO::FileIOStream ioStream; - if (!ioStream.Open(fullPath.data(), AZ::IO::OpenMode::ModeRead)) + AZStd::shared_ptr assetDataStream = AZStd::make_shared(); + + AZ::IO::FileIOStream stream(fullPath.c_str(), AZ::IO::OpenMode::ModeRead); + if (!AZ::IO::RetryOpenStream(stream)) { AZ_Warning(s_scriptCanvasBuilder, false, "CreateJobs for \"%s\" failed because the source file could not be opened.", fullPath.data()); return; } - AZStd::vector fileBuffer(ioStream.GetLength()); - size_t bytesRead = ioStream.Read(fileBuffer.size(), fileBuffer.data()); - if (bytesRead != ioStream.GetLength()) + // Read the asset into a memory buffer, then hand ownership of the buffer to assetDataStream { - AZ_Warning(s_scriptCanvasBuilder, false, AZStd::string::format("File failed to read completely: %s", fullPath.data()).c_str()); + AZ::IO::FileIOStream ioStream; + if (!ioStream.Open(fullPath.data(), AZ::IO::OpenMode::ModeRead)) + { + AZ_Warning(s_scriptCanvasBuilder, false, "CreateJobs for \"%s\" failed because the source file could not be opened.", fullPath.data()); + return; + } + + AZStd::vector fileBuffer(ioStream.GetLength()); + size_t bytesRead = ioStream.Read(fileBuffer.size(), fileBuffer.data()); + if (bytesRead != ioStream.GetLength()) + { + AZ_Warning(s_scriptCanvasBuilder, false, AZStd::string::format("File failed to read completely: %s", fullPath.data()).c_str()); + return; + } + + assetDataStream->Open(AZStd::move(fileBuffer)); + } + + m_processEditorAssetDependencies.clear(); + + asset.Create(AZ::Data::AssetId(AZ::Uuid::CreateRandom())); + if (m_editorAssetHandler->LoadAssetDataFromStream(asset, assetDataStream, {}) != AZ::Data::AssetHandler::LoadResult::LoadComplete) + { + AZ_Warning(s_scriptCanvasBuilder, false, "CreateJobs for \"%s\" failed because the asset data could not be loaded from the file", fullPath.data()); return; } - assetDataStream->Open(AZStd::move(fileBuffer)); + sourceGraph = AZ::EntityUtils::FindFirstDerivedComponent(asset.Get()->GetScriptCanvasEntity()); + graphData = sourceGraph->GetGraphDataConst(); } +#endif - m_processEditorAssetDependencies.clear(); - - AZ::Data::Asset asset; - asset.Create(AZ::Data::AssetId(AZ::Uuid::CreateRandom())); - if (m_editorAssetHandler->LoadAssetDataFromStream(asset, assetDataStream, {}) != AZ::Data::AssetHandler::LoadResult::LoadComplete) - { - AZ_Warning(s_scriptCanvasBuilder, false, "CreateJobs for \"%s\" failed because the asset data could not be loaded from the file", fullPath.data()); - return; - } - - auto* scriptCanvasEntity = asset.Get()->GetScriptCanvasEntity(); - auto* sourceGraph = AZ::EntityUtils::FindFirstDerivedComponent(scriptCanvasEntity); AZ_Assert(sourceGraph, "Graph component is missing from entity."); - AZ_Assert(sourceGraph->GetGraphData(), "GraphData is missing from entity"); + AZ_Assert(graphData, "GraphData is missing from entity"); struct EntityIdComparer { @@ -102,7 +123,7 @@ namespace ScriptCanvasBuilder return lhsEntityId < rhsEntityId; } }; - const AZStd::set sortedEntities(sourceGraph->GetGraphData()->m_nodes.begin(), sourceGraph->GetGraphData()->m_nodes.end()); + const AZStd::set sortedEntities(graphData->m_nodes.begin(), graphData->m_nodes.end()); size_t fingerprint = 0; for (const auto& nodeEntity : sortedEntities) @@ -155,7 +176,7 @@ namespace ScriptCanvasBuilder }; AZ_Verify(serializeContext->EnumerateInstanceConst - ( sourceGraph->GetGraphData() + ( graphData , azrtti_typeid() , assetFilter , {} @@ -168,17 +189,6 @@ namespace ScriptCanvasBuilder for (const AssetBuilderSDK::PlatformInfo& info : request.m_enabledPlatforms) { - if (info.HasTag("tools")) - { - AssetBuilderSDK::JobDescriptor copyDescriptor; - copyDescriptor.m_priority = 2; - copyDescriptor.m_critical = true; - copyDescriptor.m_jobKey = s_scriptCanvasCopyJobKey; - copyDescriptor.SetPlatformIdentifier(info.m_identifier.c_str()); - copyDescriptor.m_additionalFingerprintInfo = AZStd::string(GetFingerprintString()).append("|").append(AZStd::to_string(static_cast(fingerprint))); - response.m_createJobOutputs.push_back(copyDescriptor); - } - AssetBuilderSDK::JobDescriptor jobDescriptor; jobDescriptor.m_priority = 2; jobDescriptor.m_critical = true; @@ -299,23 +309,9 @@ namespace ScriptCanvasBuilder AzFramework::StringFunc::Path::Join(request.m_tempDirPath.c_str(), fileNameOnly.c_str(), runtimeScriptCanvasOutputPath, true, true); AzFramework::StringFunc::Path::ReplaceExtension(runtimeScriptCanvasOutputPath, ScriptCanvas::RuntimeAsset::GetFileExtension()); - if (request.m_jobDescription.m_jobKey == s_scriptCanvasCopyJobKey) - { - // ScriptCanvas Editor Asset Copy job - // The SubID is zero as this represents the main asset - AssetBuilderSDK::JobProduct jobProduct; - jobProduct.m_productFileName = fullPath; - jobProduct.m_productAssetType = azrtti_typeid(); - jobProduct.m_productSubID = 0; - jobProduct.m_dependenciesHandled = true; - jobProduct.m_dependencies.clear(); - response.m_outputProducts.push_back(AZStd::move(jobProduct)); - response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success; - } - else + if (request.m_jobDescription.m_jobKey == s_scriptCanvasProcessJobKey) { AZ::Entity* buildEntity = asset.Get()->GetScriptCanvasEntity(); - ProcessTranslationJobInput input; input.assetID = AZ::Data::AssetId(request.m_sourceFileUUID, AZ_CRC("RuntimeData", 0x163310ae)); input.request = &request; diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h index 668e1a0bcd..84c9285362 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h @@ -42,7 +42,6 @@ namespace ScriptCanvasEditor namespace ScriptCanvasBuilder { constexpr const char* s_scriptCanvasBuilder = "ScriptCanvasBuilder"; - constexpr const char* s_scriptCanvasCopyJobKey = "Script Canvas Copy Job"; constexpr const char* s_scriptCanvasProcessJobKey = "Script Canvas Process Job"; constexpr const char* s_unitTestParseErrorPrefix = "LY_SC_UnitTest"; @@ -59,6 +58,10 @@ namespace ScriptCanvasBuilder PrefabIntegration, CorrectGraphVariableVersion, ReflectEntityIdNodes, + + ForceBuildForDevTest0, + ForceBuildForDevTest1, + // add new entries above Current, }; diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHandler.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHandler.cpp index dea63ab852..bac1f770cb 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHandler.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHandler.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -93,49 +94,6 @@ namespace ScriptCanvasEditor } } - AZ::Outcome LoadScriptCanvasDataFromJson - ( 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"); - - ScriptCanvasAssetHandlerCpp::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::Data::AssetHandler::LoadResult ScriptCanvasAssetHandler::LoadAssetData ( const AZ::Data::Asset& assetTarget , AZStd::shared_ptr streamSource @@ -167,7 +125,7 @@ namespace ScriptCanvasEditor settings.m_serializeContext = m_serializeContext; settings.m_metadata.Create(); // attempt JSON deserialization... - auto jsonResult = LoadScriptCanvasDataFromJson + auto jsonResult = LoadDataFromJson ( scriptCanvasDataTarget , AZStd::string_view{ byteBuffer.begin(), byteBuffer.size() } , *m_serializeContext); diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp new file mode 100644 index 0000000000..c21f01bb88 --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp @@ -0,0 +1,129 @@ +/* + * 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 = Graph::Create(); + + 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())); + } + } + + return AZ::Success(ScriptCanvasEditor::SourceHandle(scriptCanvasData, {}, path)); + } +} diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.h b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.h index 9665e8ec64..d7f6ae87b6 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.h +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.h @@ -172,7 +172,6 @@ namespace ScriptCanvasEditor bool IsSourceInError() const; - void OnSourceAssetFinalized(const AZStd::string& fullPath, AZ::Uuid sourceAssetId); void SavingComplete(const AZStd::string& fullPath, AZ::Uuid sourceAssetId); AZ::Data::AssetId GetSourceUuid() const { return m_sourceUuid; } diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp index f003618c03..d1af67e8e0 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp @@ -76,6 +76,7 @@ AZ_POP_DISABLE_WARNING #include #include #include +#include #include #include #include @@ -1040,6 +1041,24 @@ namespace ScriptCanvasEditor } } + ScriptCanvas::DataPtr Graph::Create() + { + if (AZ::Entity* entity = aznew AZ::Entity("Script Canvas Graph")) + { + auto graph = entity->CreateComponent(); + graph->SetAssetType(azrtti_typeid()); + entity->CreateComponent(graph->GetScriptCanvasId()); + + if (ScriptCanvas::DataPtr data = AZStd::make_shared()) + { + data->m_scriptCanvasEntity.reset(entity); + return data; + } + } + + return nullptr; + } + bool Graph::CreateConnection(const GraphCanvas::ConnectionId& connectionId, const GraphCanvas::Endpoint& sourcePoint, const GraphCanvas::Endpoint& targetPoint) { if (!sourcePoint.IsValid() || !targetPoint.IsValid()) diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasAssetHandler.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasAssetHandler.h index f29d5aa9cb..a0e00b40fd 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasAssetHandler.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasAssetHandler.h @@ -20,11 +20,6 @@ namespace AZ namespace ScriptCanvasEditor { - AZ::Outcome LoadScriptCanvasDataFromJson - ( ScriptCanvas::ScriptCanvasData& dataTarget - , AZStd::string_view source - , AZ::SerializeContext& serializeContext); - /** * Manages editor Script Canvas graph assets. */ diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.cpp b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.cpp index 6da134ed6a..2b451b0de8 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.cpp @@ -11,13 +11,23 @@ namespace ScriptCanvas { + const Graph* ScriptCanvasData::GetGraph() const + { + return AZ::EntityUtils::FindFirstDerivedComponent(m_scriptCanvasEntity.get()); + } + + const ScriptCanvasEditor::Graph* ScriptCanvasData::GetEditorGraph() const + { + return AZ::EntityUtils::FindFirstDerivedComponent(m_scriptCanvasEntity.get()); + } + Graph* ScriptCanvasData::ModGraph() { return AZ::EntityUtils::FindFirstDerivedComponent(m_scriptCanvasEntity.get()); } - const Graph* ScriptCanvasData::GetGraph() const + ScriptCanvasEditor::Graph* ScriptCanvasData::ModEditorGraph() { - return AZ::EntityUtils::FindFirstDerivedComponent(m_scriptCanvasEntity.get()); + return AZ::EntityUtils::FindFirstDerivedComponent(m_scriptCanvasEntity.get()); } } diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.h index f4b02b56b6..5340f1128a 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.h @@ -28,9 +28,13 @@ namespace ScriptCanvas AZ::Entity* GetScriptCanvasEntity() const { return m_scriptCanvasEntity.get(); } + const Graph* GetGraph() const; + + const ScriptCanvasEditor::Graph* GetEditorGraph() const; + Graph* ModGraph(); - const Graph* GetGraph() const; + ScriptCanvasEditor::Graph* ModEditorGraph(); AZStd::unique_ptr m_scriptCanvasEntity; private: diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h new file mode 100644 index 0000000000..154ff5f2b0 --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h @@ -0,0 +1,35 @@ +/* + * 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 +#include +#include + +namespace AZ +{ + class SerializeContext; +} + +namespace ScriptCanvas +{ + class ScriptCanvasData; +} + +namespace ScriptCanvasEditor +{ + AZ::Outcome LoadFromFile(AZStd::string_view path); + + AZ::Outcome LoadDataFromJson + ( ScriptCanvas::ScriptCanvasData& dataTarget + , AZStd::string_view source + , AZ::SerializeContext& serializeContext); + } diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.cpp b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.cpp new file mode 100644 index 0000000000..e6ed773e83 --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.cpp @@ -0,0 +1,61 @@ +/* + * 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 + +namespace ScriptCanvasEditor +{ + SourceHandle::SourceHandle(ScriptCanvas::DataPtr graph, const AZ::Uuid& id, AZStd::string_view path) + : m_data(graph) + , m_id(id) + , m_path(path) + {} + + void SourceHandle::Clear() + { + m_data = nullptr; + m_id = AZ::Uuid::CreateNull(); + m_path.clear(); + } + + GraphPtrConst SourceHandle::Get() const + { + return m_data ? m_data->GetEditorGraph() : nullptr; + } + + const AZ::Uuid& SourceHandle::Id() const + { + return m_id; + } + + bool SourceHandle::IsValid() const + { + return *this; + } + + GraphPtr SourceHandle::Mod() const + { + return m_data ? m_data->ModEditorGraph() : nullptr; + } + + SourceHandle::operator bool() const + { + return m_data != nullptr; + } + + bool SourceHandle::operator!() const + { + return m_data == nullptr; + } + + const AZStd::string& SourceHandle::Path() const + { + return m_path; + } +} diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.h new file mode 100644 index 0000000000..045221310a --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.h @@ -0,0 +1,47 @@ +/* + * 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 + +namespace ScriptCanvasEditor +{ + class SourceHandle + { + public: + AZ_TYPE_INFO(SourceHandle, "{65855A98-AE2F-427F-BFC8-69D45265E312}"); + AZ_CLASS_ALLOCATOR(SourceHandle, AZ::SystemAllocator, 0); + + SourceHandle() = default; + + SourceHandle(ScriptCanvas::DataPtr graph, const AZ::Uuid& id, AZStd::string_view path); + + void Clear(); + + GraphPtrConst Get() const; + + const AZ::Uuid& Id() const; + + bool IsValid() const; + + GraphPtr Mod() const; + + operator bool() const; + + bool operator!() const; + + const AZStd::string& Path() const; + + private: + ScriptCanvas::DataPtr m_data; + AZ::Uuid m_id = AZ::Uuid::CreateNull(); + AZStd::string m_path; + }; +} diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h index 8fa7beab2b..dedfdd8d20 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h @@ -126,7 +126,7 @@ namespace ScriptCanvasEditor virtual void DisconnectEndpoints(const AZ::EntityId& /*sceneId*/, const AZStd::vector& /*endpoints*/) {} virtual void PostUndoPoint(ScriptCanvas::ScriptCanvasId) = 0; - virtual void SignalSceneDirty(AZ::Data::AssetId) = 0; + virtual void SignalSceneDirty(SourceHandle) = 0; // Increment the value of the ignore undo point tracker virtual void PushPreventUndoStateUpdate() = 0; diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h index 6f73e84493..cfd7d7ec8c 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h @@ -101,6 +101,8 @@ namespace ScriptCanvasEditor public: AZ_COMPONENT(Graph, "{4D755CA9-AB92-462C-B24F-0B3376F19967}", ScriptCanvas::Graph); + static ScriptCanvas::DataPtr Create(); + static void Reflect(AZ::ReflectContext* context); Graph(const ScriptCanvas::ScriptCanvasId& scriptCanvasId = AZ::Entity::MakeId()) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index 1ad8b58317..8be4c1db06 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -135,6 +135,7 @@ #include #include #include +#include #include @@ -235,7 +236,7 @@ namespace ScriptCanvasEditor Widget::GraphTabBar* tabBar = m_mainWindow->m_tabBar; AZStd::vector activeAssets; - AZ::Data::AssetId focusedAssetId = tabBar->FindAssetId(tabBar->currentIndex()); + ScriptCanvasEditor::SourceHandle focusedAssetId = tabBar->FindAssetId(tabBar->currentIndex()); if (m_rememberOpenCanvases) { @@ -243,13 +244,13 @@ namespace ScriptCanvasEditor for (int i = 0; i < tabBar->count(); ++i) { - AZ::Data::AssetId assetId = tabBar->FindAssetId(i); + ScriptCanvasEditor::SourceHandle assetId = tabBar->FindAssetId(i); const Tracker::ScriptCanvasFileState& fileState = m_mainWindow->GetAssetFileState(assetId); if (fileState == Tracker::ScriptCanvasFileState::MODIFIED || fileState == Tracker::ScriptCanvasFileState::UNMODIFIED) { - AZ::Data::AssetId sourceId = GetSourceAssetId(assetId); + ScriptCanvasEditor::SourceHandle sourceId = GetSourceAssetId(assetId); if (sourceId.IsValid()) { EditorSettings::EditorWorkspace::WorkspaceAssetSaveData assetSaveData; @@ -316,7 +317,7 @@ namespace ScriptCanvasEditor if (m_loadingAssets.empty()) { - m_mainWindow->OnWorkspaceRestoreEnd(AZ::Data::AssetId()); + m_mainWindow->OnWorkspaceRestoreEnd(ScriptCanvasEditor::SourceHandle()); } else { @@ -336,7 +337,7 @@ namespace ScriptCanvasEditor { if (assetSaveData.m_assetId == m_queuedAssetFocus) { - m_queuedAssetFocus = AZ::Data::AssetId(); + m_queuedAssetFocus = ScriptCanvasEditor::SourceHandle(); } SignalAssetComplete(asset.GetFileAssetId()); @@ -350,7 +351,7 @@ namespace ScriptCanvasEditor { if (assetSaveData.m_assetId == m_queuedAssetFocus) { - m_queuedAssetFocus = AZ::Data::AssetId(); + m_queuedAssetFocus = ScriptCanvasEditor::SourceHandle(); } SignalAssetComplete(assetSaveData.m_assetId); @@ -359,14 +360,14 @@ namespace ScriptCanvasEditor } else { - m_mainWindow->OnWorkspaceRestoreEnd(AZ::Data::AssetId()); + m_mainWindow->OnWorkspaceRestoreEnd(ScriptCanvasEditor::SourceHandle()); } } } void Workspace::OnAssetReady(const ScriptCanvasMemoryAsset::pointer memoryAsset) { - const AZ::Data::AssetId& fileAssetId = memoryAsset->GetFileAssetId(); + const ScriptCanvasEditor::SourceHandle& fileAssetId = memoryAsset->GetFileAssetId(); if (AssetTrackerNotificationBus::MultiHandler::BusIsConnectedId(fileAssetId)) { @@ -378,7 +379,7 @@ namespace ScriptCanvasEditor } } - void Workspace::SignalAssetComplete(const AZ::Data::AssetId& fileAssetId) + void Workspace::SignalAssetComplete(const ScriptCanvasEditor::SourceHandle& fileAssetId) { auto it = AZStd::find(m_loadingAssets.begin(), m_loadingAssets.end(), fileAssetId); if (it != m_loadingAssets.end()) @@ -394,7 +395,7 @@ namespace ScriptCanvasEditor } } - AZ::Data::AssetId Workspace::GetSourceAssetId(const AZ::Data::AssetId& memoryAssetId) const + ScriptCanvasEditor::SourceHandle Workspace::GetSourceAssetId(const ScriptCanvasEditor::SourceHandle& memoryAssetId) const { ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, memoryAssetId); @@ -404,7 +405,7 @@ namespace ScriptCanvasEditor return memoryAsset->GetFileAssetId(); } - return AZ::Data::AssetId(); + return ScriptCanvasEditor::SourceHandle(); } //////////////// @@ -653,9 +654,9 @@ namespace ScriptCanvasEditor QTimer::singleShot(0, [this]() { SetDefaultLayout(); - if (m_activeAssetId.IsValid()) + if (m_activeGraph.IsValid()) { - m_queuedFocusOverride = m_activeAssetId; + m_queuedFocusOverride = m_activeGraph; } m_workspace->Restore(); @@ -829,7 +830,7 @@ namespace ScriptCanvasEditor connect(ui->action_ViewRestoreDefaultLayout, &QAction::triggered, this, &MainWindow::OnRestoreDefaultLayout); } - void MainWindow::SignalActiveSceneChanged(AZ::Data::AssetId assetId) + void MainWindow::SignalActiveSceneChanged(ScriptCanvasEditor::SourceHandle assetId) { ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); @@ -925,7 +926,7 @@ namespace ScriptCanvasEditor for (int tabCounter = 0; tabCounter < m_tabBar->count(); ++tabCounter) { - AZ::Data::AssetId assetId = m_tabBar->FindAssetId(tabCounter); + ScriptCanvasEditor::SourceHandle assetId = m_tabBar->FindAssetId(tabCounter); auto resultIterator = m_processedClosedAssetIds.insert(assetId); if (!resultIterator.second) @@ -948,7 +949,7 @@ namespace ScriptCanvasEditor if (shouldSaveResults == UnsavedChangesOptions::SAVE) { - Callbacks::OnSave saveCB = [this](bool isSuccessful, AZ::Data::AssetPtr, AZ::Data::AssetId) + Callbacks::OnSave saveCB = [this](bool isSuccessful, AZ::Data::AssetPtr, ScriptCanvasEditor::SourceHandle) { if (isSuccessful) { @@ -990,7 +991,7 @@ namespace ScriptCanvasEditor for (auto trackedAsset : allAssets) { - const AZ::Data::AssetId& assetId = trackedAsset->GetAsset().GetId(); + const ScriptCanvasEditor::SourceHandle& assetId = trackedAsset->GetAsset().GetId(); CloseScriptCanvasAsset(assetId); } @@ -1030,7 +1031,7 @@ namespace ScriptCanvasEditor DequeuePropertyGridUpdate(); UndoRequestBus::Event(GetActiveScriptCanvasId(), &UndoRequests::Undo); - SignalSceneDirty(m_activeAssetId); + SignalSceneDirty(m_activeGraph); m_propertyGrid->ClearSelection(); GeneralEditorNotificationBus::Event(GetActiveScriptCanvasId(), &GeneralEditorNotifications::OnUndoRedoEnd); @@ -1042,7 +1043,7 @@ namespace ScriptCanvasEditor DequeuePropertyGridUpdate(); UndoRequestBus::Event(GetActiveScriptCanvasId(), &UndoRequests::Redo); - SignalSceneDirty(m_activeAssetId); + SignalSceneDirty(m_activeGraph); m_propertyGrid->ClearSelection(); GeneralEditorNotificationBus::Event(GetActiveScriptCanvasId(), &GeneralEditorNotifications::OnUndoRedoEnd); @@ -1115,14 +1116,14 @@ namespace ScriptCanvasEditor { ScopedUndoBatch scopedUndoBatch("Modify Graph Canvas Scene"); UndoRequestBus::Event(scriptCanvasId, &UndoRequests::AddGraphItemChangeUndo, "Graph Change"); - MarkAssetModified(m_activeAssetId); + MarkAssetModified(m_activeGraph); } const bool forceTimer = true; RestartAutoTimerSave(forceTimer); } - void MainWindow::SignalSceneDirty(AZ::Data::AssetId assetId) + void MainWindow::SignalSceneDirty(ScriptCanvasEditor::SourceHandle assetId) { MarkAssetModified(assetId); } @@ -1145,7 +1146,7 @@ namespace ScriptCanvasEditor m_preventUndoStateUpdateCount = 0; } - void MainWindow::MarkAssetModified(const AZ::Data::AssetId& assetId) + void MainWindow::MarkAssetModified(const ScriptCanvasEditor::SourceHandle& assetId) { if (!assetId.IsValid()) { @@ -1198,7 +1199,7 @@ namespace ScriptCanvasEditor } } - AZ::Outcome MainWindow::OpenScriptCanvasAssetId(const AZ::Data::AssetId& fileAssetId) + AZ::Outcome MainWindow::OpenScriptCanvasAssetId(const ScriptCanvasEditor::SourceHandle& fileAssetId) { if (!fileAssetId.IsValid()) { @@ -1262,7 +1263,7 @@ namespace ScriptCanvasEditor AZ::Outcome MainWindow::OpenScriptCanvasAsset(const ScriptCanvasMemoryAsset& scriptCanvasAsset, int tabIndex /*= -1*/) { - const AZ::Data::AssetId& fileAssetId = scriptCanvasAsset.GetFileAssetId(); + const ScriptCanvasEditor::SourceHandle& fileAssetId = scriptCanvasAsset.GetFileAssetId(); if (!fileAssetId.IsValid()) { return AZ::Failure(AZStd::string("Unable to open asset with invalid asset id")); @@ -1335,7 +1336,7 @@ namespace ScriptCanvasEditor return AZ::Success(outTabIndex); } - AZ::Outcome MainWindow::OpenScriptCanvasAsset(AZ::Data::AssetId scriptCanvasAssetId, int tabIndex /*= -1*/) + AZ::Outcome MainWindow::OpenScriptCanvasAsset(ScriptCanvasEditor::SourceHandle scriptCanvasAssetId, int tabIndex /*= -1*/) { ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, scriptCanvasAssetId); @@ -1351,7 +1352,7 @@ namespace ScriptCanvasEditor } } - int MainWindow::CreateAssetTab(const AZ::Data::AssetId& assetId, int tabIndex) + int MainWindow::CreateAssetTab(const ScriptCanvasEditor::SourceHandle& assetId, int tabIndex) { return m_tabBar->InsertGraphTab(tabIndex, assetId); } @@ -1376,7 +1377,7 @@ namespace ScriptCanvasEditor return AZ::Success(outTabIndex); } - void MainWindow::RemoveScriptCanvasAsset(const AZ::Data::AssetId& assetId) + void MainWindow::RemoveScriptCanvasAsset(const ScriptCanvasEditor::SourceHandle& assetId) { AssetHelpers::PrintInfo("RemoveScriptCanvasAsset : %s", AssetHelpers::AssetIdToString(assetId).c_str()); @@ -1402,13 +1403,13 @@ namespace ScriptCanvasEditor QVariant tabdata = m_tabBar->tabData(tabIndex); if (tabdata.isValid()) { - auto tabAssetId = tabdata.value(); + auto tabAssetId = tabdata.value(); SetActiveAsset(tabAssetId); } } - int MainWindow::CloseScriptCanvasAsset(const AZ::Data::AssetId& assetId) + int MainWindow::CloseScriptCanvasAsset(const ScriptCanvasEditor::SourceHandle& assetId) { int tabIndex = -1; if (IsTabOpen(assetId, tabIndex)) @@ -1429,26 +1430,26 @@ namespace ScriptCanvasEditor } } - AZ::Data::AssetId previousAssetId = m_activeAssetId; + ScriptCanvasEditor::SourceHandle previousAssetId = m_activeGraph; OnFileNew(); - bool createdNewAsset = m_activeAssetId != previousAssetId; + bool createdNewAsset = m_activeGraph != previousAssetId; if (createdNewAsset) { - m_assetCreationRequests[m_activeAssetId] = requestingEntityId; + m_assetCreationRequests[m_activeGraph] = requestingEntityId; } if (m_isRestoringWorkspace) { - m_queuedFocusOverride = m_activeAssetId; + m_queuedFocusOverride = m_activeGraph; } return createdNewAsset; } - bool MainWindow::IsScriptCanvasAssetOpen(const AZ::Data::AssetId& assetId) const + bool MainWindow::IsScriptCanvasAssetOpen(const ScriptCanvasEditor::SourceHandle& assetId) const { ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); @@ -1466,7 +1467,7 @@ namespace ScriptCanvasEditor return m_nodePaletteModel.FindNodePaletteInformation(nodeType); } - void MainWindow::GetSuggestedFullFilenameToSaveAs(const AZ::Data::AssetId& assetId, AZStd::string& filePath, AZStd::string& fileFilter) + void MainWindow::GetSuggestedFullFilenameToSaveAs(const ScriptCanvasEditor::SourceHandle& assetId, AZStd::string& filePath, AZStd::string& fileFilter) { ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); @@ -1512,6 +1513,21 @@ namespace ScriptCanvasEditor void MainWindow::OpenFile(const char* fullPath) { + AZ::Outcome outcome = LoadFromFile(fullPath); + + if (!outcome.IsSuccess()) + { + m_errorFilePath = fullPath; + AZ_Warning("ScriptCanvas", false, "Unable to open file as a ScriptCanvas graph: %s", fullPath); + } + else + { + m_errorFilePath.clear(); + m_activeGraph = outcome.TakeValue(); + return; + } + +#if defined(EDITOR_ASSET_SUPPORT_ENABLED) m_errorFilePath = fullPath; // Let's find the source file on disk @@ -1564,6 +1580,7 @@ namespace ScriptCanvasEditor { QMessageBox::warning(this, "Invalid Source Asset", QString("'%1' is not a valid asset path.").arg(fullPath), QMessageBox::Ok); } +#endif } GraphCanvas::Endpoint MainWindow::HandleProposedConnection(const GraphCanvas::GraphId&, const GraphCanvas::ConnectionId&, const GraphCanvas::Endpoint& endpoint, const GraphCanvas::NodeId& nodeId, const QPoint& screenPoint) @@ -1674,7 +1691,7 @@ namespace ScriptCanvasEditor MakeNewFile(); } - int MainWindow::InsertTabForAsset(AZStd::string_view assetPath, AZ::Data::AssetId assetId, int tabIndex) + int MainWindow::InsertTabForAsset(AZStd::string_view assetPath, ScriptCanvasEditor::SourceHandle assetId, int tabIndex) { int outTabIndex = -1; @@ -1696,7 +1713,7 @@ namespace ScriptCanvasEditor return outTabIndex; } - void MainWindow::UpdateUndoCache(AZ::Data::AssetId) + void MainWindow::UpdateUndoCache(ScriptCanvasEditor::SourceHandle) { UndoCache* undoCache = nullptr; UndoRequestBus::EventResult(undoCache, GetActiveScriptCanvasId(), &UndoRequests::GetSceneUndoCache); @@ -1710,10 +1727,10 @@ namespace ScriptCanvasEditor { int outTabIndex = -1; - AZ::Data::AssetId newAssetId; + ScriptCanvasEditor::SourceHandle newAssetId; auto onAssetCreated = [this, assetPath, tabIndex, &outTabIndex](ScriptCanvasMemoryAsset& asset) { - const AZ::Data::AssetId& assetId = asset.GetId(); + const ScriptCanvasEditor::SourceHandle& assetId = asset.GetId(); outTabIndex = InsertTabForAsset(assetPath, assetId, tabIndex); @@ -1735,15 +1752,15 @@ namespace ScriptCanvasEditor bool MainWindow::OnFileSave(const Callbacks::OnSave& saveCB) { - return SaveAssetImpl(m_activeAssetId, saveCB); + return SaveAssetImpl(m_activeGraph, saveCB); } bool MainWindow::OnFileSaveAs(const Callbacks::OnSave& saveCB) { - return SaveAssetAsImpl(m_activeAssetId, saveCB); + return SaveAssetAsImpl(m_activeGraph, saveCB); } - bool MainWindow::SaveAssetImpl(const AZ::Data::AssetId& assetId, const Callbacks::OnSave& saveCB) + bool MainWindow::SaveAssetImpl(const ScriptCanvasEditor::SourceHandle& assetId, const Callbacks::OnSave& saveCB) { if (!assetId.IsValid()) { @@ -1770,14 +1787,14 @@ namespace ScriptCanvasEditor return saveSuccessful; } - bool MainWindow::SaveAssetAsImpl(const AZ::Data::AssetId& inMemoryAssetId, const Callbacks::OnSave& saveCB) + bool MainWindow::SaveAssetAsImpl(const ScriptCanvasEditor::SourceHandle& inMemoryAssetId, const Callbacks::OnSave& saveCB) { if (!inMemoryAssetId.IsValid()) { return false; } - if (m_activeAssetId != inMemoryAssetId) + if (m_activeGraph != inMemoryAssetId) { OnChangeActiveGraphTab(inMemoryAssetId); } @@ -1856,7 +1873,7 @@ namespace ScriptCanvasEditor return false; } - void MainWindow::OnSaveCallback(bool saveSuccess, AZ::Data::AssetPtr fileAsset, AZ::Data::AssetId previousFileAssetId) + void MainWindow::OnSaveCallback(bool saveSuccess, AZ::Data::AssetPtr fileAsset, ScriptCanvasEditor::SourceHandle previousFileAssetId) { ScriptCanvasMemoryAsset::pointer memoryAsset; AZStd::string tabName = m_tabBar->tabText(m_tabBar->currentIndex()).toUtf8().data(); @@ -1869,7 +1886,7 @@ namespace ScriptCanvasEditor AZ_Assert(memoryAsset, "At this point we must have a MemoryAsset"); // Update the editor with the new information about this asset. - const AZ::Data::AssetId& fileAssetId = memoryAsset->GetFileAssetId(); + const ScriptCanvasEditor::SourceHandle& fileAssetId = memoryAsset->GetFileAssetId(); saveTabIndex = m_tabBar->FindTab(fileAssetId); @@ -1877,7 +1894,7 @@ namespace ScriptCanvasEditor if (saveTabIndex != m_tabBar->currentIndex()) { // Invalidate the file asset id so we don't delete trigger the asset flow. - m_tabBar->setTabData(saveTabIndex, QVariant::fromValue(AZ::Data::AssetId())); + m_tabBar->setTabData(saveTabIndex, QVariant::fromValue(ScriptCanvasEditor::SourceHandle())); m_tabBar->CloseTab(saveTabIndex); saveTabIndex = -1; @@ -1933,12 +1950,12 @@ namespace ScriptCanvasEditor } // Soft switch the asset id here. We'll do a double scene switch down below to actually switch the active assetid - m_activeAssetId = fileAssetId; + m_activeGraph = fileAssetId; } else { // Use the previous memory asset to find what we had setup as our display - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeAssetId); + AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeGraph); // Drop off our file modifier status for our display name when we fail to save. if (tabName.at(tabName.size() -1) == '*') @@ -1954,9 +1971,9 @@ namespace ScriptCanvasEditor else { // Something weird happens with our saving. Where we are relying on these scene changes being called. - AZ::Data::AssetId previousAssetId = m_activeAssetId; + ScriptCanvasEditor::SourceHandle previousAssetId = m_activeGraph; - OnChangeActiveGraphTab(AZ::Data::AssetId()); + OnChangeActiveGraphTab(ScriptCanvasEditor::SourceHandle()); OnChangeActiveGraphTab(previousAssetId); } @@ -1982,17 +1999,17 @@ namespace ScriptCanvasEditor UnblockCloseRequests(); } - bool MainWindow::ActivateAndSaveAsset(const AZ::Data::AssetId& unsavedAssetId, const Callbacks::OnSave& saveCB) + bool MainWindow::ActivateAndSaveAsset(const ScriptCanvasEditor::SourceHandle& unsavedAssetId, const Callbacks::OnSave& saveCB) { SetActiveAsset(unsavedAssetId); return OnFileSave(saveCB); } - void MainWindow::SaveAsset(AZ::Data::AssetId assetId, const Callbacks::OnSave& onSave) + void MainWindow::SaveAsset(ScriptCanvasEditor::SourceHandle assetId, const Callbacks::OnSave& onSave) { PrepareAssetForSave(assetId); - auto onSaveCallback = [this, onSave](bool saveSuccess, AZ::Data::AssetPtr asset, AZ::Data::AssetId previousAssetId) + auto onSaveCallback = [this, onSave](bool saveSuccess, AZ::Data::AssetPtr asset, ScriptCanvasEditor::SourceHandle previousAssetId) { OnSaveCallback(saveSuccess, asset, previousAssetId); if (onSave) @@ -2005,7 +2022,7 @@ namespace ScriptCanvasEditor UpdateSaveState(); ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeAssetId); + AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeGraph); // Disable the current view if we are saving. if (memoryAsset) @@ -2016,11 +2033,11 @@ namespace ScriptCanvasEditor BlockCloseRequests(); } - void MainWindow::SaveNewAsset(AZStd::string_view path, AZ::Data::AssetId inMemoryAssetId, const Callbacks::OnSave& onSave) + void MainWindow::SaveNewAsset(AZStd::string_view path, ScriptCanvasEditor::SourceHandle inMemoryAssetId, const Callbacks::OnSave& onSave) { PrepareAssetForSave(inMemoryAssetId); - auto onSaveCallback = [this, onSave](bool saveSuccess, AZ::Data::AssetPtr asset, AZ::Data::AssetId previousAssetId) + auto onSaveCallback = [this, onSave](bool saveSuccess, AZ::Data::AssetPtr asset, ScriptCanvasEditor::SourceHandle previousAssetId) { OnSaveCallback(saveSuccess, asset, previousAssetId); if (onSave) @@ -2050,7 +2067,7 @@ namespace ScriptCanvasEditor EBUS_EVENT_RESULT(serializeContext, AZ::ComponentApplicationBus, GetSerializeContext); AZ_Assert(serializeContext, "Failed to acquire application serialize context."); - AZ::Data::AssetId openId = ReadRecentAssetId(); + ScriptCanvasEditor::SourceHandle openId = ReadRecentAssetId(); AZStd::string assetRoot; { @@ -2454,7 +2471,7 @@ namespace ScriptCanvasEditor void MainWindow::UpdateWorkspaceStatus(const ScriptCanvasMemoryAsset& memoryAsset) { - AZ::Data::AssetId fileAssetId = memoryAsset.GetFileAssetId(); + ScriptCanvasEditor::SourceHandle fileAssetId = memoryAsset.GetFileAssetId(); size_t eraseCount = m_loadingAssets.erase(fileAssetId); @@ -2517,7 +2534,7 @@ namespace ScriptCanvasEditor { if (m_allowAutoSave) { - const Tracker::ScriptCanvasFileState& fileState = GetAssetFileState(m_activeAssetId); + const Tracker::ScriptCanvasFileState& fileState = GetAssetFileState(m_activeGraph); if (fileState != Tracker::ScriptCanvasFileState::INVALID && fileState != Tracker::ScriptCanvasFileState::NEW) { OnFileSaveCaller(); @@ -2526,7 +2543,7 @@ namespace ScriptCanvasEditor } //! GeneralRequestBus - void MainWindow::OnChangeActiveGraphTab(AZ::Data::AssetId assetId) + void MainWindow::OnChangeActiveGraphTab(ScriptCanvasEditor::SourceHandle assetId) { SetActiveAsset(assetId); } @@ -2534,14 +2551,14 @@ namespace ScriptCanvasEditor AZ::EntityId MainWindow::GetActiveGraphCanvasGraphId() const { AZ::EntityId graphId; - AssetTrackerRequestBus::BroadcastResult(graphId, &AssetTrackerRequests::GetGraphId, m_activeAssetId); + AssetTrackerRequestBus::BroadcastResult(graphId, &AssetTrackerRequests::GetGraphId, m_activeGraph); return graphId; } ScriptCanvas::ScriptCanvasId MainWindow::GetActiveScriptCanvasId() const { ScriptCanvas::ScriptCanvasId sceneId; - AssetTrackerRequestBus::BroadcastResult(sceneId, &AssetTrackerRequests::GetScriptCanvasId, m_activeAssetId); + AssetTrackerRequestBus::BroadcastResult(sceneId, &AssetTrackerRequests::GetScriptCanvasId, m_activeGraph); return sceneId; } @@ -2553,14 +2570,14 @@ namespace ScriptCanvasEditor return graphCanvasId; } - GraphCanvas::GraphId MainWindow::FindGraphCanvasGraphIdByAssetId(const AZ::Data::AssetId& assetId) const + GraphCanvas::GraphId MainWindow::FindGraphCanvasGraphIdByAssetId(const ScriptCanvasEditor::SourceHandle& assetId) const { AZ::EntityId graphId; AssetTrackerRequestBus::BroadcastResult(graphId, &AssetTrackerRequests::GetGraphId, assetId); return graphId; } - ScriptCanvas::ScriptCanvasId MainWindow::FindScriptCanvasIdByAssetId(const AZ::Data::AssetId& assetId) const + ScriptCanvas::ScriptCanvasId MainWindow::FindScriptCanvasIdByAssetId(const ScriptCanvasEditor::SourceHandle& assetId) const { ScriptCanvas::ScriptCanvasId scriptCanvasId; AssetTrackerRequestBus::BroadcastResult(scriptCanvasId, &AssetTrackerRequests::GetScriptCanvasId, assetId); @@ -2600,14 +2617,14 @@ namespace ScriptCanvasEditor return isActive; } - QVariant MainWindow::GetTabData(const AZ::Data::AssetId& assetId) + QVariant MainWindow::GetTabData(const ScriptCanvasEditor::SourceHandle& assetId) { for (int tabIndex = 0; tabIndex < m_tabBar->count(); ++tabIndex) { QVariant tabdata = m_tabBar->tabData(tabIndex); if (tabdata.isValid()) { - auto tabAssetId = tabdata.value(); + auto tabAssetId = tabdata.value(); if (tabAssetId == assetId) { return tabdata; @@ -2617,7 +2634,7 @@ namespace ScriptCanvasEditor return QVariant(); } - bool MainWindow::IsTabOpen(const AZ::Data::AssetId& fileAssetId, int& outTabIndex) const + bool MainWindow::IsTabOpen(const ScriptCanvasEditor::SourceHandle& fileAssetId, int& outTabIndex) const { int tabIndex = m_tabBar->FindTab(fileAssetId); if (-1 != tabIndex) @@ -2628,7 +2645,7 @@ namespace ScriptCanvasEditor return false; } - void MainWindow::ReconnectSceneBuses(AZ::Data::AssetId previousAssetId, AZ::Data::AssetId nextAssetId) + void MainWindow::ReconnectSceneBuses(ScriptCanvasEditor::SourceHandle previousAssetId, ScriptCanvasEditor::SourceHandle nextAssetId) { ScriptCanvasMemoryAsset::pointer previousAsset; AssetTrackerRequestBus::BroadcastResult(previousAsset, &AssetTrackerRequests::GetAsset, previousAssetId); @@ -2664,14 +2681,14 @@ namespace ScriptCanvasEditor } - void MainWindow::SetActiveAsset(const AZ::Data::AssetId& fileAssetId) + void MainWindow::SetActiveAsset(const ScriptCanvasEditor::SourceHandle& fileAssetId) { - if (m_activeAssetId == fileAssetId) + if (m_activeGraph == fileAssetId) { return; } - AssetHelpers::PrintInfo("SetActiveAsset : from: %s to %s", AssetHelpers::AssetIdToString(m_activeAssetId).c_str(), AssetHelpers::AssetIdToString(fileAssetId).c_str()); + AssetHelpers::PrintInfo("SetActiveAsset : from: %s to %s", AssetHelpers::AssetIdToString(m_activeGraph).c_str(), AssetHelpers::AssetIdToString(fileAssetId).c_str()); if (fileAssetId.IsValid()) { @@ -2686,10 +2703,10 @@ namespace ScriptCanvasEditor } } - if (m_activeAssetId.IsValid()) + if (m_activeGraph.IsValid()) { ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeAssetId); + AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeGraph); // If we are saving the asset, the Id may have changed from the in-memory to the file asset Id, in that case, // there's no need to hide the view or remove the widget @@ -2702,23 +2719,23 @@ namespace ScriptCanvasEditor if (fileAssetId.IsValid()) { - AZ::Data::AssetId previousAssetId = m_activeAssetId; + ScriptCanvasEditor::SourceHandle previousAssetId = m_activeGraph; - m_activeAssetId = fileAssetId; + m_activeGraph = fileAssetId; RefreshActiveAsset(); - ReconnectSceneBuses(previousAssetId, m_activeAssetId); + ReconnectSceneBuses(previousAssetId, m_activeGraph); } else { - AZ::Data::AssetId previousAssetId = m_activeAssetId; + ScriptCanvasEditor::SourceHandle previousAssetId = m_activeGraph; - m_activeAssetId.SetInvalid(); + m_activeGraph.SetInvalid(); m_emptyCanvas->show(); - ReconnectSceneBuses(previousAssetId, m_activeAssetId); + ReconnectSceneBuses(previousAssetId, m_activeGraph); - SignalActiveSceneChanged(AZ::Data::AssetId()); + SignalActiveSceneChanged(ScriptCanvasEditor::SourceHandle()); } UpdateUndoCache(fileAssetId); @@ -2728,12 +2745,12 @@ namespace ScriptCanvasEditor void MainWindow::RefreshActiveAsset() { - if (m_activeAssetId.IsValid()) + if (m_activeGraph.IsValid()) { - AssetHelpers::PrintInfo("RefreshActiveAsset : m_activeAssetId (%s)", AssetHelpers::AssetIdToString(m_activeAssetId).c_str()); + AssetHelpers::PrintInfo("RefreshActiveAsset : m_activeGraph (%s)", AssetHelpers::AssetIdToString(m_activeGraph).c_str()); ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeAssetId); + AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeGraph); if (memoryAsset) { @@ -2752,7 +2769,7 @@ namespace ScriptCanvasEditor AZ_Assert(view, "Asset should have a view"); if (view) { - AssetHelpers::PrintInfo("RefreshActiveAsset : m_activeAssetId (%s)", AssetHelpers::AssetIdToString(m_activeAssetId).c_str()); + AssetHelpers::PrintInfo("RefreshActiveAsset : m_activeGraph (%s)", AssetHelpers::AssetIdToString(m_activeGraph).c_str()); view->ShowScene(sceneEntityId); m_layout->addWidget(view); @@ -2761,7 +2778,7 @@ namespace ScriptCanvasEditor m_emptyCanvas->hide(); } - SignalActiveSceneChanged(m_activeAssetId); + SignalActiveSceneChanged(m_activeGraph); } } else @@ -2792,7 +2809,7 @@ namespace ScriptCanvasEditor QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) { - auto fileAssetId = tabdata.value(); + auto fileAssetId = tabdata.value(); Tracker::ScriptCanvasFileState fileState; AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, fileAssetId); @@ -2819,7 +2836,7 @@ namespace ScriptCanvasEditor if (saveDialogResults == UnsavedChangesOptions::SAVE) { - auto saveCB = [this](bool isSuccessful, AZ::Data::AssetPtr asset, AZ::Data::AssetId) + auto saveCB = [this](bool isSuccessful, AZ::Data::AssetPtr asset, ScriptCanvasEditor::SourceHandle) { if (isSuccessful) { @@ -2860,7 +2877,7 @@ namespace ScriptCanvasEditor QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) { - auto assetId = tabdata.value(); + auto assetId = tabdata.value(); SaveAssetImpl(assetId, nullptr); } @@ -2879,7 +2896,7 @@ namespace ScriptCanvasEditor QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) { - auto assetId = tabdata.value(); + auto assetId = tabdata.value(); m_isClosingTabs = true; m_skipTabOnClose = assetId; @@ -2895,7 +2912,7 @@ namespace ScriptCanvasEditor { QClipboard* clipBoard = QGuiApplication::clipboard(); - auto assetId = tabdata.value(); + auto assetId = tabdata.value(); ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); @@ -2936,7 +2953,7 @@ namespace ScriptCanvasEditor QVariant tabdata = m_tabBar->tabData(tab); if (tabdata.isValid()) { - auto assetId = tabdata.value(); + auto assetId = tabdata.value(); if (assetId != m_skipTabOnClose) { @@ -2956,9 +2973,9 @@ namespace ScriptCanvasEditor QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) { - auto tabAssetId = tabdata.value(); + auto tabAssetId = tabdata.value(); - if (tabAssetId == m_activeAssetId) + if (tabAssetId == m_activeGraph) { SetActiveAsset({}); } @@ -3162,7 +3179,7 @@ namespace ScriptCanvasEditor bool hasCopiableSelection = false; bool hasSelection = false; - if (m_activeAssetId.IsValid()) + if (m_activeGraph.IsValid()) { if (graphCanvasGraphId.IsValid()) { @@ -3550,7 +3567,7 @@ namespace ScriptCanvasEditor m_isRestoringWorkspace = true; } - void MainWindow::OnWorkspaceRestoreEnd(AZ::Data::AssetId lastFocusAsset) + void MainWindow::OnWorkspaceRestoreEnd(ScriptCanvasEditor::SourceHandle lastFocusAsset) { if (m_isRestoringWorkspace) { @@ -3566,7 +3583,7 @@ namespace ScriptCanvasEditor SetActiveAsset(lastFocusAsset); } - if (!m_activeAssetId.IsValid()) + if (!m_activeGraph.IsValid()) { if (m_tabBar->count() > 0) { @@ -3589,11 +3606,11 @@ namespace ScriptCanvasEditor void MainWindow::UpdateAssignToSelectionState() { - bool buttonEnabled = m_activeAssetId.IsValid(); + bool buttonEnabled = m_activeGraph.IsValid(); if (buttonEnabled) { - const Tracker::ScriptCanvasFileState& fileState = GetAssetFileState(m_activeAssetId); + const Tracker::ScriptCanvasFileState& fileState = GetAssetFileState(m_activeGraph); if (fileState == Tracker::ScriptCanvasFileState::INVALID || fileState == Tracker::ScriptCanvasFileState::NEW || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED) { buttonEnabled = false; @@ -3622,18 +3639,18 @@ namespace ScriptCanvasEditor void MainWindow::UpdateSaveState() { - bool enabled = m_activeAssetId.IsValid(); + bool enabled = m_activeGraph.IsValid(); bool isSaving = false; bool hasModifications = false; if (enabled) { - Tracker::ScriptCanvasFileState fileState = GetAssetFileState(m_activeAssetId); + Tracker::ScriptCanvasFileState fileState = GetAssetFileState(m_activeGraph); hasModifications = ( fileState == Tracker::ScriptCanvasFileState::MODIFIED || fileState == Tracker::ScriptCanvasFileState::NEW || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED); - AssetTrackerRequestBus::BroadcastResult(isSaving, &AssetTrackerRequests::IsSaving, m_activeAssetId); + AssetTrackerRequestBus::BroadcastResult(isSaving, &AssetTrackerRequests::IsSaving, m_activeGraph); } ui->action_Save->setEnabled(enabled && !isSaving && hasModifications); @@ -3835,14 +3852,14 @@ namespace ScriptCanvasEditor return findChild(elementName); } - AZ::EntityId MainWindow::FindEditorNodeIdByAssetNodeId(const AZ::Data::AssetId& assetId, AZ::EntityId assetNodeId) const + AZ::EntityId MainWindow::FindEditorNodeIdByAssetNodeId(const ScriptCanvasEditor::SourceHandle& assetId, AZ::EntityId assetNodeId) const { AZ::EntityId editorEntityId; AssetTrackerRequestBus::BroadcastResult(editorEntityId, &AssetTrackerRequests::GetEditorEntityIdFromSceneEntityId, assetId, assetNodeId); return editorEntityId; } - AZ::EntityId MainWindow::FindAssetNodeIdByEditorNodeId(const AZ::Data::AssetId& assetId, AZ::EntityId editorNodeId) const + AZ::EntityId MainWindow::FindAssetNodeIdByEditorNodeId(const ScriptCanvasEditor::SourceHandle& assetId, AZ::EntityId editorNodeId) const { AZ::EntityId sceneEntityId; AssetTrackerRequestBus::BroadcastResult(sceneEntityId, &AssetTrackerRequests::GetSceneEntityIdFromEditorEntityId, assetId, editorNodeId); @@ -3959,7 +3976,7 @@ namespace ScriptCanvasEditor OnFileNew(); - if (m_activeAssetId.IsValid()) + if (m_activeGraph.IsValid()) { graphId = GetActiveGraphCanvasGraphId(); } @@ -4263,10 +4280,10 @@ namespace ScriptCanvasEditor void MainWindow::PrepareActiveAssetForSave() { - PrepareAssetForSave(m_activeAssetId); + PrepareAssetForSave(m_activeGraph); } - void MainWindow::PrepareAssetForSave(const AZ::Data::AssetId& assetId) + void MainWindow::PrepareAssetForSave(const ScriptCanvasEditor::SourceHandle& assetId) { ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); @@ -4335,7 +4352,7 @@ namespace ScriptCanvasEditor void MainWindow::OnAssignToSelectedEntities() { Tracker::ScriptCanvasFileState fileState; - AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, m_activeAssetId); + AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, m_activeGraph); bool isDocumentOpen = false; AzToolsFramework::EditorRequests::Bus::BroadcastResult(isDocumentOpen, &AzToolsFramework::EditorRequests::IsLevelDocumentOpen); @@ -4396,7 +4413,7 @@ namespace ScriptCanvasEditor void MainWindow::OnAssignToEntity(const AZ::EntityId& entityId) { - Tracker::ScriptCanvasFileState fileState = GetAssetFileState(m_activeAssetId); + Tracker::ScriptCanvasFileState fileState = GetAssetFileState(m_activeGraph); if (fileState == Tracker::ScriptCanvasFileState::MODIFIED || fileState == Tracker::ScriptCanvasFileState::UNMODIFIED) @@ -4405,7 +4422,7 @@ namespace ScriptCanvasEditor } } - ScriptCanvasEditor::Tracker::ScriptCanvasFileState MainWindow::GetAssetFileState(AZ::Data::AssetId assetId) const + ScriptCanvasEditor::Tracker::ScriptCanvasFileState MainWindow::GetAssetFileState(ScriptCanvasEditor::SourceHandle assetId) const { Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::INVALID; AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, assetId); @@ -4458,7 +4475,7 @@ namespace ScriptCanvasEditor if (usableRequestBus) { ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeAssetId); + AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeGraph); if (memoryAsset) { diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h index 2c84412e28..694964e482 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h @@ -42,7 +42,7 @@ #include #include #include - +#include #include #include #include @@ -177,9 +177,9 @@ namespace ScriptCanvasEditor private: void OnAssetReady(const ScriptCanvasMemoryAsset::pointer asset) override; - void SignalAssetComplete(const AZ::Data::AssetId& fileAssetId); + void SignalAssetComplete(const ScriptCanvasEditor::SourceHandle& fileAssetId); - AZ::Data::AssetId GetSourceAssetId(const AZ::Data::AssetId& memoryAssetId) const; + ScriptCanvasEditor::SourceHandle GetSourceAssetId(const ScriptCanvasEditor::SourceHandle& memoryAssetId) const; bool m_rememberOpenCanvases; MainWindow* m_mainWindow; @@ -187,10 +187,10 @@ namespace ScriptCanvasEditor //! Setting focus is problematic unless it is done until after all currently loading graphs have finished loading //! This vector is used to track the list of graphs being opened to restore the workspace and as assets are fully //! ready and activated they are removed from this list. - AZStd::vector m_loadingAssets; + AZStd::vector m_loadingAssets; //! During restore we queue the asset Id to focus in order to do it last - AZ::Data::AssetId m_queuedAssetFocus; + ScriptCanvasEditor::SourceHandle m_queuedAssetFocus; }; enum class UnsavedChangesOptions; @@ -271,7 +271,7 @@ namespace ScriptCanvasEditor // Undo Handlers void PostUndoPoint(ScriptCanvas::ScriptCanvasId scriptCanvasId) override; - void SignalSceneDirty(AZ::Data::AssetId assetId) override; + void SignalSceneDirty(ScriptCanvasEditor::SourceHandle assetId) override; void PushPreventUndoStateUpdate() override; void PopPreventUndoStateUpdate() override; @@ -331,8 +331,8 @@ namespace ScriptCanvasEditor bool OnFileSaveAs(const Callbacks::OnSave& saveCB); bool OnFileSaveCaller(){return OnFileSave(nullptr);}; bool OnFileSaveAsCaller(){return OnFileSaveAs(nullptr);}; - bool SaveAssetImpl(const AZ::Data::AssetId& assetId, const Callbacks::OnSave& saveCB); - bool SaveAssetAsImpl(const AZ::Data::AssetId& assetId, const Callbacks::OnSave& saveCB); + bool SaveAssetImpl(const ScriptCanvasEditor::SourceHandle& assetId, const Callbacks::OnSave& saveCB); + bool SaveAssetAsImpl(const ScriptCanvasEditor::SourceHandle& assetId, const Callbacks::OnSave& saveCB); void OnFileOpen(); // Edit menu @@ -417,17 +417,17 @@ namespace ScriptCanvasEditor void CloseNextTab(); - bool IsTabOpen(const AZ::Data::AssetId& assetId, int& outTabIndex) const; - QVariant GetTabData(const AZ::Data::AssetId& assetId); + bool IsTabOpen(const ScriptCanvasEditor::SourceHandle& assetId, int& outTabIndex) const; + QVariant GetTabData(const ScriptCanvasEditor::SourceHandle& assetId); //! GeneralRequestBus - AZ::Outcome OpenScriptCanvasAssetId(const AZ::Data::AssetId& assetId) override; - AZ::Outcome OpenScriptCanvasAsset(AZ::Data::AssetId scriptCanvasAssetId, int tabIndex = -1) override; + AZ::Outcome OpenScriptCanvasAssetId(const ScriptCanvasEditor::SourceHandle& assetId) override; + AZ::Outcome OpenScriptCanvasAsset(ScriptCanvasEditor::SourceHandle scriptCanvasAssetId, int tabIndex = -1) override; AZ::Outcome OpenScriptCanvasAsset(const ScriptCanvasMemoryAsset& scriptCanvasAsset, int tabIndex = -1); - int CloseScriptCanvasAsset(const AZ::Data::AssetId& assetId) override; + int CloseScriptCanvasAsset(const ScriptCanvasEditor::SourceHandle& assetId) override; bool CreateScriptCanvasAssetFor(const TypeDefs::EntityComponentId& requestingEntityId) override; - bool IsScriptCanvasAssetOpen(const AZ::Data::AssetId& assetId) const override; + bool IsScriptCanvasAssetOpen(const ScriptCanvasEditor::SourceHandle& assetId) const override; const CategoryInformation* FindNodePaletteCategoryInformation(AZStd::string_view categoryPath) const override; const NodePaletteModelInformation* FindNodePaletteModelInformation(const ScriptCanvas::NodeTypeIdentifier& nodeType) const override; @@ -439,8 +439,8 @@ namespace ScriptCanvasEditor void RefreshScriptCanvasAsset(const AZ::Data::Asset& scriptCanvasAsset); //! Removes the assetId -> ScriptCanvasAsset mapping and disconnects from the asset tracker - void RemoveScriptCanvasAsset(const AZ::Data::AssetId& assetId); - void OnChangeActiveGraphTab(AZ::Data::AssetId) override; + void RemoveScriptCanvasAsset(const ScriptCanvasEditor::SourceHandle& assetId); + void OnChangeActiveGraphTab(ScriptCanvasEditor::SourceHandle) override; void CreateNewRuntimeAsset() override { OnFileNew(); } @@ -450,8 +450,8 @@ namespace ScriptCanvasEditor GraphCanvas::GraphId GetGraphCanvasGraphId(const ScriptCanvas::ScriptCanvasId& scriptCanvasId) const override; - GraphCanvas::GraphId FindGraphCanvasGraphIdByAssetId(const AZ::Data::AssetId& assetId) const override; - ScriptCanvas::ScriptCanvasId FindScriptCanvasIdByAssetId(const AZ::Data::AssetId& assetId) const override; + GraphCanvas::GraphId FindGraphCanvasGraphIdByAssetId(const ScriptCanvasEditor::SourceHandle& assetId) const override; + ScriptCanvas::ScriptCanvasId FindScriptCanvasIdByAssetId(const ScriptCanvasEditor::SourceHandle& assetId) const override; bool IsInUndoRedo(const AZ::EntityId& graphCanvasGraphId) const override; bool IsScriptCanvasInUndoRedo(const ScriptCanvas::ScriptCanvasId& scriptCanvasId) const override; @@ -519,8 +519,8 @@ namespace ScriptCanvasEditor QObject* FindElementByName(QString elementName) override; //// - AZ::EntityId FindEditorNodeIdByAssetNodeId(const AZ::Data::AssetId& assetId, AZ::EntityId assetNodeId) const override; - AZ::EntityId FindAssetNodeIdByEditorNodeId(const AZ::Data::AssetId& assetId, AZ::EntityId editorNodeId) const override; + AZ::EntityId FindEditorNodeIdByAssetNodeId(const ScriptCanvasEditor::SourceHandle& assetId, AZ::EntityId assetNodeId) const override; + AZ::EntityId FindAssetNodeIdByEditorNodeId(const ScriptCanvasEditor::SourceHandle& assetId, AZ::EntityId editorNodeId) const override; private: void DeleteNodes(const AZ::EntityId& sceneId, const AZStd::vector& nodes) override; @@ -548,26 +548,23 @@ namespace ScriptCanvasEditor //! Helper function which serializes a file to disk //! \param filename name of file to serialize the Entity //! \param asset asset to save - void GetSuggestedFullFilenameToSaveAs(const AZ::Data::AssetId& assetId, AZStd::string& filePath, AZStd::string& fileFilter); + void GetSuggestedFullFilenameToSaveAs(const ScriptCanvasEditor::SourceHandle& assetId, AZStd::string& filePath, AZStd::string& fileFilter); - void MarkAssetModified(const AZ::Data::AssetId& assetId); + void MarkAssetModified(const ScriptCanvasEditor::SourceHandle& assetId); // QMainWindow void closeEvent(QCloseEvent *event) override; UnsavedChangesOptions ShowSaveDialog(const QString& filename); - bool ActivateAndSaveAsset(const AZ::Data::AssetId& unsavedAssetId, const Callbacks::OnSave& onSave); + bool ActivateAndSaveAsset(const ScriptCanvasEditor::SourceHandle& unsavedAssetId, const Callbacks::OnSave& onSave); - void SaveNewAsset(AZStd::string_view path, AZ::Data::AssetId assetId, const Callbacks::OnSave& onSave); - void SaveAsset(AZ::Data::AssetId assetId, const Callbacks::OnSave& onSave); + void SaveNewAsset(AZStd::string_view path, ScriptCanvasEditor::SourceHandle assetId, const Callbacks::OnSave& onSave); + void SaveAsset(ScriptCanvasEditor::SourceHandle assetId, const Callbacks::OnSave& onSave); void OpenFile(const char* fullPath); void CreateMenus(); - void SignalActiveSceneChanged(const AZ::Data::AssetId assetId); - - void SaveWorkspace(bool updateAssetList = true); - void RestoreWorkspace(); + void SignalActiveSceneChanged(const ScriptCanvasEditor::SourceHandle assetId); void RunUpgradeTool(); @@ -595,7 +592,7 @@ namespace ScriptCanvasEditor void UpdateMenuState(bool enabledState); void OnWorkspaceRestoreStart(); - void OnWorkspaceRestoreEnd(AZ::Data::AssetId lastFocusAsset); + void OnWorkspaceRestoreEnd(ScriptCanvasEditor::SourceHandle lastFocusAsset); void UpdateAssignToSelectionState(); void UpdateUndoRedoState(); @@ -606,18 +603,16 @@ namespace ScriptCanvasEditor void CreateFunctionDefinitionNode(int positionOffset); - int CreateAssetTab(const AZ::Data::AssetId& assetId, int tabIndex = -1); + int CreateAssetTab(const ScriptCanvasEditor::SourceHandle& assetId, int tabIndex = -1); //! \param asset The AssetId of the ScriptCanvas Asset. - void SetActiveAsset(const AZ::Data::AssetId& assetId); + void SetActiveAsset(const ScriptCanvasEditor::SourceHandle& assetId); void RefreshActiveAsset(); - void ReconnectSceneBuses(AZ::Data::AssetId previousAssetId, AZ::Data::AssetId nextAssetId); - - void SignalBatchOperationComplete(BatchOperatorTool* batchTool); + void ReconnectSceneBuses(ScriptCanvasEditor::SourceHandle previousAssetId, ScriptCanvasEditor::SourceHandle nextAssetId); void PrepareActiveAssetForSave(); - void PrepareAssetForSave(const AZ::Data::AssetId& asssetId); + void PrepareAssetForSave(const ScriptCanvasEditor::SourceHandle& asssetId); void RestartAutoTimerSave(bool forceTimer = false); @@ -628,9 +623,9 @@ namespace ScriptCanvasEditor void AssignGraphToEntityImpl(const AZ::EntityId& entityId); //// - Tracker::ScriptCanvasFileState GetAssetFileState(AZ::Data::AssetId assetId) const; + Tracker::ScriptCanvasFileState GetAssetFileState(ScriptCanvasEditor::SourceHandle assetId) const; - AZ::Data::AssetId GetSourceAssetId(const AZ::Data::AssetId& memoryAssetId) const + ScriptCanvasEditor::SourceHandle GetSourceAssetId(const ScriptCanvasEditor::SourceHandle& memoryAssetId) const { ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, memoryAssetId); @@ -640,12 +635,12 @@ namespace ScriptCanvasEditor return memoryAsset->GetFileAssetId(); } - return AZ::Data::AssetId(); + return ScriptCanvasEditor::SourceHandle(); } - int InsertTabForAsset(AZStd::string_view assetPath, AZ::Data::AssetId assetId, int tabIndex = -1); + int InsertTabForAsset(AZStd::string_view assetPath, ScriptCanvasEditor::SourceHandle assetId, int tabIndex = -1); - void UpdateUndoCache(AZ::Data::AssetId assetId); + void UpdateUndoCache(ScriptCanvasEditor::SourceHandle assetId); bool HasSystemTickAction(SystemTickActionFlag action); @@ -743,22 +738,22 @@ namespace ScriptCanvasEditor GraphCanvas::GraphCanvasEditorEmptyDockWidget* m_emptyCanvas; // Displayed when there is no open graph QVBoxLayout* m_layout; - AZ::Data::AssetId m_activeAssetId; - + ScriptCanvasEditor::SourceHandle m_activeGraph; + bool m_loadingNewlySavedFile; AZStd::string m_newlySavedFile; AZStd::string m_errorFilePath; bool m_isClosingTabs; - AZ::Data::AssetId m_skipTabOnClose; + ScriptCanvasEditor::SourceHandle m_skipTabOnClose; bool m_enterState; bool m_ignoreSelection; AZ::s32 m_preventUndoStateUpdateCount; bool m_isRestoringWorkspace; - AZ::Data::AssetId m_queuedFocusOverride; + ScriptCanvasEditor::SourceHandle m_queuedFocusOverride; Ui::MainWindow* ui; AZStd::array, c_scriptCanvasEditorSettingsRecentFilesCountMax> m_recentActions; @@ -780,17 +775,17 @@ namespace ScriptCanvasEditor AZStd::vector m_selectedVariableIds; AZ::u32 m_systemTickActions; - AZStd::unordered_set< AZ::Data::AssetId > m_processedClosedAssetIds; + AZStd::unordered_set< ScriptCanvasEditor::SourceHandle > m_processedClosedAssetIds; - AZStd::unordered_set< AZ::Data::AssetId > m_loadingWorkspaceAssets; - AZStd::unordered_set< AZ::Data::AssetId > m_loadingAssets; + AZStd::unordered_set< ScriptCanvasEditor::SourceHandle > m_loadingWorkspaceAssets; + AZStd::unordered_set< ScriptCanvasEditor::SourceHandle > m_loadingAssets; AZStd::unordered_set< AZ::Uuid > m_variablePaletteTypes; AZStd::unordered_map< AZ::Crc32, QObject* > m_automationLookUpMap; bool m_closeCurrentGraphAfterSave; - AZStd::unordered_map< AZ::Data::AssetId, TypeDefs::EntityComponentId > m_assetCreationRequests; + AZStd::unordered_map< ScriptCanvasEditor::SourceHandle, TypeDefs::EntityComponentId > m_assetCreationRequests; ScriptCanvas::Debugger::ClientTransceiver m_clientTRX; GraphCanvas::StyleManager m_styleManager; @@ -799,6 +794,6 @@ namespace ScriptCanvasEditor //! this object manages the Save/Restore operations Workspace* m_workspace; - void OnSaveCallback(bool saveSuccess, AZ::Data::AssetPtr, AZ::Data::AssetId previousFileAssetId); + void OnSaveCallback(bool saveSuccess, AZ::Data::AssetPtr, ScriptCanvasEditor::SourceHandle previousFileAssetId); }; } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/ScriptCanvasAssetBase.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/ScriptCanvasAssetBase.h index 265c35d310..1dc0b38e01 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/ScriptCanvasAssetBase.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/ScriptCanvasAssetBase.h @@ -8,16 +8,17 @@ #pragma once +#include #include #include #include - #include namespace ScriptCanvas { class ScriptCanvasAssetBase : public AZ::Data::AssetData + , public AZStd::enable_shared_from_this , ScriptCanvas::ScriptCanvasAssetBusRequestBus::Handler { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h index 0e64c19dcb..85f76280d2 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h @@ -26,6 +26,8 @@ #define OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED +#define EDITOR_ASSET_SUPPORT_ENABLED + namespace AZ { class Entity; @@ -61,6 +63,10 @@ namespace ScriptCanvas class Node; class Edge; + class Graph; + + using GraphPtr = Graph*; + using GraphPtrConst = const Graph*; using ID = AZ::EntityId; @@ -297,6 +303,24 @@ namespace ScriptCanvas void ReflectEventTypeOnDemand(const AZ::TypeId& typeId, AZStd::string_view name, AZ::IRttiHelper* rttiHelper = nullptr); } +namespace ScriptCanvas +{ + class ScriptCanvasData; + + using DataPtr = AZStd::shared_ptr; + using DataPtrConst = AZStd::shared_ptr; +} + +namespace ScriptCanvasEditor +{ + class Graph; + + using GraphPtr = Graph*; + using GraphPtrConst = const Graph*; + + class SourceHandle; +} + namespace AZStd { template<> diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.h index 46e8a103bb..786e693a04 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.h @@ -14,14 +14,12 @@ #include #include #include - #include #include #include #include #include #include - #include namespace ScriptCanvas @@ -209,7 +207,7 @@ namespace ScriptCanvas GraphVariableManagerRequests* m_variableRequests = nullptr; // Keeps a mapping of the Node EntityId -> NodeComponent. - // Saves looking up the NodeComponent everytime we need the Node. + // Saves looking up the NodeComponent every time we need the Node. AZStd::unordered_map m_nodeMapping; bool m_isObserved; diff --git a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake index 609f7cd454..49f89d8e48 100644 --- a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake +++ b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake @@ -27,7 +27,11 @@ set(FILES Editor/Assets/ScriptCanvasAsset.cpp Editor/Include/ScriptCanvas/Assets/ScriptCanvasAssetBus.h Editor/Include/ScriptCanvas/Assets/ScriptCanvasAssetTypes.h + Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h + Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.h + Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.cpp Editor/Include/ScriptCanvas/Assets/ScriptCanvasAssetHandler.h + Editor/Assets/ScriptCanvasFileHandling.cpp Editor/Assets/ScriptCanvasAssetHandler.cpp Editor/Assets/ScriptCanvasAssetHolder.h Editor/Assets/ScriptCanvasAssetHolder.cpp From b7f6ebb708e5c1279b509eb8f353ea3a8b389d11 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Mon, 18 Oct 2021 11:56:14 -0700 Subject: [PATCH 002/128] Git MainWindow.cpp to point where it compiles, and reveals the radius of changes for everything to work without assets Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Editor/Assets/ScriptCanvasAssetTracker.h | 3 + .../Assets/ScriptCanvasSourceFileHandle.cpp | 52 -- .../Assets/ScriptCanvasSourceFileHandle.h | 37 - .../ScriptCanvas/Bus/EditorScriptCanvasBus.h | 2 - .../Include/ScriptCanvas/Bus/RequestBus.h | 14 +- .../ScriptCanvas/Components/EditorGraph.h | 6 +- Gems/ScriptCanvas/Code/Editor/QtMetaTypes.h | 4 +- Gems/ScriptCanvas/Code/Editor/Settings.h | 13 +- .../Code/Editor/Utilities/RecentAssetPath.cpp | 4 +- .../Code/Editor/Utilities/RecentAssetPath.h | 4 +- .../View/Widgets/AssetGraphSceneDataBus.h | 6 +- .../Code/Editor/View/Widgets/GraphTabBar.h | 14 +- .../Code/Editor/View/Windows/MainWindow.cpp | 740 ++++++++++-------- .../Code/Editor/View/Windows/MainWindow.h | 24 +- .../Code/Include/ScriptCanvas/Core/Core.cpp | 53 +- .../Code/Include/ScriptCanvas/Core/Core.h | 36 +- 16 files changed, 534 insertions(+), 478 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.h b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.h index 4850e669ff..6b462e27ab 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.h +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.h @@ -22,6 +22,9 @@ namespace ScriptCanvasEditor { class ScriptCanvasMemoryAsset; + + // MOVE THIS MOSTLY TO TAB BAR, MAIN WINDOW AND THE CANVAS WIDGET + // This class tracks all things related to the assets that the Script Canvas editor // has in play. It also provides helper functionality to quickly getting asset information // from GraphCanvas diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.cpp b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.cpp index e6ed773e83..258a862a19 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.cpp @@ -7,55 +7,3 @@ */ #include -#include - -namespace ScriptCanvasEditor -{ - SourceHandle::SourceHandle(ScriptCanvas::DataPtr graph, const AZ::Uuid& id, AZStd::string_view path) - : m_data(graph) - , m_id(id) - , m_path(path) - {} - - void SourceHandle::Clear() - { - m_data = nullptr; - m_id = AZ::Uuid::CreateNull(); - m_path.clear(); - } - - GraphPtrConst SourceHandle::Get() const - { - return m_data ? m_data->GetEditorGraph() : nullptr; - } - - const AZ::Uuid& SourceHandle::Id() const - { - return m_id; - } - - bool SourceHandle::IsValid() const - { - return *this; - } - - GraphPtr SourceHandle::Mod() const - { - return m_data ? m_data->ModEditorGraph() : nullptr; - } - - SourceHandle::operator bool() const - { - return m_data != nullptr; - } - - bool SourceHandle::operator!() const - { - return m_data == nullptr; - } - - const AZStd::string& SourceHandle::Path() const - { - return m_path; - } -} diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.h index 045221310a..1d14b9b21b 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.h @@ -8,40 +8,3 @@ #pragma once -#include -#include - -namespace ScriptCanvasEditor -{ - class SourceHandle - { - public: - AZ_TYPE_INFO(SourceHandle, "{65855A98-AE2F-427F-BFC8-69D45265E312}"); - AZ_CLASS_ALLOCATOR(SourceHandle, AZ::SystemAllocator, 0); - - SourceHandle() = default; - - SourceHandle(ScriptCanvas::DataPtr graph, const AZ::Uuid& id, AZStd::string_view path); - - void Clear(); - - GraphPtrConst Get() const; - - const AZ::Uuid& Id() const; - - bool IsValid() const; - - GraphPtr Mod() const; - - operator bool() const; - - bool operator!() const; - - const AZStd::string& Path() const; - - private: - ScriptCanvas::DataPtr m_data; - AZ::Uuid m_id = AZ::Uuid::CreateNull(); - AZStd::string m_path; - }; -} diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h index 7e7b600081..7c57d661f0 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h @@ -121,8 +121,6 @@ namespace ScriptCanvasEditor static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; using BusIdType = ScriptCanvas::ScriptCanvasId; - virtual void SetAssetId(const AZ::Data::AssetId& assetId) = 0; - virtual void CreateGraphCanvasScene() = 0; virtual void ClearGraphCanvasScene() = 0; virtual GraphCanvas::GraphId GetGraphCanvasGraphId() const = 0; diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h index dedfdd8d20..2d9a7d6b58 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h @@ -70,16 +70,16 @@ namespace ScriptCanvasEditor //! Opens an existing graph and returns the tab index in which it was open in. //! \param File AssetId //! \return index of open tab if the asset was able to be open successfully or error message of why the open failed - virtual AZ::Outcome OpenScriptCanvasAsset(AZ::Data::AssetId scriptCanvasAssetId, int tabIndex = -1) = 0; - virtual AZ::Outcome OpenScriptCanvasAssetId(const AZ::Data::AssetId& scriptCanvasAsset) = 0; + virtual AZ::Outcome OpenScriptCanvasAsset(SourceHandle scriptCanvasAssetId, int tabIndex = -1) = 0; + virtual AZ::Outcome OpenScriptCanvasAssetId(const SourceHandle& scriptCanvasAsset) = 0; - virtual int CloseScriptCanvasAsset(const AZ::Data::AssetId&) = 0; + virtual int CloseScriptCanvasAsset(const SourceHandle&) = 0; virtual bool CreateScriptCanvasAssetFor(const TypeDefs::EntityComponentId& requestingComponent) = 0; - virtual bool IsScriptCanvasAssetOpen(const AZ::Data::AssetId& assetId) const = 0; + virtual bool IsScriptCanvasAssetOpen(const SourceHandle& assetId) const = 0; - virtual void OnChangeActiveGraphTab(AZ::Data::AssetId) {} + virtual void OnChangeActiveGraphTab(SourceHandle) {} virtual void CreateNewRuntimeAsset() = 0; @@ -103,12 +103,12 @@ namespace ScriptCanvasEditor return ScriptCanvas::ScriptCanvasId(); } - virtual GraphCanvas::GraphId FindGraphCanvasGraphIdByAssetId([[maybe_unused]] const AZ::Data::AssetId& assetId) const + virtual GraphCanvas::GraphId FindGraphCanvasGraphIdByAssetId([[maybe_unused]] const SourceHandle& assetId) const { return GraphCanvas::GraphId(); } - virtual ScriptCanvas::ScriptCanvasId FindScriptCanvasIdByAssetId([[maybe_unused]] const AZ::Data::AssetId& assetId) const + virtual ScriptCanvas::ScriptCanvasId FindScriptCanvasIdByAssetId([[maybe_unused]] const SourceHandle& assetId) const { return ScriptCanvas::ScriptCanvasId(); } diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h index cfd7d7ec8c..dc55f11d11 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h @@ -141,7 +141,7 @@ namespace ScriptCanvasEditor //// // RuntimeBus - AZ::Data::AssetId GetAssetId() const override { return m_assetId; } + //AZ::Data::AssetId GetAssetId() const override { return m_assetId; } //// // GraphCanvas::GraphModelRequestBus @@ -224,7 +224,7 @@ namespace ScriptCanvasEditor /////////////////////////// // EditorGraphRequestBus - void SetAssetId(const AZ::Data::AssetId& assetId) override { m_assetId = assetId; } + // void SetAssetId(const AZ::Data::AssetId& assetId) override { m_assetId = assetId; } void CreateGraphCanvasScene() override; void ClearGraphCanvasScene() override; @@ -392,6 +392,6 @@ namespace ScriptCanvasEditor //! Defaults to true to signal that this graph does not have the GraphCanvas stuff intermingled bool m_saveFormatConverted = true; - AZ::Data::AssetId m_assetId; + ScriptCanvasEditor::SourceHandle m_assetId; }; } diff --git a/Gems/ScriptCanvas/Code/Editor/QtMetaTypes.h b/Gems/ScriptCanvas/Code/Editor/QtMetaTypes.h index 9058e27b03..5e413f0266 100644 --- a/Gems/ScriptCanvas/Code/Editor/QtMetaTypes.h +++ b/Gems/ScriptCanvas/Code/Editor/QtMetaTypes.h @@ -11,11 +11,13 @@ AZ_PUSH_DISABLE_WARNING(4251 4800 4244, "-Wunknown-warning-option") #include AZ_POP_DISABLE_WARNING +#include #include #include - // VariableId is a UUID typedef for now. So we don't want to double reflect the UUID. Q_DECLARE_METATYPE(AZ::Uuid); Q_DECLARE_METATYPE(AZ::Data::AssetId); Q_DECLARE_METATYPE(ScriptCanvas::Data::Type); Q_DECLARE_METATYPE(ScriptCanvas::VariableId); +Q_DECLARE_METATYPE(ScriptCanvasEditor::SourceHandle); + diff --git a/Gems/ScriptCanvas/Code/Editor/Settings.h b/Gems/ScriptCanvas/Code/Editor/Settings.h index eefb7454c3..9065ac72f5 100644 --- a/Gems/ScriptCanvas/Code/Editor/Settings.h +++ b/Gems/ScriptCanvas/Code/Editor/Settings.h @@ -53,11 +53,10 @@ namespace ScriptCanvasEditor AZ_RTTI(WorkspaceAssetSaveData, "{927368CA-096F-4CF1-B2E0-1B9E4A93EA57}"); WorkspaceAssetSaveData(); - WorkspaceAssetSaveData(const AZ::Data::AssetId& assetId); + WorkspaceAssetSaveData(SourceHandle assetId); virtual ~WorkspaceAssetSaveData() = default; - AZ::Data::AssetId m_assetId; - AZ::Data::AssetType m_assetType; + SourceHandle m_assetId; }; @@ -69,9 +68,9 @@ namespace ScriptCanvasEditor EditorWorkspace() = default; - void ConfigureActiveAssets(AZ::Data::AssetId focusedAssetId, const AZStd::vector< WorkspaceAssetSaveData >& activeAssetIds); + void ConfigureActiveAssets(SourceHandle focusedAsset, const AZStd::vector< WorkspaceAssetSaveData >& activeAssetIds); - AZ::Data::AssetId GetFocusedAssetId() const; + SourceHandle GetFocusedAssetId() const; AZStd::vector< WorkspaceAssetSaveData > GetActiveAssetData() const; void Init(const QByteArray& windowState, const QByteArray& windowGeometry); @@ -79,7 +78,7 @@ namespace ScriptCanvasEditor void Clear() { - m_focusedAssetId.SetInvalid(); + m_focusedAssetId.Clear(); m_activeAssetData.clear(); } @@ -91,7 +90,7 @@ namespace ScriptCanvasEditor AZStd::vector m_windowGeometry; AZStd::vector m_windowState; - AZ::Data::AssetId m_focusedAssetId; + SourceHandle m_focusedAssetId; AZStd::vector< WorkspaceAssetSaveData > m_activeAssetData; }; diff --git a/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.cpp b/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.cpp index 06bbd29250..f2da3868de 100644 --- a/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.cpp @@ -15,7 +15,7 @@ namespace ScriptCanvasEditor { - AZ::Data::AssetId ReadRecentAssetId() + SourceHandle ReadRecentAssetId() { QSettings settings(QSettings::IniFormat, QSettings::UserScope, SCRIPTCANVASEDITOR_AZ_QCOREAPPLICATION_SETTINGS_ORGANIZATION_NAME); @@ -34,7 +34,7 @@ namespace ScriptCanvasEditor return assetId; } - void SetRecentAssetId(const AZ::Data::AssetId& assetId) + void SetRecentAssetId(SourceHandle assetId) { QSettings settings(QSettings::IniFormat, QSettings::UserScope, SCRIPTCANVASEDITOR_AZ_QCOREAPPLICATION_SETTINGS_ORGANIZATION_NAME); diff --git a/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.h b/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.h index 0aa4332ca4..35666d7c34 100644 --- a/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.h +++ b/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.h @@ -11,7 +11,7 @@ namespace ScriptCanvasEditor { - AZ::Data::AssetId ReadRecentAssetId(); - void SetRecentAssetId(const AZ::Data::AssetId& assetId); + SourceHandle ReadRecentAssetId(); + void SetRecentAssetId(SourceHandle assetId); void ClearRecentAssetId(); } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/AssetGraphSceneDataBus.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/AssetGraphSceneDataBus.h index cbb8ef12d6..6d2c3280ac 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/AssetGraphSceneDataBus.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/AssetGraphSceneDataBus.h @@ -11,14 +11,16 @@ #include #include #include +#include namespace ScriptCanvasEditor { + // #sc-editor-asset remove this class AssetGraphScene : public AZ::EBusTraits { public: - virtual AZ::EntityId FindEditorNodeIdByAssetNodeId(const AZ::Data::AssetId& assetId, AZ::EntityId assetNodeId) const = 0; - virtual AZ::EntityId FindAssetNodeIdByEditorNodeId(const AZ::Data::AssetId& assetId, AZ::EntityId editorNodeId) const = 0; + virtual AZ::EntityId FindEditorNodeIdByAssetNodeId(const SourceHandle& assetId, AZ::EntityId assetNodeId) const = 0; + virtual AZ::EntityId FindAssetNodeIdByEditorNodeId(const SourceHandle& assetId, AZ::EntityId editorNodeId) const = 0; }; using AssetGraphSceneBus = AZ::EBus; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h index 47a5cb8651..490c17cc29 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h @@ -45,14 +45,14 @@ namespace ScriptCanvasEditor GraphTabBar(QWidget* parent = nullptr); ~GraphTabBar() override = default; - void AddGraphTab(const AZ::Data::AssetId& assetId); - int InsertGraphTab(int tabIndex, const AZ::Data::AssetId& assetId); - bool SelectTab(const AZ::Data::AssetId& assetId); + void AddGraphTab(ScriptCanvasEditor::SourceHandle assetId); + int InsertGraphTab(int tabIndex, ScriptCanvasEditor::SourceHandle assetId); + bool SelectTab(ScriptCanvasEditor::SourceHandle assetId); - void ConfigureTab(int tabIndex, AZ::Data::AssetId fileAssetId, const AZStd::string& tabName); + void ConfigureTab(int tabIndex, ScriptCanvasEditor::SourceHandle fileAssetId, const AZStd::string& tabName); - int FindTab(const AZ::Data::AssetId& assetId) const; - AZ::Data::AssetId FindAssetId(int tabIndex); + int FindTab(ScriptCanvasEditor::SourceHandle assetId) const; + ScriptCanvasEditor::SourceHandle FindAssetId(int tabIndex); void CloseTab(int index); void CloseAllTabs(); @@ -92,7 +92,7 @@ namespace ScriptCanvasEditor // Called when the selected tab changes void currentChangedTab(int index); - void SetFileState(AZ::Data::AssetId assetId, Tracker::ScriptCanvasFileState fileState); + void SetFileState(ScriptCanvasEditor::SourceHandle, Tracker::ScriptCanvasFileState fileState); int m_signalSaveOnChangeTo = -1; }; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index 8be4c1db06..cb66be6ba8 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -257,20 +257,12 @@ namespace ScriptCanvasEditor assetSaveData.m_assetId = sourceId; ScriptCanvas::ScriptCanvasId scriptCanvasId = m_mainWindow->FindScriptCanvasIdByAssetId(assetId); - - EditorGraphRequests* editorRequests = EditorGraphRequestBus::FindFirstHandler(scriptCanvasId); - - if (editorRequests) - { - assetSaveData.m_assetType = azrtti_typeid(); - } - activeAssets.push_back(assetSaveData); } } else if (assetId == focusedAssetId) { - focusedAssetId.SetInvalid(); + focusedAssetId.Clear(); } } @@ -326,36 +318,38 @@ namespace ScriptCanvasEditor m_queuedAssetFocus = workspace->GetFocusedAssetId(); - for (const auto& assetSaveData : workspace->GetActiveAssetData()) + // #sc-asset-editor + //for (const auto& assetSaveData : workspace->GetActiveAssetData()) { - AssetTrackerNotificationBus::MultiHandler::BusConnect(assetSaveData.m_assetId); - - Callbacks::OnAssetReadyCallback onAssetReady = [this, assetSaveData](ScriptCanvasMemoryAsset& asset) - { - // If we get an error callback. Just remove it from out active lists. - if (asset.IsSourceInError()) - { - if (assetSaveData.m_assetId == m_queuedAssetFocus) - { - m_queuedAssetFocus = ScriptCanvasEditor::SourceHandle(); - } - - SignalAssetComplete(asset.GetFileAssetId()); - } - }; - - bool loadedFile = true; - AssetTrackerRequestBus::BroadcastResult(loadedFile, &AssetTrackerRequests::Load, assetSaveData.m_assetId, assetSaveData.m_assetType, onAssetReady); - - if (!loadedFile) - { - if (assetSaveData.m_assetId == m_queuedAssetFocus) - { - m_queuedAssetFocus = ScriptCanvasEditor::SourceHandle(); - } - - SignalAssetComplete(assetSaveData.m_assetId); - } + // load all the files +// AssetTrackerNotificationBus::MultiHandler::BusConnect(assetSaveData.m_assetId); +// +// Callbacks::OnAssetReadyCallback onAssetReady = [this, assetSaveData](ScriptCanvasMemoryAsset& asset) +// { +// // If we get an error callback. Just remove it from out active lists. +// if (asset.IsSourceInError()) +// { +// if (assetSaveData.m_assetId == m_queuedAssetFocus) +// { +// m_queuedAssetFocus = ScriptCanvasEditor::SourceHandle(); +// } +// +// SignalAssetComplete(asset.GetFileAssetId()); +// } +// }; +// +// bool loadedFile = true; +// AssetTrackerRequestBus::BroadcastResult(loadedFile, &AssetTrackerRequests::Load, assetSaveData.m_assetId, assetSaveData.m_assetType, onAssetReady); +// +// if (!loadedFile) +// { +// if (assetSaveData.m_assetId == m_queuedAssetFocus) +// { +// m_queuedAssetFocus = ScriptCanvasEditor::SourceHandle(); +// } +// +// SignalAssetComplete(assetSaveData.m_assetId); +// } } } else @@ -367,45 +361,38 @@ namespace ScriptCanvasEditor void Workspace::OnAssetReady(const ScriptCanvasMemoryAsset::pointer memoryAsset) { - const ScriptCanvasEditor::SourceHandle& fileAssetId = memoryAsset->GetFileAssetId(); - - if (AssetTrackerNotificationBus::MultiHandler::BusIsConnectedId(fileAssetId)) - { - AssetTrackerNotificationBus::MultiHandler::BusDisconnect(fileAssetId); - - m_mainWindow->OpenScriptCanvasAsset(*memoryAsset); - - SignalAssetComplete(fileAssetId); - } + // open the file in the main window +// const ScriptCanvasEditor::SourceHandle& fileAssetId = memoryAsset->GetFileAssetId(); +// +// if (AssetTrackerNotificationBus::MultiHandler::BusIsConnectedId(fileAssetId)) +// { +// AssetTrackerNotificationBus::MultiHandler::BusDisconnect(fileAssetId); +// +// m_mainWindow->OpenScriptCanvasAsset(*memoryAsset); +// +// SignalAssetComplete(fileAssetId); +// } } - void Workspace::SignalAssetComplete(const ScriptCanvasEditor::SourceHandle& fileAssetId) + void Workspace::SignalAssetComplete(const ScriptCanvasEditor::SourceHandle& /*fileAssetId*/) { - auto it = AZStd::find(m_loadingAssets.begin(), m_loadingAssets.end(), fileAssetId); - if (it != m_loadingAssets.end()) - { - m_loadingAssets.erase(it); - } - - //! When we are done loading all assets we can safely set the focus to the recorded asset - if (m_loadingAssets.empty()) - { - m_mainWindow->OnWorkspaceRestoreEnd(m_queuedAssetFocus); - m_queuedAssetFocus.SetInvalid(); - } + // When we are done loading all assets we can safely set the focus to the recorded asset +// auto it = AZStd::find(m_loadingAssets.begin(), m_loadingAssets.end(), fileAssetId); +// if (it != m_loadingAssets.end()) +// { +// m_loadingAssets.erase(it); +// } +// +// if (m_loadingAssets.empty()) +// { +// m_mainWindow->OnWorkspaceRestoreEnd(m_queuedAssetFocus); +// m_queuedAssetFocus.SetInvalid(); +// } } ScriptCanvasEditor::SourceHandle Workspace::GetSourceAssetId(const ScriptCanvasEditor::SourceHandle& memoryAssetId) const { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, memoryAssetId); - - if (memoryAsset) - { - return memoryAsset->GetFileAssetId(); - } - - return ScriptCanvasEditor::SourceHandle(); + return memoryAssetId; } //////////////// @@ -832,6 +819,8 @@ namespace ScriptCanvasEditor void MainWindow::SignalActiveSceneChanged(ScriptCanvasEditor::SourceHandle assetId) { + // #sc-editor-asset + /* ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); @@ -869,7 +858,7 @@ namespace ScriptCanvasEditor } UpdateMenuState(enabled); - + */ } void MainWindow::UpdateRecentMenu() @@ -949,21 +938,22 @@ namespace ScriptCanvasEditor if (shouldSaveResults == UnsavedChangesOptions::SAVE) { - Callbacks::OnSave saveCB = [this](bool isSuccessful, AZ::Data::AssetPtr, ScriptCanvasEditor::SourceHandle) - { - if (isSuccessful) - { - // Continue closing. - qobject_cast(parent())->close(); - } - else - { - // Abort closing. - QMessageBox::critical(this, QString(), QObject::tr("Failed to save.")); - m_processedClosedAssetIds.clear(); - } - }; - ActivateAndSaveAsset(assetId, saveCB); + // #sc-editor-asset +// Callbacks::OnSave saveCB = [this](bool isSuccessful, AZ::Data::AssetPtr, ScriptCanvasEditor::SourceHandle) +// { +// if (isSuccessful) +// { +// // Continue closing. +// qobject_cast(parent())->close(); +// } +// else +// { +// // Abort closing. +// QMessageBox::critical(this, QString(), QObject::tr("Failed to save.")); +// m_processedClosedAssetIds.clear(); +// } +// }; +// ActivateAndSaveAsset(assetId, saveCB); event->ignore(); return; } @@ -985,15 +975,15 @@ namespace ScriptCanvasEditor m_workspace->Save(); // Close all files. - - AssetTrackerRequests::AssetList allAssets; - AssetTrackerRequestBus::BroadcastResult(allAssets, &AssetTrackerRequests::GetAssets); - - for (auto trackedAsset : allAssets) - { - const ScriptCanvasEditor::SourceHandle& assetId = trackedAsset->GetAsset().GetId(); - CloseScriptCanvasAsset(assetId); - } +// +// AssetTrackerRequests::AssetList allAssets; +// AssetTrackerRequestBus::BroadcastResult(allAssets, &AssetTrackerRequests::GetAssets); +// +// for (auto trackedAsset : allAssets) +// { +// const ScriptCanvasEditor::SourceHandle& assetId = trackedAsset->GetAsset().GetId(); +// CloseScriptCanvasAsset(assetId); +// } m_processedClosedAssetIds.clear(); @@ -1146,29 +1136,31 @@ namespace ScriptCanvasEditor m_preventUndoStateUpdateCount = 0; } - void MainWindow::MarkAssetModified(const ScriptCanvasEditor::SourceHandle& assetId) + void MainWindow::MarkAssetModified(const ScriptCanvasEditor::SourceHandle& /*assetId*/) { - if (!assetId.IsValid()) - { - return; - } - - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); - - if (memoryAsset) - { - const auto& memoryAssetId = memoryAsset->GetId(); - const Tracker::ScriptCanvasFileState& fileState = GetAssetFileState(memoryAssetId); - if (fileState != Tracker::ScriptCanvasFileState::NEW) - { - AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::UpdateFileState, memoryAssetId, Tracker::ScriptCanvasFileState::MODIFIED); - } - } +// #sc-editor-asset if (!assetId.IsValid()) +// { +// return; +// } +// +// ScriptCanvasMemoryAsset::pointer memoryAsset; +// AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); +// +// if (memoryAsset) +// { +// const auto& memoryAssetId = memoryAsset->GetId(); +// const Tracker::ScriptCanvasFileState& fileState = GetAssetFileState(memoryAssetId); +// if (fileState != Tracker::ScriptCanvasFileState::NEW) +// { +// AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::UpdateFileState, memoryAssetId, Tracker::ScriptCanvasFileState::MODIFIED); +// } +// } } - void MainWindow::RefreshScriptCanvasAsset(const AZ::Data::Asset& asset) + void MainWindow::RefreshScriptCanvasAsset(const AZ::Data::Asset& /*asset*/) { + // #sc-editor-asset + /* ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, asset.GetId()); @@ -1197,10 +1189,14 @@ namespace ScriptCanvasEditor GraphCanvas::SceneMemberNotificationBus::Event(graphCanvasId, &GraphCanvas::SceneMemberNotifications::OnSceneReady); } } + */ } - AZ::Outcome MainWindow::OpenScriptCanvasAssetId(const ScriptCanvasEditor::SourceHandle& fileAssetId) + AZ::Outcome MainWindow::OpenScriptCanvasAssetId(const ScriptCanvasEditor::SourceHandle& /*fileAssetId*/) { + // #sc-editor-asset + return AZ::Failure(AZStd::string("rewrite MainWindow::OpenScriptCanvasAssetId")); + /* if (!fileAssetId.IsValid()) { return AZ::Failure(AZStd::string("Unable to open asset with invalid asset id")); @@ -1259,10 +1255,14 @@ namespace ScriptCanvasEditor { return AZ::Failure(AZStd::string("Specified asset is in an error state and cannot be properly displayed.")); } + */ } - AZ::Outcome MainWindow::OpenScriptCanvasAsset(const ScriptCanvasMemoryAsset& scriptCanvasAsset, int tabIndex /*= -1*/) + AZ::Outcome MainWindow::OpenScriptCanvasAsset(const ScriptCanvasMemoryAsset& /*scriptCanvasAsset*/, int /*tabIndex*/ /*= -1*/) { + // #sc-editor-asset + return AZ::Failure(AZStd::string("rewrite MainWindow::OpenScriptCanvasAsset")); + /* const ScriptCanvasEditor::SourceHandle& fileAssetId = scriptCanvasAsset.GetFileAssetId(); if (!fileAssetId.IsValid()) { @@ -1334,10 +1334,14 @@ namespace ScriptCanvasEditor AssetTrackerNotificationBus::MultiHandler::BusConnect(fileAssetId); return AZ::Success(outTabIndex); + */ } - AZ::Outcome MainWindow::OpenScriptCanvasAsset(ScriptCanvasEditor::SourceHandle scriptCanvasAssetId, int tabIndex /*= -1*/) + AZ::Outcome MainWindow::OpenScriptCanvasAsset(ScriptCanvasEditor::SourceHandle /*scriptCanvasAssetId*/, int /*tabIndex*/ /*= -1*/) { + // #sc-editor-asset + return AZ::Failure(AZStd::string("rewrite MainWindow::OpenScriptCanvasAsset")); + /* ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, scriptCanvasAssetId); @@ -1350,15 +1354,22 @@ namespace ScriptCanvasEditor { return OpenScriptCanvasAssetId(scriptCanvasAssetId); } + */ } - int MainWindow::CreateAssetTab(const ScriptCanvasEditor::SourceHandle& assetId, int tabIndex) + int MainWindow::CreateAssetTab(const ScriptCanvasEditor::SourceHandle& /*assetId*/, int /*tabIndex*/) { - return m_tabBar->InsertGraphTab(tabIndex, assetId); + // #sc-editor-asset + return -1; + // return m_tabBar->InsertGraphTab(tabIndex, assetId); } - AZ::Outcome MainWindow::UpdateScriptCanvasAsset(const AZ::Data::Asset& scriptCanvasAsset) + AZ::Outcome MainWindow::UpdateScriptCanvasAsset(const AZ::Data::Asset& /*scriptCanvasAsset*/) { + // #sc-editor-asset + return AZ::Failure(AZStd::string("rewrite MainWindow::UpdateScriptCanvasAsset")); + + /* int outTabIndex = -1; PushPreventUndoStateUpdate(); @@ -1375,10 +1386,13 @@ namespace ScriptCanvasEditor } return AZ::Success(outTabIndex); + */ } - void MainWindow::RemoveScriptCanvasAsset(const ScriptCanvasEditor::SourceHandle& assetId) + void MainWindow::RemoveScriptCanvasAsset(const ScriptCanvasEditor::SourceHandle& /*assetId*/) { + // #sc-editor-asset move what is necessary to the widget + /* AssetHelpers::PrintInfo("RemoveScriptCanvasAsset : %s", AssetHelpers::AssetIdToString(assetId).c_str()); m_assetCreationRequests.erase(assetId); @@ -1406,7 +1420,7 @@ namespace ScriptCanvasEditor auto tabAssetId = tabdata.value(); SetActiveAsset(tabAssetId); } - + */ } int MainWindow::CloseScriptCanvasAsset(const ScriptCanvasEditor::SourceHandle& assetId) @@ -1449,12 +1463,10 @@ namespace ScriptCanvasEditor return createdNewAsset; } - bool MainWindow::IsScriptCanvasAssetOpen(const ScriptCanvasEditor::SourceHandle& assetId) const + bool MainWindow::IsScriptCanvasAssetOpen(const ScriptCanvasEditor::SourceHandle& /*assetId*/) const { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); - - return memoryAsset != nullptr; + // #sc-editor-asset + return false; } const CategoryInformation* MainWindow::FindNodePaletteCategoryInformation(AZStd::string_view categoryPath) const @@ -1467,8 +1479,10 @@ namespace ScriptCanvasEditor return m_nodePaletteModel.FindNodePaletteInformation(nodeType); } - void MainWindow::GetSuggestedFullFilenameToSaveAs(const ScriptCanvasEditor::SourceHandle& assetId, AZStd::string& filePath, AZStd::string& fileFilter) + void MainWindow::GetSuggestedFullFilenameToSaveAs(const ScriptCanvasEditor::SourceHandle& /*assetId*/, AZStd::string& /*filePath*/, AZStd::string& /*fileFilter*/) { + // #sc-editor-asset + /* ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); @@ -1509,6 +1523,7 @@ namespace ScriptCanvasEditor AZStd::array resolvedPath; AZ::IO::FileIOBase::GetInstance()->ResolvePath(assetPath.data(), resolvedPath.data(), resolvedPath.size()); filePath = resolvedPath.data(); + */ } void MainWindow::OpenFile(const char* fullPath) @@ -1527,7 +1542,8 @@ namespace ScriptCanvasEditor return; } -#if defined(EDITOR_ASSET_SUPPORT_ENABLED) +#if defined(EDITOR_ASSET_SUPPORT_ENABLED) + /* m_errorFilePath = fullPath; // Let's find the source file on disk @@ -1574,12 +1590,13 @@ namespace ScriptCanvasEditor }; // TODO-LS the assetInfo.m_assetType is always null for some reason, I know in this case we want default assets so it's ok to hardcode it - AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::Load, assetInfo.m_assetId, /*assetInfo.m_assetType*/azrtti_typeid(), onAssetReady); + AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::Load, assetInfo.m_assetId, assetInfo.m_assetType, azrtti_typeid(), onAssetReady); } else { QMessageBox::warning(this, "Invalid Source Asset", QString("'%1' is not a valid asset path.").arg(fullPath), QMessageBox::Ok); } + */ #endif } @@ -1703,7 +1720,7 @@ namespace ScriptCanvasEditor if (!IsTabOpen(assetId, outTabIndex)) { - AZ_Assert(false, AZStd::string::format("Unable to open new Script Canvas Asset with id %s in the Script Canvas Editor", AssetHelpers::AssetIdToString(assetId).c_str()).c_str()); + AZ_Assert(false, AZStd::string::format("Unable to open new Script Canvas Asset with id %s in the Script Canvas Editor", assetId.ToString().c_str()).c_str()); return -1; } @@ -1723,31 +1740,32 @@ namespace ScriptCanvasEditor } } - AZ::Outcome MainWindow::CreateScriptCanvasAsset(AZStd::string_view assetPath, AZ::Data::AssetType assetType, int tabIndex) + AZ::Outcome MainWindow::CreateScriptCanvasAsset(AZStd::string_view /*assetPath*/, AZ::Data::AssetType /*assetType*/, int /*tabIndex*/) { - int outTabIndex = -1; + return AZ::Failure(AZStd::string("MainWindow::CreateScriptCanvasAsset just make a new thing with the project root + untitled...")); +// int outTabIndex = -1; +// +// ScriptCanvasEditor::SourceHandle newAssetId; +// auto onAssetCreated = [this, assetPath, tabIndex, &outTabIndex](ScriptCanvasMemoryAsset& asset) +// { +// const ScriptCanvasEditor::SourceHandle& assetId = asset.GetId(); +// +// outTabIndex = InsertTabForAsset(assetPath, assetId, tabIndex); +// +// SetActiveAsset(assetId); +// +// UpdateScriptCanvasAsset(asset.GetAsset()); +// +// AZ::EntityId scriptCanvasEntityId; +// AssetTrackerRequestBus::BroadcastResult(scriptCanvasEntityId, &AssetTrackerRequests::GetScriptCanvasId, assetId); +// +// GraphCanvas::GraphId graphCanvasGraphId = GetGraphCanvasGraphId(scriptCanvasEntityId); +// GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId, &GraphCanvas::AssetEditorNotifications::OnGraphLoaded, graphCanvasGraphId); +// +// }; +// AssetTrackerRequestBus::BroadcastResult(newAssetId, &AssetTrackerRequests::Create, assetPath, assetType, onAssetCreated); - ScriptCanvasEditor::SourceHandle newAssetId; - auto onAssetCreated = [this, assetPath, tabIndex, &outTabIndex](ScriptCanvasMemoryAsset& asset) - { - const ScriptCanvasEditor::SourceHandle& assetId = asset.GetId(); - - outTabIndex = InsertTabForAsset(assetPath, assetId, tabIndex); - - SetActiveAsset(assetId); - - UpdateScriptCanvasAsset(asset.GetAsset()); - - AZ::EntityId scriptCanvasEntityId; - AssetTrackerRequestBus::BroadcastResult(scriptCanvasEntityId, &AssetTrackerRequests::GetScriptCanvasId, assetId); - - GraphCanvas::GraphId graphCanvasGraphId = GetGraphCanvasGraphId(scriptCanvasEntityId); - GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId, &GraphCanvas::AssetEditorNotifications::OnGraphLoaded, graphCanvasGraphId); - - }; - AssetTrackerRequestBus::BroadcastResult(newAssetId, &AssetTrackerRequests::Create, assetPath, assetType, onAssetCreated); - - return AZ::Success(outTabIndex); + // return AZ::Success(outTabIndex); } bool MainWindow::OnFileSave(const Callbacks::OnSave& saveCB) @@ -1873,8 +1891,11 @@ namespace ScriptCanvasEditor return false; } - void MainWindow::OnSaveCallback(bool saveSuccess, AZ::Data::AssetPtr fileAsset, ScriptCanvasEditor::SourceHandle previousFileAssetId) + void MainWindow::OnSaveCallback(bool /*saveSuccess*/, AZ::Data::AssetPtr /*fileAsset*/, ScriptCanvasEditor::SourceHandle /*previousFileAssetId*/) { + // #sc-editor-asset yikes...just save the thing...move to ::SaveAsset maybe + + /* ScriptCanvasMemoryAsset::pointer memoryAsset; AZStd::string tabName = m_tabBar->tabText(m_tabBar->currentIndex()).toUtf8().data(); @@ -1997,6 +2018,7 @@ namespace ScriptCanvasEditor EnableAssetView(memoryAsset); UnblockCloseRequests(); + */ } bool MainWindow::ActivateAndSaveAsset(const ScriptCanvasEditor::SourceHandle& unsavedAssetId, const Callbacks::OnSave& saveCB) @@ -2005,8 +2027,9 @@ namespace ScriptCanvasEditor return OnFileSave(saveCB); } - void MainWindow::SaveAsset(ScriptCanvasEditor::SourceHandle assetId, const Callbacks::OnSave& onSave) + void MainWindow::SaveAsset(ScriptCanvasEditor::SourceHandle /*assetId*/, const Callbacks::OnSave& /*onSave*/) { + /* PrepareAssetForSave(assetId); auto onSaveCallback = [this, onSave](bool saveSuccess, AZ::Data::AssetPtr asset, ScriptCanvasEditor::SourceHandle previousAssetId) @@ -2031,10 +2054,12 @@ namespace ScriptCanvasEditor } BlockCloseRequests(); + */ } - void MainWindow::SaveNewAsset(AZStd::string_view path, ScriptCanvasEditor::SourceHandle inMemoryAssetId, const Callbacks::OnSave& onSave) + void MainWindow::SaveNewAsset(AZStd::string_view /*path*/, ScriptCanvasEditor::SourceHandle /*inMemoryAssetId*/, const Callbacks::OnSave& /*onSave*/) { + /* PrepareAssetForSave(inMemoryAssetId); auto onSaveCallback = [this, onSave](bool saveSuccess, AZ::Data::AssetPtr asset, ScriptCanvasEditor::SourceHandle previousAssetId) @@ -2059,6 +2084,7 @@ namespace ScriptCanvasEditor } BlockCloseRequests(); + */ } void MainWindow::OnFileOpen() @@ -2067,8 +2093,6 @@ namespace ScriptCanvasEditor EBUS_EVENT_RESULT(serializeContext, AZ::ComponentApplicationBus, GetSerializeContext); AZ_Assert(serializeContext, "Failed to acquire application serialize context."); - ScriptCanvasEditor::SourceHandle openId = ReadRecentAssetId(); - AZStd::string assetRoot; { AZStd::array assetRootChar; @@ -2076,18 +2100,7 @@ namespace ScriptCanvasEditor assetRoot = assetRootChar.data(); } - AZStd::string assetPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, openId); - if (!assetPath.empty()) - { - assetPath = AZStd::string::format("%s/%s", assetRoot.c_str(), assetPath.c_str()); - } - - if (!openId.IsValid() || !QFile::exists(assetPath.c_str())) - { - assetPath = AZStd::string::format("%s/scriptcanvas", assetRoot.c_str()); - } - assetPath = AZStd::string::format("%s/scriptcanvas", assetRoot.c_str()); + AZStd::string assetPath = AZStd::string::format("%s/scriptcanvas", assetRoot.c_str()); AZ::EBusAggregateResults> fileFilters; AssetRegistryRequestBus::BroadcastResult(fileFilters, &AssetRegistryRequests::GetAssetHandlerFileFilters); @@ -2469,8 +2482,10 @@ namespace ScriptCanvasEditor GraphCanvas::ViewRequestBus::Event(viewId, &GraphCanvas::ViewRequests::CenterOnEndOfChain); } - void MainWindow::UpdateWorkspaceStatus(const ScriptCanvasMemoryAsset& memoryAsset) + void MainWindow::UpdateWorkspaceStatus(const ScriptCanvasMemoryAsset& /*memoryAsset*/) { + // only occurs on file open, do it there, if necessary + /* ScriptCanvasEditor::SourceHandle fileAssetId = memoryAsset.GetFileAssetId(); size_t eraseCount = m_loadingAssets.erase(fileAssetId); @@ -2492,6 +2507,7 @@ namespace ScriptCanvasEditor } } } + */ } void MainWindow::OnCanUndoChanged(bool canUndo) @@ -2550,49 +2566,69 @@ namespace ScriptCanvasEditor AZ::EntityId MainWindow::GetActiveGraphCanvasGraphId() const { - AZ::EntityId graphId; - AssetTrackerRequestBus::BroadcastResult(graphId, &AssetTrackerRequests::GetGraphId, m_activeGraph); - return graphId; + // #sc-editor-asset + + // AZ::EntityId graphId; + // AssetTrackerRequestBus::BroadcastResult(graphId, &AssetTrackerRequests::GetGraphId, m_activeGraph); + /* + * Falls through to this, which falls through to editor graph, move to canvas widget + AZ::EntityId ScriptCanvasMemoryAsset::GetGraphId() + { + if (!m_graphId.IsValid()) + { + EditorGraphRequestBus::EventResult(m_graphId, m_scriptCanvasId, &EditorGraphRequests::GetGraphCanvasGraphId); + } + + return m_graphId; + } + */ + return AZ::EntityId{}; } ScriptCanvas::ScriptCanvasId MainWindow::GetActiveScriptCanvasId() const { - ScriptCanvas::ScriptCanvasId sceneId; - AssetTrackerRequestBus::BroadcastResult(sceneId, &AssetTrackerRequests::GetScriptCanvasId, m_activeGraph); - return sceneId; + // ScriptCanvas::ScriptCanvasId sceneId; + // AssetTrackerRequestBus::BroadcastResult(sceneId, &AssetTrackerRequests::GetScriptCanvasId, m_activeGraph); + // #sc-editor-asset + return ScriptCanvas::ScriptCanvasId{}; } - GraphCanvas::GraphId MainWindow::GetGraphCanvasGraphId(const ScriptCanvas::ScriptCanvasId& scriptCanvasId) const + GraphCanvas::GraphId MainWindow::GetGraphCanvasGraphId(const ScriptCanvas::ScriptCanvasId& /*scriptCanvasId*/) const { - AZ::EntityId graphCanvasId; - AssetTrackerRequestBus::BroadcastResult(graphCanvasId, &AssetTrackerRequests::GetGraphCanvasId, scriptCanvasId); - - return graphCanvasId; + // #sc-editor-asset + // AZ::EntityId graphCanvasId; + // AssetTrackerRequestBus::BroadcastResult(graphCanvasId, &AssetTrackerRequests::GetGraphCanvasId, scriptCanvasId); + // move to widget + return AZ::EntityId{}; } - GraphCanvas::GraphId MainWindow::FindGraphCanvasGraphIdByAssetId(const ScriptCanvasEditor::SourceHandle& assetId) const + GraphCanvas::GraphId MainWindow::FindGraphCanvasGraphIdByAssetId(const ScriptCanvasEditor::SourceHandle& /*assetId*/) const { - AZ::EntityId graphId; - AssetTrackerRequestBus::BroadcastResult(graphId, &AssetTrackerRequests::GetGraphId, assetId); - return graphId; + // #sc-editor-asset + // AZ::EntityId graphId; + // AssetTrackerRequestBus::BroadcastResult(graphId, &AssetTrackerRequests::GetGraphId, assetId); + return AZ::EntityId{}; } - ScriptCanvas::ScriptCanvasId MainWindow::FindScriptCanvasIdByAssetId(const ScriptCanvasEditor::SourceHandle& assetId) const + ScriptCanvas::ScriptCanvasId MainWindow::FindScriptCanvasIdByAssetId(const ScriptCanvasEditor::SourceHandle& /*assetId*/) const { - ScriptCanvas::ScriptCanvasId scriptCanvasId; - AssetTrackerRequestBus::BroadcastResult(scriptCanvasId, &AssetTrackerRequests::GetScriptCanvasId, assetId); - return scriptCanvasId; + // #sc-editor-asset + // ScriptCanvas::ScriptCanvasId scriptCanvasId; + // AssetTrackerRequestBus::BroadcastResult(scriptCanvasId, &AssetTrackerRequests::GetScriptCanvasId, assetId); + return ScriptCanvas::ScriptCanvasId{}; } - ScriptCanvas::ScriptCanvasId MainWindow::GetScriptCanvasId(const GraphCanvas::GraphId& graphCanvasGraphId) const + ScriptCanvas::ScriptCanvasId MainWindow::GetScriptCanvasId(const GraphCanvas::GraphId& /*graphCanvasGraphId*/) const { - ScriptCanvas::ScriptCanvasId scriptCanvasId; - AssetTrackerRequestBus::BroadcastResult(scriptCanvasId, &AssetTrackerRequests::GetScriptCanvasIdFromGraphId, graphCanvasGraphId); - return scriptCanvasId; + // #sc-editor-asset + // ScriptCanvas::ScriptCanvasId scriptCanvasId; + // AssetTrackerRequestBus::BroadcastResult(scriptCanvasId, &AssetTrackerRequests::GetScriptCanvasIdFromGraphId, graphCanvasGraphId); + return ScriptCanvas::ScriptCanvasId{}; } bool MainWindow::IsInUndoRedo(const AZ::EntityId& graphCanvasGraphId) const { + // #sc-editor-asset bool isActive = false; UndoRequestBus::EventResult(isActive, GetScriptCanvasId(graphCanvasGraphId), &UndoRequests::IsActive); return isActive; @@ -2645,8 +2681,10 @@ namespace ScriptCanvasEditor return false; } - void MainWindow::ReconnectSceneBuses(ScriptCanvasEditor::SourceHandle previousAssetId, ScriptCanvasEditor::SourceHandle nextAssetId) + void MainWindow::ReconnectSceneBuses(ScriptCanvasEditor::SourceHandle /*previousAssetId*/, ScriptCanvasEditor::SourceHandle /*nextAssetId*/) { + // #sc-editor-asset + /* ScriptCanvasMemoryAsset::pointer previousAsset; AssetTrackerRequestBus::BroadcastResult(previousAsset, &AssetTrackerRequests::GetAsset, previousAssetId); @@ -2678,17 +2716,19 @@ namespace ScriptCanvasEditor // Notify about the graph refresh GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId, &GraphCanvas::AssetEditorNotifications::OnGraphRefreshed, previousScriptCanvasSceneId, nextAssetGraphCanvasId); - + */ } - void MainWindow::SetActiveAsset(const ScriptCanvasEditor::SourceHandle& fileAssetId) + void MainWindow::SetActiveAsset(const ScriptCanvasEditor::SourceHandle& /*fileAssetId*/) { + // #sc-editor-asset + /* if (m_activeGraph == fileAssetId) { return; } - AssetHelpers::PrintInfo("SetActiveAsset : from: %s to %s", AssetHelpers::AssetIdToString(m_activeGraph).c_str(), AssetHelpers::AssetIdToString(fileAssetId).c_str()); + AssetHelpers::PrintInfo("SetActiveAsset : from: %s to %s", m_activeGraph.ToString().c_str(), fileAssetId.ToString().c_str()); if (fileAssetId.IsValid()) { @@ -2730,7 +2770,7 @@ namespace ScriptCanvasEditor { ScriptCanvasEditor::SourceHandle previousAssetId = m_activeGraph; - m_activeGraph.SetInvalid(); + m_activeGraph.Clear(); m_emptyCanvas->show(); ReconnectSceneBuses(previousAssetId, m_activeGraph); @@ -2741,13 +2781,16 @@ namespace ScriptCanvasEditor UpdateUndoCache(fileAssetId); RefreshSelection(); + */ } void MainWindow::RefreshActiveAsset() { + // #sc-editor-asset + /* if (m_activeGraph.IsValid()) { - AssetHelpers::PrintInfo("RefreshActiveAsset : m_activeGraph (%s)", AssetHelpers::AssetIdToString(m_activeGraph).c_str()); + AssetHelpers::PrintInfo("RefreshActiveAsset : m_activeGraph (%s)", m_activeGraph.ToString().c_str()); ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeGraph); @@ -2769,7 +2812,7 @@ namespace ScriptCanvasEditor AZ_Assert(view, "Asset should have a view"); if (view) { - AssetHelpers::PrintInfo("RefreshActiveAsset : m_activeGraph (%s)", AssetHelpers::AssetIdToString(m_activeGraph).c_str()); + AssetHelpers::PrintInfo("RefreshActiveAsset : m_activeGraph (%s)", m_activeGraph.ToString().c_str()); view->ShowScene(sceneEntityId); m_layout->addWidget(view); @@ -2787,36 +2830,41 @@ namespace ScriptCanvasEditor SetActiveAsset({}); } } + */ } void MainWindow::Clear() { m_tabBar->CloseAllTabs(); - - AssetTrackerRequests::AssetList assets; - AssetTrackerRequestBus::BroadcastResult(assets, &AssetTrackerRequests::GetAssets); - - for (auto asset : assets) - { - RemoveScriptCanvasAsset(asset->GetAsset().GetId()); - } + // #sc-editor-asset +// +// AssetTrackerRequests::AssetList assets; +// AssetTrackerRequestBus::BroadcastResult(assets, &AssetTrackerRequests::GetAssets); +// +// for (auto asset : assets) +// { +// RemoveScriptCanvasAsset(asset->GetAsset().GetId()); +// } SetActiveAsset({}); } void MainWindow::OnTabCloseButtonPressed(int index) { + QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) { auto fileAssetId = tabdata.value(); - Tracker::ScriptCanvasFileState fileState; - AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, fileAssetId); - + Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::NEW; bool isSaving = false; - AssetTrackerRequestBus::BroadcastResult(isSaving, &AssetTrackerRequests::IsSaving, fileAssetId); + // #sc-editor-asset Get from widgets + /* + AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, fileAssetId); + AssetTrackerRequestBus::BroadcastResult(isSaving, &AssetTrackerRequests::IsSaving, fileAssetId); + */ if (isSaving) { m_closeCurrentGraphAfterSave = true; @@ -2828,42 +2876,44 @@ namespace ScriptCanvasEditor { SetActiveAsset(fileAssetId); - AZStd::string tabName; - AssetTrackerRequestBus::BroadcastResult(tabName, &AssetTrackerRequests::GetTabName, fileAssetId); + // #sc-editor-asset + AZStd::string tabName = "Get from widget"; + // AssetTrackerRequestBus::BroadcastResult(tabName, &AssetTrackerRequests::GetTabName, fileAssetId); saveDialogResults = ShowSaveDialog(tabName.c_str()); } if (saveDialogResults == UnsavedChangesOptions::SAVE) { - auto saveCB = [this](bool isSuccessful, AZ::Data::AssetPtr asset, ScriptCanvasEditor::SourceHandle) - { - if (isSuccessful) - { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, asset->GetId()); - AZ_Assert(memoryAsset, "At this point we must have a MemoryAsset"); - - int tabIndex = -1; - if (IsTabOpen(memoryAsset->GetFileAssetId(), tabIndex)) - { - OnTabCloseRequest(tabIndex); - } - } - else - { - QMessageBox::critical(this, QString(), QObject::tr("Failed to save.")); - } - }; - - if (fileState == Tracker::ScriptCanvasFileState::NEW) - { - SaveAssetAsImpl(fileAssetId, saveCB); - } - else - { - SaveAsset(fileAssetId, saveCB); - } + // #sc-editor-asset +// auto saveCB = [this](bool isSuccessful, AZ::Data::AssetPtr asset, ScriptCanvasEditor::SourceHandle) +// { +// if (isSuccessful) +// { +// ScriptCanvasMemoryAsset::pointer memoryAsset; +// AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, asset->GetId()); +// AZ_Assert(memoryAsset, "At this point we must have a MemoryAsset"); +// +// int tabIndex = -1; +// if (IsTabOpen(memoryAsset->GetFileAssetId(), tabIndex)) +// { +// OnTabCloseRequest(tabIndex); +// } +// } +// else +// { +// QMessageBox::critical(this, QString(), QObject::tr("Failed to save.")); +// } +// }; +// +// if (fileState == Tracker::ScriptCanvasFileState::NEW) +// { +// SaveAssetAsImpl(fileAssetId, saveCB); +// } +// else +// { +// SaveAsset(fileAssetId, saveCB); +// } } else if (saveDialogResults == UnsavedChangesOptions::CONTINUE_WITHOUT_SAVING) { @@ -2886,7 +2936,7 @@ namespace ScriptCanvasEditor void MainWindow::CloseAllTabs() { m_isClosingTabs = true; - m_skipTabOnClose.SetInvalid(); + m_skipTabOnClose.Clear(); CloseNextTab(); } @@ -2904,8 +2954,10 @@ namespace ScriptCanvasEditor } } - void MainWindow::CopyPathToClipboard(int index) + void MainWindow::CopyPathToClipboard(int /*index*/) { + // #sc-editor-asset + /* QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) @@ -2926,6 +2978,7 @@ namespace ScriptCanvasEditor clipBoard->setText(m_tabBar->tabText(index)); } } + */ } void MainWindow::OnActiveFileStateChanged() @@ -2942,7 +2995,7 @@ namespace ScriptCanvasEditor || (m_tabBar->count() == 1 && m_skipTabOnClose.IsValid())) { m_isClosingTabs = false; - m_skipTabOnClose.SetInvalid(); + m_skipTabOnClose.Clear(); return; } @@ -2968,8 +3021,9 @@ namespace ScriptCanvasEditor } } - void MainWindow::OnTabCloseRequest(int index) + void MainWindow::OnTabCloseRequest(int /*index*/) { + /* QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) { @@ -3003,6 +3057,7 @@ namespace ScriptCanvasEditor // information AddSystemTickAction(SystemTickActionFlag::CloseNextTabAction); } + */ } void MainWindow::OnNodeAdded(const AZ::EntityId& nodeId, bool isPaste) @@ -3576,7 +3631,7 @@ namespace ScriptCanvasEditor if (m_queuedFocusOverride.IsValid()) { SetActiveAsset(m_queuedFocusOverride); - m_queuedFocusOverride.SetInvalid(); + m_queuedFocusOverride.Clear(); } else if (lastFocusAsset.IsValid()) { @@ -3639,22 +3694,23 @@ namespace ScriptCanvasEditor void MainWindow::UpdateSaveState() { - bool enabled = m_activeGraph.IsValid(); - bool isSaving = false; - bool hasModifications = false; - - if (enabled) - { - Tracker::ScriptCanvasFileState fileState = GetAssetFileState(m_activeGraph); - hasModifications = ( fileState == Tracker::ScriptCanvasFileState::MODIFIED - || fileState == Tracker::ScriptCanvasFileState::NEW - || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED); - - AssetTrackerRequestBus::BroadcastResult(isSaving, &AssetTrackerRequests::IsSaving, m_activeGraph); - } - - ui->action_Save->setEnabled(enabled && !isSaving && hasModifications); - ui->action_Save_As->setEnabled(enabled && !isSaving); + // #sc-editor-asset todo, consider making blocking +// bool enabled = m_activeGraph.IsValid(); +// bool isSaving = false; +// bool hasModifications = false; +// +// if (enabled) +// { +// Tracker::ScriptCanvasFileState fileState = GetAssetFileState(m_activeGraph); +// hasModifications = ( fileState == Tracker::ScriptCanvasFileState::MODIFIED +// || fileState == Tracker::ScriptCanvasFileState::NEW +// || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED); +// +// AssetTrackerRequestBus::BroadcastResult(isSaving, &AssetTrackerRequests::IsSaving, m_activeGraph); +// } +// +// ui->action_Save->setEnabled(enabled && !isSaving && hasModifications); +// ui->action_Save_As->setEnabled(enabled && !isSaving); } void MainWindow::CreateFunctionInput() @@ -3852,18 +3908,22 @@ namespace ScriptCanvasEditor return findChild(elementName); } - AZ::EntityId MainWindow::FindEditorNodeIdByAssetNodeId(const ScriptCanvasEditor::SourceHandle& assetId, AZ::EntityId assetNodeId) const + AZ::EntityId MainWindow::FindEditorNodeIdByAssetNodeId(const ScriptCanvasEditor::SourceHandle& /*assetId*/, AZ::EntityId /*assetNodeId*/) const { - AZ::EntityId editorEntityId; - AssetTrackerRequestBus::BroadcastResult(editorEntityId, &AssetTrackerRequests::GetEditorEntityIdFromSceneEntityId, assetId, assetNodeId); - return editorEntityId; + // #sc-editor-asset + return AZ::EntityId{}; + // AZ::EntityId editorEntityId; + // AssetTrackerRequestBus::BroadcastResult(editorEntityId, &AssetTrackerRequests::GetEditorEntityIdFromSceneEntityId, assetId, assetNodeId); + //return AZ::EntityId{};// editorEntityId; } - AZ::EntityId MainWindow::FindAssetNodeIdByEditorNodeId(const ScriptCanvasEditor::SourceHandle& assetId, AZ::EntityId editorNodeId) const + AZ::EntityId MainWindow::FindAssetNodeIdByEditorNodeId(const ScriptCanvasEditor::SourceHandle& /*assetId*/, AZ::EntityId /*editorNodeId*/) const { - AZ::EntityId sceneEntityId; - AssetTrackerRequestBus::BroadcastResult(sceneEntityId, &AssetTrackerRequests::GetSceneEntityIdFromEditorEntityId, assetId, editorNodeId); - return sceneEntityId; + // #sc-editor-asset + return AZ::EntityId{}; + // AZ::EntityId sceneEntityId; + // AssetTrackerRequestBus::BroadcastResult(sceneEntityId, &AssetTrackerRequests::GetSceneEntityIdFromEditorEntityId, assetId, editorNodeId); + // return sceneEntityId; } GraphCanvas::Endpoint MainWindow::CreateNodeForProposalWithGroup(const AZ::EntityId& connectionId, const GraphCanvas::Endpoint& endpoint, const QPointF& scenePoint, const QPoint& screenPoint, AZ::EntityId groupTarget) @@ -4283,8 +4343,9 @@ namespace ScriptCanvasEditor PrepareAssetForSave(m_activeGraph); } - void MainWindow::PrepareAssetForSave(const ScriptCanvasEditor::SourceHandle& assetId) + void MainWindow::PrepareAssetForSave(const ScriptCanvasEditor::SourceHandle& /*assetId*/) { + /* ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); @@ -4309,6 +4370,7 @@ namespace ScriptCanvasEditor graph->MarkVersion(); } } + */ } void MainWindow::RestartAutoTimerSave(bool forceTimer) @@ -4351,64 +4413,65 @@ namespace ScriptCanvasEditor void MainWindow::OnAssignToSelectedEntities() { - Tracker::ScriptCanvasFileState fileState; - AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, m_activeGraph); - - bool isDocumentOpen = false; - AzToolsFramework::EditorRequests::Bus::BroadcastResult(isDocumentOpen, &AzToolsFramework::EditorRequests::IsLevelDocumentOpen); - - if (fileState == Tracker::ScriptCanvasFileState::NEW || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED || !isDocumentOpen) - { - return; - } - - AzToolsFramework::EntityIdList selectedEntityIds; - AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(selectedEntityIds, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities); - - auto selectedEntityIdIter = selectedEntityIds.begin(); - - bool isLayerAmbiguous = false; - AZ::EntityId targetLayer; - - while (selectedEntityIdIter != selectedEntityIds.end()) - { - bool isLayerEntity = false; - AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(isLayerEntity, (*selectedEntityIdIter), &AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer); - - if (isLayerEntity) - { - if (targetLayer.IsValid()) - { - isLayerAmbiguous = true; - } - - targetLayer = (*selectedEntityIdIter); - - selectedEntityIdIter = selectedEntityIds.erase(selectedEntityIdIter); - } - else - { - ++selectedEntityIdIter; - } - } - - if (selectedEntityIds.empty()) - { - AZ::EntityId createdId; - AzToolsFramework::EditorRequests::Bus::BroadcastResult(createdId, &AzToolsFramework::EditorRequests::CreateNewEntity, AZ::EntityId()); - - selectedEntityIds.emplace_back(createdId); - - if (targetLayer.IsValid() && !isLayerAmbiguous) - { - AZ::TransformBus::Event(createdId, &AZ::TransformBus::Events::SetParent, targetLayer); - } - } - - for (const AZ::EntityId& entityId : selectedEntityIds) - { - AssignGraphToEntityImpl(entityId); - } + // #sc-editor-asset consider cutting +// Tracker::ScriptCanvasFileState fileState; +// AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, m_activeGraph); +// +// bool isDocumentOpen = false; +// AzToolsFramework::EditorRequests::Bus::BroadcastResult(isDocumentOpen, &AzToolsFramework::EditorRequests::IsLevelDocumentOpen); +// +// if (fileState == Tracker::ScriptCanvasFileState::NEW || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED || !isDocumentOpen) +// { +// return; +// } +// +// AzToolsFramework::EntityIdList selectedEntityIds; +// AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(selectedEntityIds, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities); +// +// auto selectedEntityIdIter = selectedEntityIds.begin(); +// +// bool isLayerAmbiguous = false; +// AZ::EntityId targetLayer; +// +// while (selectedEntityIdIter != selectedEntityIds.end()) +// { +// bool isLayerEntity = false; +// AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(isLayerEntity, (*selectedEntityIdIter), &AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer); +// +// if (isLayerEntity) +// { +// if (targetLayer.IsValid()) +// { +// isLayerAmbiguous = true; +// } +// +// targetLayer = (*selectedEntityIdIter); +// +// selectedEntityIdIter = selectedEntityIds.erase(selectedEntityIdIter); +// } +// else +// { +// ++selectedEntityIdIter; +// } +// } +// +// if (selectedEntityIds.empty()) +// { +// AZ::EntityId createdId; +// AzToolsFramework::EditorRequests::Bus::BroadcastResult(createdId, &AzToolsFramework::EditorRequests::CreateNewEntity, AZ::EntityId()); +// +// selectedEntityIds.emplace_back(createdId); +// +// if (targetLayer.IsValid() && !isLayerAmbiguous) +// { +// AZ::TransformBus::Event(createdId, &AZ::TransformBus::Events::SetParent, targetLayer); +// } +// } +// +// for (const AZ::EntityId& entityId : selectedEntityIds) +// { +// AssignGraphToEntityImpl(entityId); +// } } void MainWindow::OnAssignToEntity(const AZ::EntityId& entityId) @@ -4422,11 +4485,13 @@ namespace ScriptCanvasEditor } } - ScriptCanvasEditor::Tracker::ScriptCanvasFileState MainWindow::GetAssetFileState(ScriptCanvasEditor::SourceHandle assetId) const + ScriptCanvasEditor::Tracker::ScriptCanvasFileState MainWindow::GetAssetFileState(ScriptCanvasEditor::SourceHandle /*assetId*/) const { - Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::INVALID; - AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, assetId); - return fileState; + // #sc-editor-asset + return Tracker::ScriptCanvasFileState::INVALID; + // Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::INVALID; + // AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, assetId); + // return fileState; } void MainWindow::AssignGraphToEntityImpl(const AZ::EntityId& entityId) @@ -4475,7 +4540,8 @@ namespace ScriptCanvasEditor if (usableRequestBus) { ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeGraph); + // #sc-editor-asset + // AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeGraph); if (memoryAsset) { diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h index 694964e482..241ac0dc60 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h @@ -155,7 +155,7 @@ namespace ScriptCanvasEditor } }; - //! Manages the Save/Restore operations of the user's las topened and focused graphs + //! Manages the Save/Restore operations of the user's last opened and focused graphs class Workspace : AssetTrackerNotificationBus::MultiHandler { @@ -417,17 +417,17 @@ namespace ScriptCanvasEditor void CloseNextTab(); - bool IsTabOpen(const ScriptCanvasEditor::SourceHandle& assetId, int& outTabIndex) const; - QVariant GetTabData(const ScriptCanvasEditor::SourceHandle& assetId); + bool IsTabOpen(const SourceHandle& assetId, int& outTabIndex) const; + QVariant GetTabData(const SourceHandle& assetId); //! GeneralRequestBus - AZ::Outcome OpenScriptCanvasAssetId(const ScriptCanvasEditor::SourceHandle& assetId) override; - AZ::Outcome OpenScriptCanvasAsset(ScriptCanvasEditor::SourceHandle scriptCanvasAssetId, int tabIndex = -1) override; + AZ::Outcome OpenScriptCanvasAssetId(const SourceHandle& assetId) override; + AZ::Outcome OpenScriptCanvasAsset(SourceHandle scriptCanvasAssetId, int tabIndex = -1) override; AZ::Outcome OpenScriptCanvasAsset(const ScriptCanvasMemoryAsset& scriptCanvasAsset, int tabIndex = -1); - int CloseScriptCanvasAsset(const ScriptCanvasEditor::SourceHandle& assetId) override; + int CloseScriptCanvasAsset(const SourceHandle& assetId) override; bool CreateScriptCanvasAssetFor(const TypeDefs::EntityComponentId& requestingEntityId) override; - bool IsScriptCanvasAssetOpen(const ScriptCanvasEditor::SourceHandle& assetId) const override; + bool IsScriptCanvasAssetOpen(const SourceHandle& assetId) const override; const CategoryInformation* FindNodePaletteCategoryInformation(AZStd::string_view categoryPath) const override; const NodePaletteModelInformation* FindNodePaletteModelInformation(const ScriptCanvas::NodeTypeIdentifier& nodeType) const override; @@ -627,15 +627,7 @@ namespace ScriptCanvasEditor ScriptCanvasEditor::SourceHandle GetSourceAssetId(const ScriptCanvasEditor::SourceHandle& memoryAssetId) const { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, memoryAssetId); - - if (memoryAsset) - { - return memoryAsset->GetFileAssetId(); - } - - return ScriptCanvasEditor::SourceHandle(); + return memoryAssetId; } int InsertTabForAsset(AZStd::string_view assetPath, ScriptCanvasEditor::SourceHandle assetId, int tabIndex = -1); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp index 9b2d0e4982..e598700899 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "Core.h" #include "Attributes.h" @@ -182,5 +183,55 @@ namespace ScriptCanvas serializeContext->RegisterType(typeId, AZStd::move(classData), EventPlaceholderAnyCreator); } - +} + +namespace ScriptCanvasEditor +{ + SourceHandle::SourceHandle(ScriptCanvas::DataPtr graph, const AZ::Uuid& id, AZStd::string_view path) + : m_data(graph) + , m_id(id) + , m_path(path) + {} + + void SourceHandle::Clear() + { + m_data = nullptr; + m_id = AZ::Uuid::CreateNull(); + m_path.clear(); + } + + GraphPtrConst SourceHandle::Get() const + { + return m_data ? m_data->GetEditorGraph() : nullptr; + } + + const AZ::Uuid& SourceHandle::Id() const + { + return m_id; + } + + bool SourceHandle::IsValid() const + { + return *this; + } + + GraphPtr SourceHandle::Mod() const + { + return m_data ? m_data->ModEditorGraph() : nullptr; + } + + SourceHandle::operator bool() const + { + return m_data != nullptr; + } + + bool SourceHandle::operator!() const + { + return m_data == nullptr; + } + + const AZStd::string& SourceHandle::Path() const + { + return m_path; + } } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h index 85f76280d2..e2b2ef5919 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h @@ -20,7 +20,7 @@ #include #include #include - +#include #include #include @@ -318,7 +318,39 @@ namespace ScriptCanvasEditor using GraphPtr = Graph*; using GraphPtrConst = const Graph*; - class SourceHandle; + class SourceHandle + { + public: + AZ_TYPE_INFO(SourceHandle, "{65855A98-AE2F-427F-BFC8-69D45265E312}"); + AZ_CLASS_ALLOCATOR(SourceHandle, AZ::SystemAllocator, 0); + + SourceHandle() = default; + + SourceHandle(ScriptCanvas::DataPtr graph, const AZ::Uuid& id, AZStd::string_view path); + + void Clear(); + + GraphPtrConst Get() const; + + const AZ::Uuid& Id() const; + + bool IsValid() const; + + GraphPtr Mod() const; + + operator bool() const; + + bool operator!() const; + + const AZStd::string& Path() const; + + AZStd::string ToString() const; + + private: + ScriptCanvas::DataPtr m_data; + AZ::Uuid m_id = AZ::Uuid::CreateNull(); + AZStd::string m_path; + }; } namespace AZStd From ad6dc8a3bddf3b83b2207873fadf68e083e726cd Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Fri, 29 Oct 2021 16:23:20 -0700 Subject: [PATCH 003/128] initial compile of detailed path of change to regular sc files Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Asset/EditorAssetSystemComponent.cpp | 33 ++-- .../Editor/Assets/ScriptCanvasAssetHolder.cpp | 49 +++--- .../Code/Editor/Components/EditorGraph.cpp | 3 +- .../EditorScriptCanvasComponent.cpp | 11 +- .../FunctionNodeDescriptorComponent.cpp | 2 +- .../Assets/ScriptCanvasBaseAssetData.cpp | 23 --- .../Assets/ScriptCanvasBaseAssetData.h | 28 +--- .../Include/ScriptCanvas/Bus/RequestBus.h | 14 +- .../Components/EditorScriptCanvasComponent.h | 3 +- Gems/ScriptCanvas/Code/Editor/Settings.cpp | 40 ++--- Gems/ScriptCanvas/Code/Editor/Settings.h | 1 + .../Code/Editor/SystemComponent.cpp | 94 +++++------ .../Code/Editor/Utilities/RecentAssetPath.cpp | 9 +- .../Code/Editor/Utilities/RecentAssetPath.h | 1 + .../Code/Editor/View/Widgets/CanvasWidget.cpp | 6 - .../Code/Editor/View/Widgets/GraphTabBar.cpp | 147 +++++++++--------- .../LoggingPanel/LoggingWindowSession.cpp | 18 +-- .../LoggingPanel/LoggingWindowTreeItems.cpp | 98 ++++++------ .../PivotTree/PivotTreeWidget.cpp | 24 +-- .../FunctionNodePaletteTreeItemTypes.cpp | 8 +- .../ScriptCanvasStatisticsDialog.cpp | 3 +- .../UnitTestPanel/UnitTestDockWidget.cpp | 2 +- .../Code/Editor/View/Windows/MainWindow.cpp | 68 ++++---- .../Tools/UpgradeTool/UpgradeHelper.cpp | 3 +- .../Code/Include/ScriptCanvas/Core/Core.cpp | 35 +++++ .../Code/Include/ScriptCanvas/Core/Core.h | 31 ++++ 26 files changed, 388 insertions(+), 366 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp b/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp index 4df2a57c36..1c383d04bd 100644 --- a/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp +++ b/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp @@ -122,7 +122,7 @@ namespace ScriptCanvasEditor return ScriptCanvasBuilder::CreateLuaAsset(editAsset->GetScriptCanvasEntity(), editAsset->GetId(), graphPathForRawLuaFile); } - void EditorAssetSystemComponent::AddSourceFileOpeners([[maybe_unused]] const char* fullSourceFileName, const AZ::Uuid& sourceUuid, AzToolsFramework::AssetBrowser::SourceFileOpenerList& openers) + void EditorAssetSystemComponent::AddSourceFileOpeners([[maybe_unused]] const char* fullSourceFileName, [[maybe_unused]] const AZ::Uuid& sourceUuid, [[maybe_unused]] AzToolsFramework::AssetBrowser::SourceFileOpenerList& openers) { using namespace AzToolsFramework; using namespace AzToolsFramework::AssetBrowser; @@ -139,21 +139,22 @@ namespace ScriptCanvasEditor return; } // You can push back any number of "Openers" - choose a unique identifier, and icon, and then a lambda which will be activated if the user chooses to open it with your opener: - openers.push_back({ "ScriptCanvas_Editor_Asset_Edit", "Script Canvas Editor...", QIcon(), - [](const char*, const AZ::Uuid& scSourceUuid) - { - AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); - AZ::Data::AssetId sourceAssetId(scSourceUuid, 0); - - auto& assetManager = AZ::Data::AssetManager::Instance(); - AZ::Data::Asset scriptCanvasAsset = assetManager.GetAsset(sourceAssetId, azrtti_typeid(), AZ::Data::AssetLoadBehavior::Default); - AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); - GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, scriptCanvasAsset.GetId(), -1); - if (!openOutcome) - { - AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data()); - } - } }); + // #sc_editor_asset + // openers.push_back({ "ScriptCanvas_Editor_Asset_Edit", "Script Canvas Editor...", QIcon(), +// [](const char*, const AZ::Uuid& scSourceUuid) +// { +// AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); +// AZ::Data::AssetId sourceAssetId(scSourceUuid, 0); +// +// auto& assetManager = AZ::Data::AssetManager::Instance(); +// AZ::Data::Asset scriptCanvasAsset = assetManager.GetAsset(sourceAssetId, azrtti_typeid(), AZ::Data::AssetLoadBehavior::Default); +// AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); +// GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, scriptCanvasAsset.GetId(), -1); +// if (!openOutcome) +// { +// AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data()); +// } +// } }); } } diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHolder.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHolder.cpp index a42a9bad48..c5c08d5bbe 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHolder.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHolder.cpp @@ -82,30 +82,31 @@ namespace ScriptCanvasEditor void ScriptCanvasAssetHolder::OpenEditor() const { - AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); - - AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); - - if (m_scriptCanvasAsset.IsReady()) - { - GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, m_scriptCanvasAsset.GetId(), -1); - - if (!openOutcome) - { - AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data()); - } - } - else if (m_ownerId.first.IsValid()) - { - AzToolsFramework::EntityIdList selectedEntityIds; - AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(selectedEntityIds, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities); - - // Going to bypass the multiple selected entities flow for right now. - if (selectedEntityIds.size() == 1) - { - GeneralRequestBus::Broadcast(&GeneralRequests::CreateScriptCanvasAssetFor, m_ownerId); - } - } + // #sc_editor_asset +// AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); +// +// AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); +// +// if (m_scriptCanvasAsset.IsReady()) +// { +// GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, m_scriptCanvasAsset.GetId(), -1); +// +// if (!openOutcome) +// { +// AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data()); +// } +// } +// else if (m_ownerId.first.IsValid()) +// { +// AzToolsFramework::EntityIdList selectedEntityIds; +// AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(selectedEntityIds, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities); +// +// // Going to bypass the multiple selected entities flow for right now. +// if (selectedEntityIds.size() == 1) +// { +// GeneralRequestBus::Broadcast(&GeneralRequests::CreateScriptCanvasAssetFor, m_ownerId); +// } +// } } ScriptCanvas::ScriptCanvasId ScriptCanvasAssetHolder::GetScriptCanvasId() const diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp index afb80cc46a..4a03a60db8 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp @@ -1340,7 +1340,8 @@ namespace ScriptCanvasEditor void Graph::SignalDirty() { - GeneralRequestBus::Broadcast(&GeneralRequests::SignalSceneDirty, GetAssetId()); + // #sc_editor_asset + // GeneralRequestBus::Broadcast(&GeneralRequests::SignalSceneDirty, GetAssetId()); } void Graph::HighlightNodesByType(const ScriptCanvas::NodeTypeIdentifier& nodeTypeIdentifier) diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp index 043e034062..d73273103c 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp @@ -247,21 +247,12 @@ namespace ScriptCanvasEditor m_scriptCanvasAssetHolder.OpenEditor(); } - void EditorScriptCanvasComponent::CloseGraph() - { - AZ::Data::AssetId assetId = m_scriptCanvasAssetHolder.GetAssetId(); - if (assetId.IsValid()) - { - GeneralRequestBus::Broadcast(&GeneralRequests::CloseScriptCanvasAsset, assetId); - } - } - void EditorScriptCanvasComponent::Init() { EditorComponentBase::Init(); AzFramework::AssetCatalogEventBus::Handler::BusConnect(); AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusConnect(); - m_scriptCanvasAssetHolder.Init(GetEntityId(), GetId()); + // m_scriptCanvasAssetHolder.Init(GetEntityId(), GetId()); } //========================================================================= diff --git a/Gems/ScriptCanvas/Code/Editor/GraphCanvas/Components/NodeDescriptors/FunctionNodeDescriptorComponent.cpp b/Gems/ScriptCanvas/Code/Editor/GraphCanvas/Components/NodeDescriptors/FunctionNodeDescriptorComponent.cpp index db41fa70ca..f649bb9f7d 100644 --- a/Gems/ScriptCanvas/Code/Editor/GraphCanvas/Components/NodeDescriptors/FunctionNodeDescriptorComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/GraphCanvas/Components/NodeDescriptors/FunctionNodeDescriptorComponent.cpp @@ -97,7 +97,7 @@ namespace ScriptCanvasEditor } AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); - GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, assetInfo.m_assetId, -1); + GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, SourceHandle( nullptr, assetInfo.m_assetId.m_guid, {} ), -1); return openOutcome.IsSuccess(); } diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.cpp b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.cpp index 2b451b0de8..efb20e3518 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.cpp @@ -7,27 +7,4 @@ */ #include -#include -namespace ScriptCanvas -{ - const Graph* ScriptCanvasData::GetGraph() const - { - return AZ::EntityUtils::FindFirstDerivedComponent(m_scriptCanvasEntity.get()); - } - - const ScriptCanvasEditor::Graph* ScriptCanvasData::GetEditorGraph() const - { - return AZ::EntityUtils::FindFirstDerivedComponent(m_scriptCanvasEntity.get()); - } - - Graph* ScriptCanvasData::ModGraph() - { - return AZ::EntityUtils::FindFirstDerivedComponent(m_scriptCanvasEntity.get()); - } - - ScriptCanvasEditor::Graph* ScriptCanvasData::ModEditorGraph() - { - return AZ::EntityUtils::FindFirstDerivedComponent(m_scriptCanvasEntity.get()); - } -} diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.h index 5340f1128a..7597da9081 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasBaseAssetData.h @@ -13,31 +13,5 @@ namespace ScriptCanvas { - class ScriptCanvasData - { - public: - - AZ_RTTI(ScriptCanvasData, "{1072E894-0C67-4091-8B64-F7DB324AD13C}"); - AZ_CLASS_ALLOCATOR(ScriptCanvasData, AZ::SystemAllocator, 0); - ScriptCanvasData() {} - virtual ~ScriptCanvasData() {} - ScriptCanvasData(ScriptCanvasData&& other); - ScriptCanvasData& operator=(ScriptCanvasData&& other); - - static void Reflect(AZ::ReflectContext* reflectContext); - - AZ::Entity* GetScriptCanvasEntity() const { return m_scriptCanvasEntity.get(); } - - const Graph* GetGraph() const; - - const ScriptCanvasEditor::Graph* GetEditorGraph() const; - - Graph* ModGraph(); - - ScriptCanvasEditor::Graph* ModEditorGraph(); - - AZStd::unique_ptr m_scriptCanvasEntity; - private: - ScriptCanvasData(const ScriptCanvasData&) = delete; - }; + } diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h index 2d9a7d6b58..8dbaf5b31a 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h @@ -8,18 +8,16 @@ #pragma once -#include -#include -#include #include -#include +#include +#include +#include #include - +#include #include - -#include #include - +#include +#include #include class QLineEdit; diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h index 5dbe718eca..87ffff8b19 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h @@ -67,8 +67,7 @@ namespace ScriptCanvasEditor //===================================================================== void OpenEditor(); - void CloseGraph(); - + void SetName(const AZStd::string& name) { m_name = name; } const AZStd::string& GetName() const; AZ::EntityId GetEditorEntityId() const { return GetEntity() ? GetEntityId() : AZ::EntityId(); } diff --git a/Gems/ScriptCanvas/Code/Editor/Settings.cpp b/Gems/ScriptCanvas/Code/Editor/Settings.cpp index fd745fa257..d072e465b8 100644 --- a/Gems/ScriptCanvas/Code/Editor/Settings.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Settings.cpp @@ -92,13 +92,11 @@ namespace ScriptCanvasEditor // WorkspaceAssetSaveData EditorWorkspace::WorkspaceAssetSaveData::WorkspaceAssetSaveData() - : m_assetType(azrtti_typeid()) { } - EditorWorkspace::WorkspaceAssetSaveData::WorkspaceAssetSaveData(const AZ::Data::AssetId& assetId) + EditorWorkspace::WorkspaceAssetSaveData::WorkspaceAssetSaveData(SourceHandle assetId) : m_assetId(assetId) - , m_assetType(azrtti_typeid()) { } @@ -108,24 +106,31 @@ namespace ScriptCanvasEditor { AZStd::vector assetSaveData; AZStd::vector assetIds; - auto subElement = rootDataElementNode.FindSubElement(AZ_CRC("ActiveAssetIds", 0xe445268a)); + auto subElement = rootDataElementNode.FindSubElement(AZ_CRC_CE("ActiveAssetIds")); if (subElement) { - if (subElement->GetData(assetIds)) - { - assetSaveData.reserve(assetIds.size()); - for (const AZ::Data::AssetId& assetId : assetIds) - { - assetSaveData.emplace_back(assetId); - } - } +// #sc_editor_asset +// if (subElement->GetData(assetIds)) +// { +// assetSaveData.reserve(assetIds.size()); +// for (const AZ::Data::AssetId& assetId : assetIds) +// { +// assetSaveData.emplace_back(assetId); +// } +// } } - rootDataElementNode.RemoveElementByName(AZ_CRC("ActiveAssetIds", 0xe445268a)); + rootDataElementNode.RemoveElementByName(AZ_CRC_CE("ActiveAssetIds")); rootDataElementNode.AddElementWithData(context, "ActiveAssetData", assetSaveData); } + if (rootDataElementNode.GetVersion() < 4) + { + rootDataElementNode.RemoveElementByName(AZ_CRC_CE("ActiveAssetIds")); + rootDataElementNode.RemoveElementByName(AZ_CRC_CE("FocusedAssetId")); + } + return true; } @@ -135,13 +140,12 @@ namespace ScriptCanvasEditor if (serialize) { serialize->Class() - ->Version(1) + ->Version(2) ->Field("AssetId", &WorkspaceAssetSaveData::m_assetId) - ->Field("AssetType", &WorkspaceAssetSaveData::m_assetType) ; serialize->Class() - ->Version(3, &EditorWorkspace::VersionConverter) + ->Version(4, &EditorWorkspace::VersionConverter) ->Field("m_storedWindowState", &EditorWorkspace::m_storedWindowState) ->Field("m_windowGeometry", &EditorWorkspace::m_windowGeometry) ->Field("FocusedAssetId", &EditorWorkspace::m_focusedAssetId) @@ -150,13 +154,13 @@ namespace ScriptCanvasEditor } } - void EditorWorkspace::ConfigureActiveAssets(AZ::Data::AssetId focussedAssetId, const AZStd::vector< WorkspaceAssetSaveData >& activeAssetData) + void EditorWorkspace::ConfigureActiveAssets(SourceHandle focussedAssetId, const AZStd::vector< WorkspaceAssetSaveData >& activeAssetData) { m_focusedAssetId = focussedAssetId; m_activeAssetData = activeAssetData; } - AZ::Data::AssetId EditorWorkspace::GetFocusedAssetId() const + SourceHandle EditorWorkspace::GetFocusedAssetId() const { return m_focusedAssetId; } diff --git a/Gems/ScriptCanvas/Code/Editor/Settings.h b/Gems/ScriptCanvas/Code/Editor/Settings.h index 9065ac72f5..2871b3deca 100644 --- a/Gems/ScriptCanvas/Code/Editor/Settings.h +++ b/Gems/ScriptCanvas/Code/Editor/Settings.h @@ -11,6 +11,7 @@ #include #include #include +#include // qdatastream.h(173): warning C4251: 'QDataStream::d': class 'QScopedPointer>' needs to have dll-interface to be used by clients of class 'QDataStream' // qwidget.h(858): warning C4800: 'uint': forcing value to bool 'true' or 'false' (performance warning) diff --git a/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp b/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp index f901915fdb..0246071172 100644 --- a/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp @@ -209,7 +209,7 @@ namespace ScriptCanvasEditor if (!entitiesWithScriptCanvas.empty()) { QMenu* scriptCanvasMenu = nullptr; - QAction* action = nullptr; + // QAction* action = nullptr; // For entities with script canvas component, create a context menu to open any existing script canvases within each selected entity. for (const AZ::EntityId& entityId : entitiesWithScriptCanvas) @@ -242,31 +242,32 @@ namespace ScriptCanvasEditor AZStd::unordered_set< AZ::Data::AssetId > usedIds; - for (const auto& assetId : assetIds.values) - { - if (!assetId.IsValid() || usedIds.count(assetId) != 0) - { - continue; - } - - entityMenu->setEnabled(true); - - usedIds.insert(assetId); - - AZStd::string rootPath; - AZ::Data::AssetInfo assetInfo = AssetHelpers::GetAssetInfo(assetId, rootPath); - - AZStd::string displayName; - AZ::StringFunc::Path::GetFileName(assetInfo.m_relativePath.c_str(), displayName); - - action = entityMenu->addAction(QString("%1").arg(QString(displayName.c_str()))); - - QObject::connect(action, &QAction::triggered, [assetId] - { - AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); - GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAsset, assetId, -1); - }); - } + //#sc_editor_asset +// for (const auto& assetId : assetIds.values) +// { +// if (!assetId.IsValid() || usedIds.count(assetId) != 0) +// { +// continue; +// } +// +// entityMenu->setEnabled(true); +// +// usedIds.insert(assetId); +// +// AZStd::string rootPath; +// AZ::Data::AssetInfo assetInfo = AssetHelpers::GetAssetInfo(assetId, rootPath); +// +// AZStd::string displayName; +// AZ::StringFunc::Path::GetFileName(assetInfo.m_relativePath.c_str(), displayName); +// +// action = entityMenu->addAction(QString("%1").arg(QString(displayName.c_str()))); +// +// QObject::connect(action, &QAction::triggered, [assetId] +// { +// AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); +// GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAsset, assetId, -1); +// }); +// } } } } @@ -301,7 +302,10 @@ namespace ScriptCanvasEditor return AzToolsFramework::AssetBrowser::SourceFileDetails(); } - void SystemComponent::AddSourceFileOpeners(const char* fullSourceFileName, [[maybe_unused]] const AZ::Uuid& sourceUUID, AzToolsFramework::AssetBrowser::SourceFileOpenerList& openers) + void SystemComponent::AddSourceFileOpeners + ( [[maybe_unused]] const char* fullSourceFileName + , [[maybe_unused]] const AZ::Uuid& sourceUUID + , [[maybe_unused]] AzToolsFramework::AssetBrowser::SourceFileOpenerList& openers) { using namespace AzToolsFramework; using namespace AzToolsFramework::AssetBrowser; @@ -312,24 +316,24 @@ namespace ScriptCanvasEditor { isScriptCanvasAsset = true; } - - if (isScriptCanvasAsset) - { - auto scriptCanvasEditorCallback = []([[maybe_unused]] const char* fullSourceFileNameInCall, const AZ::Uuid& sourceUUIDInCall) - { - AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); - const SourceAssetBrowserEntry* fullDetails = SourceAssetBrowserEntry::GetSourceByUuid(sourceUUIDInCall); - if (fullDetails) - { - AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); - - AzToolsFramework::EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::OpenViewPane, "Script Canvas"); - GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, sourceUUIDInCall, -1); - } - }; - - openers.push_back({ "O3DE_ScriptCanvasEditor", "Open In Script Canvas Editor...", QIcon(), scriptCanvasEditorCallback }); - } + // #sc_editor_asset +// if (isScriptCanvasAsset) +// { +// auto scriptCanvasEditorCallback = []([[maybe_unused]] const char* fullSourceFileNameInCall, const AZ::Uuid& sourceUUIDInCall) +// { +// AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); +// const SourceAssetBrowserEntry* fullDetails = SourceAssetBrowserEntry::GetSourceByUuid(sourceUUIDInCall); +// if (fullDetails) +// { +// AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); +// +// AzToolsFramework::EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::OpenViewPane, "Script Canvas"); +// GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, sourceUUIDInCall, -1); +// } +// }; +// +// openers.push_back({ "O3DE_ScriptCanvasEditor", "Open In Script Canvas Editor...", QIcon(), scriptCanvasEditorCallback }); +// } } void SystemComponent::OnUserSettingsActivated() diff --git a/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.cpp b/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.cpp index f2da3868de..5d415f5fd9 100644 --- a/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.cpp @@ -26,12 +26,7 @@ namespace ScriptCanvasEditor recentOpenFileLocation = settings.value(SCRIPTCANVASEDITOR_SETTINGS_RECENT_OPEN_FILE_LOCATION_KEY).toString(); settings.endGroup(); - if (recentOpenFileLocation.isEmpty()) - { - return {}; - } - AZ::Data::AssetId assetId(recentOpenFileLocation.toUtf8().constData()); - return assetId; + return { nullptr, {}, recentOpenFileLocation.toUtf8().constData() }; } void SetRecentAssetId(SourceHandle assetId) @@ -39,7 +34,7 @@ namespace ScriptCanvasEditor QSettings settings(QSettings::IniFormat, QSettings::UserScope, SCRIPTCANVASEDITOR_AZ_QCOREAPPLICATION_SETTINGS_ORGANIZATION_NAME); - AZStd::string guidStr = assetId.m_guid.ToString(); + AZStd::string guidStr = assetId.Id().ToString(); settings.beginGroup(SCRIPTCANVASEDITOR_NAME_SHORT); settings.setValue(SCRIPTCANVASEDITOR_SETTINGS_RECENT_OPEN_FILE_LOCATION_KEY, diff --git a/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.h b/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.h index 35666d7c34..aaef02ca58 100644 --- a/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.h +++ b/Gems/ScriptCanvas/Code/Editor/Utilities/RecentAssetPath.h @@ -8,6 +8,7 @@ #pragma once #include +#include namespace ScriptCanvasEditor { diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp index e448f3ea40..359d262d6c 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp @@ -69,8 +69,6 @@ namespace ScriptCanvasEditor void CanvasWidget::ShowScene(const ScriptCanvas::ScriptCanvasId& scriptCanvasId) { EditorGraphRequests* editorGraphRequests = EditorGraphRequestBus::FindFirstHandler(scriptCanvasId); - - editorGraphRequests->SetAssetId(m_assetId); editorGraphRequests->CreateGraphCanvasScene(); AZ::EntityId graphCanvasSceneId = editorGraphRequests->GetGraphCanvasGraphId(); @@ -83,10 +81,6 @@ namespace ScriptCanvasEditor void CanvasWidget::SetAssetId(const AZ::Data::AssetId& assetId) { m_assetId = assetId; - - EditorGraphRequests* editorGraphRequests = EditorGraphRequestBus::FindFirstHandler(m_scriptCanvasId); - - editorGraphRequests->SetAssetId(m_assetId); } const GraphCanvas::ViewId& CanvasWidget::GetViewId() const diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp index f2963287c6..6db4b5bd3e 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp @@ -44,49 +44,50 @@ namespace ScriptCanvasEditor connect(this, &QTabBar::customContextMenuRequested, this, &GraphTabBar::OnContextMenu); } - void GraphTabBar::AddGraphTab(const AZ::Data::AssetId& assetId) + void GraphTabBar::AddGraphTab(ScriptCanvasEditor::SourceHandle assetId) { InsertGraphTab(count(), assetId); } - int GraphTabBar::InsertGraphTab(int tabIndex, const AZ::Data::AssetId& assetId) + int GraphTabBar::InsertGraphTab([[maybe_unused]] int tabIndex, [[maybe_unused]] ScriptCanvasEditor::SourceHandle assetId) { - if (!SelectTab(assetId)) - { - AZStd::shared_ptr memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); - - if (memoryAsset) - { - ScriptCanvas::AssetDescription assetDescription = memoryAsset->GetAsset().Get()->GetAssetDescription(); - - QIcon tabIcon = QIcon(assetDescription.GetIconPathImpl()); - int newTabIndex = qobject_cast(parent())->insertTab(tabIndex, new QWidget(), tabIcon, ""); - - CanvasWidget* canvasWidget = memoryAsset->CreateView(this); - - canvasWidget->SetDefaultBorderColor(assetDescription.GetDisplayColorImpl()); - - AZStd::string tabName; - AzFramework::StringFunc::Path::GetFileName(memoryAsset->GetAbsolutePath().c_str(), tabName); - - ConfigureTab(newTabIndex, assetId, tabName); - - // new graphs will need to use their in-memory assetid which we'll need to update - // upon saving the asset - if (!memoryAsset->GetFileAssetId().IsValid()) - { - setTabData(newTabIndex, QVariant::fromValue(memoryAsset->GetId())); - } - - return newTabIndex; - } - } + // #sc_editor_asset + // if (!SelectTab(assetId)) +// { +// AZStd::shared_ptr memoryAsset; +// AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); +// +// if (memoryAsset) +// { +// ScriptCanvas::AssetDescription assetDescription = memoryAsset->GetAsset().Get()->GetAssetDescription(); +// +// QIcon tabIcon = QIcon(assetDescription.GetIconPathImpl()); +// int newTabIndex = qobject_cast(parent())->insertTab(tabIndex, new QWidget(), tabIcon, ""); +// +// CanvasWidget* canvasWidget = memoryAsset->CreateView(this); +// +// canvasWidget->SetDefaultBorderColor(assetDescription.GetDisplayColorImpl()); +// +// AZStd::string tabName; +// AzFramework::StringFunc::Path::GetFileName(memoryAsset->GetAbsolutePath().c_str(), tabName); +// +// ConfigureTab(newTabIndex, assetId, tabName); +// +// // new graphs will need to use their in-memory assetid which we'll need to update +// // upon saving the asset +// if (!memoryAsset->GetFileAssetId().IsValid()) +// { +// setTabData(newTabIndex, QVariant::fromValue(memoryAsset->GetId())); +// } +// +// return newTabIndex; +// } +// } return -1; } - bool GraphTabBar::SelectTab(const AZ::Data::AssetId& assetId) + bool GraphTabBar::SelectTab(ScriptCanvasEditor::SourceHandle assetId) { int tabIndex = FindTab(assetId); if (-1 != tabIndex) @@ -97,7 +98,7 @@ namespace ScriptCanvasEditor return false; } - void GraphTabBar::ConfigureTab(int tabIndex, AZ::Data::AssetId fileAssetId, const AZStd::string& tabName) + void GraphTabBar::ConfigureTab(int tabIndex, ScriptCanvasEditor::SourceHandle fileAssetId, const AZStd::string& tabName) { if (fileAssetId.IsValid()) { @@ -105,29 +106,32 @@ namespace ScriptCanvasEditor if (tabDataVariant.isValid()) { - auto tabAssetId = tabDataVariant.value(); - MemoryAssetNotificationBus::MultiHandler::BusDisconnect(tabAssetId); + // #se_editor_asset + // auto tabAssetId = tabDataVariant.value(); + // MemoryAssetNotificationBus::MultiHandler::BusDisconnect(tabAssetId); } setTabData(tabIndex, QVariant::fromValue(fileAssetId)); - MemoryAssetNotificationBus::MultiHandler::BusConnect(fileAssetId); + // #se_editor_asset + // MemoryAssetNotificationBus::MultiHandler::BusConnect(fileAssetId); } + // #se_editor_asset Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::INVALID; - AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, fileAssetId); + // AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, fileAssetId); SetTabText(tabIndex, tabName.c_str(), fileState); } - int GraphTabBar::FindTab(const AZ::Data::AssetId& assetId) const + int GraphTabBar::FindTab(ScriptCanvasEditor::SourceHandle assetId) const { for (int tabIndex = 0; tabIndex < count(); ++tabIndex) { QVariant tabDataVariant = tabData(tabIndex); if (tabDataVariant.isValid()) { - auto tabAssetId = tabDataVariant.value(); + auto tabAssetId = tabDataVariant.value(); if (tabAssetId == assetId) { return tabIndex; @@ -137,16 +141,16 @@ namespace ScriptCanvasEditor return -1; } - AZ::Data::AssetId GraphTabBar::FindAssetId(int tabIndex) + ScriptCanvasEditor::SourceHandle GraphTabBar::FindAssetId(int tabIndex) { QVariant dataVariant = tabData(tabIndex); if (dataVariant.isValid()) { - auto tabAssetId = dataVariant.value(); + auto tabAssetId = dataVariant.value(); return tabAssetId; } - return AZ::Data::AssetId(); + return ScriptCanvasEditor::SourceHandle(); } void GraphTabBar::CloseTab(int index) @@ -263,19 +267,20 @@ namespace ScriptCanvasEditor AzQtComponents::TabBar::mouseReleaseEvent(event); } - void GraphTabBar::OnFileStateChanged(Tracker::ScriptCanvasFileState fileState) + void GraphTabBar::OnFileStateChanged(Tracker::ScriptCanvasFileState ) { - const AZ::Data::AssetId* fileAssetId = MemoryAssetNotificationBus::GetCurrentBusId(); + // #se_editor_asset + // const AZ::Data::AssetId* fileAssetId = MemoryAssetNotificationBus::GetCurrentBusId(); - if (fileAssetId) - { - SetFileState((*fileAssetId), fileState); - - if (FindTab((*fileAssetId)) == currentIndex()) - { - Q_EMIT OnActiveFileStateChanged(); - } - } +// if (fileAssetId) +// { +// SetFileState((*fileAssetId), fileState); +// +// if (FindTab((*fileAssetId)) == currentIndex()) +// { +// Q_EMIT OnActiveFileStateChanged(); +// } +// } } void GraphTabBar::SetTabText(int tabIndex, const QString& path, Tracker::ScriptCanvasFileState fileState) @@ -329,7 +334,8 @@ namespace ScriptCanvasEditor auto assetId = tabdata.value(); - ScriptCanvasEditor::GeneralRequestBus::Broadcast(&ScriptCanvasEditor::GeneralRequests::OnChangeActiveGraphTab, assetId); + // #sc_editor_asset + // ScriptCanvasEditor::GeneralRequestBus::Broadcast(&ScriptCanvasEditor::GeneralRequests::OnChangeActiveGraphTab, assetId); if (m_signalSaveOnChangeTo >= 0 && m_signalSaveOnChangeTo == index) { @@ -338,22 +344,23 @@ namespace ScriptCanvasEditor } } - void GraphTabBar::SetFileState(AZ::Data::AssetId assetId, Tracker::ScriptCanvasFileState fileState) + void GraphTabBar::SetFileState(ScriptCanvasEditor::SourceHandle, Tracker::ScriptCanvasFileState ) { - int index = FindTab(assetId); + // #se_editor_asset + // int index = FindTab(assetId); - if (index >= 0 && index < count()) - { - QVariant tabdata = tabData(index); - if (tabdata.isValid()) - { - auto tabAssetId = tabdata.value(); - - AZStd::string tabName; - AssetTrackerRequestBus::BroadcastResult(tabName, &AssetTrackerRequests::GetTabName, tabAssetId); - SetTabText(index, tabName.c_str(), fileState); - } - } +// if (index >= 0 && index < count()) +// { +// QVariant tabdata = tabData(index); +// if (tabdata.isValid()) +// { +// auto tabAssetId = tabdata.value(); +// +// AZStd::string tabName; +// AssetTrackerRequestBus::BroadcastResult(tabName, &AssetTrackerRequests::GetTabName, tabAssetId); +// SetTabText(index, tabName.c_str(), fileState); +// } +// } } #include diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowSession.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowSession.cpp index 5fadb0a81e..2e712cef08 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowSession.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowSession.cpp @@ -256,7 +256,7 @@ namespace ScriptCanvasEditor const AZ::Data::AssetId& assetId = executionItem->GetAssetId(); - GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId, assetId); + GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId, SourceHandle(nullptr, assetId.m_guid, {})); } } } @@ -270,12 +270,12 @@ namespace ScriptCanvasEditor const AZ::Data::AssetId& assetId = executionItem->GetAssetId(); bool isAssetOpen = false; - GeneralRequestBus::BroadcastResult(isAssetOpen, &GeneralRequests::IsScriptCanvasAssetOpen, assetId); + GeneralRequestBus::BroadcastResult(isAssetOpen, &GeneralRequests::IsScriptCanvasAssetOpen, SourceHandle(nullptr, assetId.m_guid, {})); - GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId, assetId); + GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId, SourceHandle(nullptr, assetId.m_guid, {})); AZ::EntityId graphCanvasGraphId; - GeneralRequestBus::BroadcastResult(graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, assetId); + GeneralRequestBus::BroadcastResult(graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, SourceHandle(nullptr, assetId.m_guid, {})); if (isAssetOpen) { @@ -348,7 +348,7 @@ namespace ScriptCanvasEditor GeneralRequestBus::BroadcastResult(activeGraphCanvasGraphId, &GeneralRequests::GetActiveGraphCanvasGraphId); AZ::EntityId graphCanvasGraphId; - GeneralRequestBus::BroadcastResult(graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, m_assetId); + GeneralRequestBus::BroadcastResult(graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, SourceHandle(nullptr, m_assetId.m_guid, {})); if (activeGraphCanvasGraphId == graphCanvasGraphId) { @@ -366,7 +366,7 @@ namespace ScriptCanvasEditor GraphCanvas::FocusConfig focusConfig; AZ::EntityId scriptCanvasNodeId; - AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, assetId, assetNodeId); + AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, SourceHandle(nullptr, assetId.m_guid, {}), assetNodeId); GraphCanvas::NodeId graphCanvasNodeId; SceneMemberMappingRequestBus::EventResult(graphCanvasNodeId, scriptCanvasNodeId, &SceneMemberMappingRequests::GetGraphCanvasEntityId); @@ -403,12 +403,12 @@ namespace ScriptCanvasEditor void LoggingWindowSession::HighlightElement(const AZ::Data::AssetId& assetId, const AZ::EntityId& assetNodeId) { AZ::EntityId graphCanvasGraphId; - GeneralRequestBus::BroadcastResult(graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, assetId); + GeneralRequestBus::BroadcastResult(graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, SourceHandle(nullptr, assetId.m_guid, {})); if (graphCanvasGraphId.IsValid()) { AZ::EntityId scriptCanvasNodeId; - AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, assetId, assetNodeId); + AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, SourceHandle(nullptr, assetId.m_guid, {}), assetNodeId); GraphCanvas::NodeId graphCanvasNodeId; SceneMemberMappingRequestBus::EventResult(graphCanvasNodeId, scriptCanvasNodeId, &SceneMemberMappingRequests::GetGraphCanvasEntityId); @@ -447,7 +447,7 @@ namespace ScriptCanvasEditor if (effectIter != m_highlightEffects.end()) { AZ::EntityId graphCanvasGraphId; - GeneralRequestBus::BroadcastResult(graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, assetId); + GeneralRequestBus::BroadcastResult(graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, SourceHandle(nullptr, assetId.m_guid, {})); if (graphCanvasGraphId.IsValid()) { diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp index b992d3a289..732aacc993 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp @@ -621,50 +621,51 @@ namespace ScriptCanvasEditor void ExecutionLogTreeItem::ScrapeGraphCanvasData() { - if (!m_graphCanvasGraphId.IsValid()) - { - GeneralRequestBus::BroadcastResult(m_graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, GetAssetId()); - - if (!EditorGraphNotificationBus::Handler::BusIsConnected()) - { - ScriptCanvas::ScriptCanvasId scriptCanvasId; - GeneralRequestBus::BroadcastResult(scriptCanvasId, &GeneralRequests::FindScriptCanvasIdByAssetId, GetAssetId()); - - EditorGraphNotificationBus::Handler::BusConnect(scriptCanvasId); - } - } - - if (m_graphCanvasGraphId.IsValid()) - { - if (!m_graphCanvasNodeId.IsValid()) - { - AssetGraphSceneBus::BroadcastResult(m_scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, GetAssetId(), m_scriptCanvasAssetNodeId); - SceneMemberMappingRequestBus::EventResult(m_graphCanvasNodeId, m_scriptCanvasNodeId, &SceneMemberMappingRequests::GetGraphCanvasEntityId); - } - - if (m_graphCanvasNodeId.IsValid()) - { - const bool refreshDisplayData = false; - ResolveWrapperNode(refreshDisplayData); - - AZStd::string displayName; - GraphCanvas::NodeTitleRequestBus::EventResult(displayName, m_graphCanvasNodeId, &GraphCanvas::NodeTitleRequests::GetTitle); - - if (!displayName.empty()) - { - m_displayName = displayName.c_str(); - } - - GraphCanvas::NodeTitleRequestBus::Event(m_graphCanvasNodeId, &GraphCanvas::NodeTitleRequests::ConfigureIconConfiguration, m_paletteConfiguration); - - OnStylesLoaded(); - - PopulateInputSlotData(); - PopulateOutputSlotData(); - - SignalDataChanged(); - } - } + // #sc_editor_asset +// if (!m_graphCanvasGraphId.IsValid()) +// { +// GeneralRequestBus::BroadcastResult(m_graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, GetAssetId()); +// +// if (!EditorGraphNotificationBus::Handler::BusIsConnected()) +// { +// ScriptCanvas::ScriptCanvasId scriptCanvasId; +// GeneralRequestBus::BroadcastResult(scriptCanvasId, &GeneralRequests::FindScriptCanvasIdByAssetId, GetAssetId()); +// +// EditorGraphNotificationBus::Handler::BusConnect(scriptCanvasId); +// } +// } +// +// if (m_graphCanvasGraphId.IsValid()) +// { +// if (!m_graphCanvasNodeId.IsValid()) +// { +// AssetGraphSceneBus::BroadcastResult(m_scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, GetAssetId(), m_scriptCanvasAssetNodeId); +// SceneMemberMappingRequestBus::EventResult(m_graphCanvasNodeId, m_scriptCanvasNodeId, &SceneMemberMappingRequests::GetGraphCanvasEntityId); +// } +// +// if (m_graphCanvasNodeId.IsValid()) +// { +// const bool refreshDisplayData = false; +// ResolveWrapperNode(refreshDisplayData); +// +// AZStd::string displayName; +// GraphCanvas::NodeTitleRequestBus::EventResult(displayName, m_graphCanvasNodeId, &GraphCanvas::NodeTitleRequests::GetTitle); +// +// if (!displayName.empty()) +// { +// m_displayName = displayName.c_str(); +// } +// +// GraphCanvas::NodeTitleRequestBus::Event(m_graphCanvasNodeId, &GraphCanvas::NodeTitleRequests::ConfigureIconConfiguration, m_paletteConfiguration); +// +// OnStylesLoaded(); +// +// PopulateInputSlotData(); +// PopulateOutputSlotData(); +// +// SignalDataChanged(); +// } +// } } void ExecutionLogTreeItem::PopulateInputSlotData() @@ -806,7 +807,8 @@ namespace ScriptCanvasEditor { if (!m_graphCanvasGraphId.IsValid()) { - GeneralRequestBus::BroadcastResult(m_graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, m_graphIdentifier.m_assetId); + // #sc_editor_asset + // GeneralRequestBus::BroadcastResult(m_graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, m_graphIdentifier.m_assetId); } ScrapeInputName(); @@ -828,7 +830,8 @@ namespace ScriptCanvasEditor if (m_graphCanvasGraphId.IsValid() && m_assetInputEndpoint.IsValid()) { AZ::EntityId scriptCanvasNodeId; - AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, GetAssetId(), m_assetInputEndpoint.GetNodeId()); + // #sc_editor_asset + // AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, GetAssetId(), m_assetInputEndpoint.GetNodeId()); GraphCanvas::NodeId graphCanvasNodeId; SceneMemberMappingRequestBus::EventResult(graphCanvasNodeId, scriptCanvasNodeId, &SceneMemberMappingRequests::GetGraphCanvasEntityId); @@ -851,7 +854,8 @@ namespace ScriptCanvasEditor if (m_graphCanvasGraphId.IsValid() && m_assetOutputEndpoint.IsValid()) { AZ::EntityId scriptCanvasNodeId; - AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, GetAssetId(), m_assetOutputEndpoint.GetNodeId()); + // #sc_editor_asset + // AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, GetAssetId(), m_assetOutputEndpoint.GetNodeId()); GraphCanvas::NodeId graphCanvasNodeId; SceneMemberMappingRequestBus::EventResult(graphCanvasNodeId, scriptCanvasNodeId, &SceneMemberMappingRequests::GetGraphCanvasEntityId); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/PivotTree/PivotTreeWidget.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/PivotTree/PivotTreeWidget.cpp index a34b42bed8..d085ebbbcf 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/PivotTree/PivotTreeWidget.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/PivotTree/PivotTreeWidget.cpp @@ -405,18 +405,18 @@ namespace ScriptCanvasEditor { sourceIndex = proxyModel->mapToSource(modelIndex); } - - PivotTreeItem* pivotTreeItem = static_cast(sourceIndex.internalPointer()); - - if (pivotTreeItem) - { - PivotTreeGraphItem* graphItem = azrtti_cast(pivotTreeItem); - - if (graphItem) - { - GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId, graphItem->GetAssetId()); - } - } + // #sc_editor_asset +// PivotTreeItem* pivotTreeItem = static_cast(sourceIndex.internalPointer()); +// +// if (pivotTreeItem) +// { +// PivotTreeGraphItem* graphItem = azrtti_cast(pivotTreeItem); +// +// if (graphItem) +// { +// GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId, graphItem->GetAssetId()); +// } +// } } #include diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/FunctionNodePaletteTreeItemTypes.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/FunctionNodePaletteTreeItemTypes.cpp index 50a5e8ac1a..6473dcbb40 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/FunctionNodePaletteTreeItemTypes.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/FunctionNodePaletteTreeItemTypes.cpp @@ -129,7 +129,8 @@ namespace ScriptCanvasEditor { if (row == NodePaletteTreeItem::Column::Customization) { - GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAsset, GetSourceAssetId(), -1); + // #sc_editor_asset + // GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAsset, GetSourceAssetId(), -1); } } @@ -137,8 +138,9 @@ namespace ScriptCanvasEditor { if (row != NodePaletteTreeItem::Column::Customization) { - GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAsset, GetSourceAssetId(), -1); - return true; + // #sc_editor_asset + // GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAsset, GetSourceAssetId(), -1); + // return true; } return false; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/StatisticsDialog/ScriptCanvasStatisticsDialog.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/StatisticsDialog/ScriptCanvasStatisticsDialog.cpp index ece93955bb..9538a5732a 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/StatisticsDialog/ScriptCanvasStatisticsDialog.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/StatisticsDialog/ScriptCanvasStatisticsDialog.cpp @@ -257,7 +257,8 @@ namespace ScriptCanvasEditor if (treeItem->GetAssetId().IsValid()) { - GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId, treeItem->GetAssetId()); + // #sc_editor_asset + // GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId, treeItem->GetAssetId()); } } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/UnitTestPanel/UnitTestDockWidget.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/UnitTestPanel/UnitTestDockWidget.cpp index 6142729bfe..a60c59ad7e 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/UnitTestPanel/UnitTestDockWidget.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/UnitTestPanel/UnitTestDockWidget.cpp @@ -433,7 +433,7 @@ namespace ScriptCanvasEditor AZ::Data::AssetId sourceAssetId(sourceUuid, 0); AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); - GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAssetId, sourceAssetId); + GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAssetId, ScriptCanvasEditor::SourceHandle(nullptr, sourceUuid, {})); if (!openOutcome) { AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data()); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index cb66be6ba8..32db8451cf 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -819,7 +819,7 @@ namespace ScriptCanvasEditor void MainWindow::SignalActiveSceneChanged(ScriptCanvasEditor::SourceHandle assetId) { - // #sc-editor-asset + // #se_editor_asset /* ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); @@ -938,7 +938,7 @@ namespace ScriptCanvasEditor if (shouldSaveResults == UnsavedChangesOptions::SAVE) { - // #sc-editor-asset + // #se_editor_asset // Callbacks::OnSave saveCB = [this](bool isSuccessful, AZ::Data::AssetPtr, ScriptCanvasEditor::SourceHandle) // { // if (isSuccessful) @@ -1138,7 +1138,7 @@ namespace ScriptCanvasEditor void MainWindow::MarkAssetModified(const ScriptCanvasEditor::SourceHandle& /*assetId*/) { -// #sc-editor-asset if (!assetId.IsValid()) +// #se_editor_asset if (!assetId.IsValid()) // { // return; // } @@ -1159,7 +1159,7 @@ namespace ScriptCanvasEditor void MainWindow::RefreshScriptCanvasAsset(const AZ::Data::Asset& /*asset*/) { - // #sc-editor-asset + // #se_editor_asset /* ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, asset.GetId()); @@ -1194,7 +1194,7 @@ namespace ScriptCanvasEditor AZ::Outcome MainWindow::OpenScriptCanvasAssetId(const ScriptCanvasEditor::SourceHandle& /*fileAssetId*/) { - // #sc-editor-asset + // #se_editor_asset return AZ::Failure(AZStd::string("rewrite MainWindow::OpenScriptCanvasAssetId")); /* if (!fileAssetId.IsValid()) @@ -1260,7 +1260,7 @@ namespace ScriptCanvasEditor AZ::Outcome MainWindow::OpenScriptCanvasAsset(const ScriptCanvasMemoryAsset& /*scriptCanvasAsset*/, int /*tabIndex*/ /*= -1*/) { - // #sc-editor-asset + // #se_editor_asset return AZ::Failure(AZStd::string("rewrite MainWindow::OpenScriptCanvasAsset")); /* const ScriptCanvasEditor::SourceHandle& fileAssetId = scriptCanvasAsset.GetFileAssetId(); @@ -1339,7 +1339,7 @@ namespace ScriptCanvasEditor AZ::Outcome MainWindow::OpenScriptCanvasAsset(ScriptCanvasEditor::SourceHandle /*scriptCanvasAssetId*/, int /*tabIndex*/ /*= -1*/) { - // #sc-editor-asset + // #se_editor_asset return AZ::Failure(AZStd::string("rewrite MainWindow::OpenScriptCanvasAsset")); /* ScriptCanvasMemoryAsset::pointer memoryAsset; @@ -1359,14 +1359,14 @@ namespace ScriptCanvasEditor int MainWindow::CreateAssetTab(const ScriptCanvasEditor::SourceHandle& /*assetId*/, int /*tabIndex*/) { - // #sc-editor-asset + // #se_editor_asset return -1; // return m_tabBar->InsertGraphTab(tabIndex, assetId); } AZ::Outcome MainWindow::UpdateScriptCanvasAsset(const AZ::Data::Asset& /*scriptCanvasAsset*/) { - // #sc-editor-asset + // #se_editor_asset return AZ::Failure(AZStd::string("rewrite MainWindow::UpdateScriptCanvasAsset")); /* @@ -1391,7 +1391,7 @@ namespace ScriptCanvasEditor void MainWindow::RemoveScriptCanvasAsset(const ScriptCanvasEditor::SourceHandle& /*assetId*/) { - // #sc-editor-asset move what is necessary to the widget + // #se_editor_asset move what is necessary to the widget /* AssetHelpers::PrintInfo("RemoveScriptCanvasAsset : %s", AssetHelpers::AssetIdToString(assetId).c_str()); @@ -1465,7 +1465,7 @@ namespace ScriptCanvasEditor bool MainWindow::IsScriptCanvasAssetOpen(const ScriptCanvasEditor::SourceHandle& /*assetId*/) const { - // #sc-editor-asset + // #se_editor_asset return false; } @@ -1481,7 +1481,7 @@ namespace ScriptCanvasEditor void MainWindow::GetSuggestedFullFilenameToSaveAs(const ScriptCanvasEditor::SourceHandle& /*assetId*/, AZStd::string& /*filePath*/, AZStd::string& /*fileFilter*/) { - // #sc-editor-asset + // #se_editor_asset /* ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); @@ -1893,7 +1893,7 @@ namespace ScriptCanvasEditor void MainWindow::OnSaveCallback(bool /*saveSuccess*/, AZ::Data::AssetPtr /*fileAsset*/, ScriptCanvasEditor::SourceHandle /*previousFileAssetId*/) { - // #sc-editor-asset yikes...just save the thing...move to ::SaveAsset maybe + // #se_editor_asset yikes...just save the thing...move to ::SaveAsset maybe /* ScriptCanvasMemoryAsset::pointer memoryAsset; @@ -2566,7 +2566,7 @@ namespace ScriptCanvasEditor AZ::EntityId MainWindow::GetActiveGraphCanvasGraphId() const { - // #sc-editor-asset + // #se_editor_asset // AZ::EntityId graphId; // AssetTrackerRequestBus::BroadcastResult(graphId, &AssetTrackerRequests::GetGraphId, m_activeGraph); @@ -2589,13 +2589,13 @@ namespace ScriptCanvasEditor { // ScriptCanvas::ScriptCanvasId sceneId; // AssetTrackerRequestBus::BroadcastResult(sceneId, &AssetTrackerRequests::GetScriptCanvasId, m_activeGraph); - // #sc-editor-asset + // #se_editor_asset return ScriptCanvas::ScriptCanvasId{}; } GraphCanvas::GraphId MainWindow::GetGraphCanvasGraphId(const ScriptCanvas::ScriptCanvasId& /*scriptCanvasId*/) const { - // #sc-editor-asset + // #se_editor_asset // AZ::EntityId graphCanvasId; // AssetTrackerRequestBus::BroadcastResult(graphCanvasId, &AssetTrackerRequests::GetGraphCanvasId, scriptCanvasId); // move to widget @@ -2604,7 +2604,7 @@ namespace ScriptCanvasEditor GraphCanvas::GraphId MainWindow::FindGraphCanvasGraphIdByAssetId(const ScriptCanvasEditor::SourceHandle& /*assetId*/) const { - // #sc-editor-asset + // #se_editor_asset // AZ::EntityId graphId; // AssetTrackerRequestBus::BroadcastResult(graphId, &AssetTrackerRequests::GetGraphId, assetId); return AZ::EntityId{}; @@ -2612,7 +2612,7 @@ namespace ScriptCanvasEditor ScriptCanvas::ScriptCanvasId MainWindow::FindScriptCanvasIdByAssetId(const ScriptCanvasEditor::SourceHandle& /*assetId*/) const { - // #sc-editor-asset + // #se_editor_asset // ScriptCanvas::ScriptCanvasId scriptCanvasId; // AssetTrackerRequestBus::BroadcastResult(scriptCanvasId, &AssetTrackerRequests::GetScriptCanvasId, assetId); return ScriptCanvas::ScriptCanvasId{}; @@ -2620,7 +2620,7 @@ namespace ScriptCanvasEditor ScriptCanvas::ScriptCanvasId MainWindow::GetScriptCanvasId(const GraphCanvas::GraphId& /*graphCanvasGraphId*/) const { - // #sc-editor-asset + // #se_editor_asset // ScriptCanvas::ScriptCanvasId scriptCanvasId; // AssetTrackerRequestBus::BroadcastResult(scriptCanvasId, &AssetTrackerRequests::GetScriptCanvasIdFromGraphId, graphCanvasGraphId); return ScriptCanvas::ScriptCanvasId{}; @@ -2628,7 +2628,7 @@ namespace ScriptCanvasEditor bool MainWindow::IsInUndoRedo(const AZ::EntityId& graphCanvasGraphId) const { - // #sc-editor-asset + // #se_editor_asset bool isActive = false; UndoRequestBus::EventResult(isActive, GetScriptCanvasId(graphCanvasGraphId), &UndoRequests::IsActive); return isActive; @@ -2683,7 +2683,7 @@ namespace ScriptCanvasEditor void MainWindow::ReconnectSceneBuses(ScriptCanvasEditor::SourceHandle /*previousAssetId*/, ScriptCanvasEditor::SourceHandle /*nextAssetId*/) { - // #sc-editor-asset + // #se_editor_asset /* ScriptCanvasMemoryAsset::pointer previousAsset; AssetTrackerRequestBus::BroadcastResult(previousAsset, &AssetTrackerRequests::GetAsset, previousAssetId); @@ -2721,7 +2721,7 @@ namespace ScriptCanvasEditor void MainWindow::SetActiveAsset(const ScriptCanvasEditor::SourceHandle& /*fileAssetId*/) { - // #sc-editor-asset + // #se_editor_asset /* if (m_activeGraph == fileAssetId) { @@ -2786,7 +2786,7 @@ namespace ScriptCanvasEditor void MainWindow::RefreshActiveAsset() { - // #sc-editor-asset + // #se_editor_asset /* if (m_activeGraph.IsValid()) { @@ -2836,7 +2836,7 @@ namespace ScriptCanvasEditor void MainWindow::Clear() { m_tabBar->CloseAllTabs(); - // #sc-editor-asset + // #se_editor_asset // // AssetTrackerRequests::AssetList assets; // AssetTrackerRequestBus::BroadcastResult(assets, &AssetTrackerRequests::GetAssets); @@ -2860,7 +2860,7 @@ namespace ScriptCanvasEditor Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::NEW; bool isSaving = false; - // #sc-editor-asset Get from widgets + // #se_editor_asset Get from widgets /* AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, fileAssetId); AssetTrackerRequestBus::BroadcastResult(isSaving, &AssetTrackerRequests::IsSaving, fileAssetId); @@ -2876,7 +2876,7 @@ namespace ScriptCanvasEditor { SetActiveAsset(fileAssetId); - // #sc-editor-asset + // #se_editor_asset AZStd::string tabName = "Get from widget"; // AssetTrackerRequestBus::BroadcastResult(tabName, &AssetTrackerRequests::GetTabName, fileAssetId); @@ -2885,7 +2885,7 @@ namespace ScriptCanvasEditor if (saveDialogResults == UnsavedChangesOptions::SAVE) { - // #sc-editor-asset + // #se_editor_asset // auto saveCB = [this](bool isSuccessful, AZ::Data::AssetPtr asset, ScriptCanvasEditor::SourceHandle) // { // if (isSuccessful) @@ -2956,7 +2956,7 @@ namespace ScriptCanvasEditor void MainWindow::CopyPathToClipboard(int /*index*/) { - // #sc-editor-asset + // #se_editor_asset /* QVariant tabdata = m_tabBar->tabData(index); @@ -3694,7 +3694,7 @@ namespace ScriptCanvasEditor void MainWindow::UpdateSaveState() { - // #sc-editor-asset todo, consider making blocking + // #se_editor_asset todo, consider making blocking // bool enabled = m_activeGraph.IsValid(); // bool isSaving = false; // bool hasModifications = false; @@ -3910,7 +3910,7 @@ namespace ScriptCanvasEditor AZ::EntityId MainWindow::FindEditorNodeIdByAssetNodeId(const ScriptCanvasEditor::SourceHandle& /*assetId*/, AZ::EntityId /*assetNodeId*/) const { - // #sc-editor-asset + // #se_editor_asset return AZ::EntityId{}; // AZ::EntityId editorEntityId; // AssetTrackerRequestBus::BroadcastResult(editorEntityId, &AssetTrackerRequests::GetEditorEntityIdFromSceneEntityId, assetId, assetNodeId); @@ -3919,7 +3919,7 @@ namespace ScriptCanvasEditor AZ::EntityId MainWindow::FindAssetNodeIdByEditorNodeId(const ScriptCanvasEditor::SourceHandle& /*assetId*/, AZ::EntityId /*editorNodeId*/) const { - // #sc-editor-asset + // #se_editor_asset return AZ::EntityId{}; // AZ::EntityId sceneEntityId; // AssetTrackerRequestBus::BroadcastResult(sceneEntityId, &AssetTrackerRequests::GetSceneEntityIdFromEditorEntityId, assetId, editorNodeId); @@ -4413,7 +4413,7 @@ namespace ScriptCanvasEditor void MainWindow::OnAssignToSelectedEntities() { - // #sc-editor-asset consider cutting + // #se_editor_asset consider cutting // Tracker::ScriptCanvasFileState fileState; // AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, m_activeGraph); // @@ -4487,7 +4487,7 @@ namespace ScriptCanvasEditor ScriptCanvasEditor::Tracker::ScriptCanvasFileState MainWindow::GetAssetFileState(ScriptCanvasEditor::SourceHandle /*assetId*/) const { - // #sc-editor-asset + // #se_editor_asset return Tracker::ScriptCanvasFileState::INVALID; // Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::INVALID; // AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, assetId); @@ -4540,7 +4540,7 @@ namespace ScriptCanvasEditor if (usableRequestBus) { ScriptCanvasMemoryAsset::pointer memoryAsset; - // #sc-editor-asset + // #se_editor_asset // AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeGraph); if (memoryAsset) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp index 14bc1c4dc8..e88675814b 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp @@ -99,7 +99,8 @@ namespace ScriptCanvasEditor if (assetId.IsValid()) { - GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, assetId, -1); + // #sc_editor_asset + // GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, assetId, -1); } if (!openOutcome) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp index e598700899..09c21fe43f 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp @@ -13,10 +13,13 @@ #include #include #include +// #include #include "Core.h" #include "Attributes.h" +#include + namespace ScriptCanvas { ScopedAuxiliaryEntityHandler::ScopedAuxiliaryEntityHandler(AZ::Entity* buildEntity) @@ -234,4 +237,36 @@ namespace ScriptCanvasEditor { return m_path; } + + AZStd::string SourceHandle::ToString() const + { + return AZStd::string::format + ( "%s, %s, %s" + , IsValid() ? "O" : "X" + , m_path.empty() ? m_path.c_str() : "" + , m_id.IsNull() ? "" : m_id.ToString().c_str()); + } +} + +namespace ScriptCanvas +{ + const Graph* ScriptCanvasData::GetGraph() const + { + return AZ::EntityUtils::FindFirstDerivedComponent(m_scriptCanvasEntity.get()); + } + + const ScriptCanvasEditor::Graph* ScriptCanvasData::GetEditorGraph() const + { + return reinterpret_cast(GetGraph()); + } + + Graph* ScriptCanvasData::ModGraph() + { + return AZ::EntityUtils::FindFirstDerivedComponent(m_scriptCanvasEntity.get()); + } + + ScriptCanvasEditor::Graph* ScriptCanvasData::ModEditorGraph() + { + return reinterpret_cast(ModGraph()); + } } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h index e2b2ef5919..4c1734413c 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h @@ -353,6 +353,37 @@ namespace ScriptCanvasEditor }; } +namespace ScriptCanvas +{ + class ScriptCanvasData + { + public: + + AZ_RTTI(ScriptCanvasData, "{1072E894-0C67-4091-8B64-F7DB324AD13C}"); + AZ_CLASS_ALLOCATOR(ScriptCanvasData, AZ::SystemAllocator, 0); + ScriptCanvasData() {} + virtual ~ScriptCanvasData() {} + ScriptCanvasData(ScriptCanvasData&& other); + ScriptCanvasData& operator=(ScriptCanvasData&& other); + + static void Reflect(AZ::ReflectContext* reflectContext); + + AZ::Entity* GetScriptCanvasEntity() const { return m_scriptCanvasEntity.get(); } + + const Graph* GetGraph() const; + + const ScriptCanvasEditor::Graph* GetEditorGraph() const; + + Graph* ModGraph(); + + ScriptCanvasEditor::Graph* ModEditorGraph(); + + AZStd::unique_ptr m_scriptCanvasEntity; + private: + ScriptCanvasData(const ScriptCanvasData&) = delete; + }; +} + namespace AZStd { template<> From b635e112fc7ce4b0b516d56dfd609fd75a18b066 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 3 Nov 2021 19:15:44 -0700 Subject: [PATCH 004/128] clean up open pipeline to render graph Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Assets/ScriptCanvasAssetTracker.cpp | 208 ++++---- .../ScriptCanvasAssetTrackerDefinitions.h | 2 +- .../Assets/ScriptCanvasFileHandling.cpp | 6 + .../Editor/Assets/ScriptCanvasMemoryAsset.cpp | 177 +++---- .../Include/ScriptCanvas/Bus/RequestBus.h | 2 +- .../Code/Editor/View/Widgets/CanvasWidget.cpp | 4 +- .../Code/Editor/View/Widgets/CanvasWidget.h | 7 +- .../Code/Editor/View/Widgets/GraphTabBar.cpp | 207 +++++--- .../Code/Editor/View/Widgets/GraphTabBar.h | 19 +- .../LoggingPanel/LoggingWindowTreeItems.cpp | 31 +- .../LoggingPanel/LoggingWindowTreeItems.h | 12 +- .../Code/Editor/View/Windows/MainWindow.cpp | 465 +++++++----------- .../Code/Editor/View/Windows/MainWindow.h | 7 +- .../Code/Include/ScriptCanvas/Core/Core.cpp | 15 + .../Code/Include/ScriptCanvas/Core/Core.h | 23 +- 15 files changed, 616 insertions(+), 569 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.cpp index 6d9799ee7f..f498fa2a69 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.cpp @@ -58,111 +58,111 @@ namespace ScriptCanvasEditor SaveAs(assetId, {}, onSaveCallback); } - void AssetTracker::SaveAs(AZ::Data::AssetId assetId, const AZStd::string& path, Callbacks::OnSave onSaveCallback) + void AssetTracker::SaveAs(AZ::Data::AssetId /*assetId*/, const AZStd::string& /*path*/, Callbacks::OnSave /*onSaveCallback*/) { - auto assetIter = m_assetsInUse.find(assetId); - - if (assetIter != m_assetsInUse.end()) - { - auto onSave = [this, assetId, onSaveCallback](bool saveSuccess, AZ::Data::AssetPtr asset, AZ::Data::AssetId previousFileAssetId) - { - AZ::Data::AssetId signalId = assetId; - AZ::Data::AssetId fileAssetId = asset->GetId(); - - // If there is a previous file Id is valid, it means this is a save-as operation and we need to remap the tracking. - if (previousFileAssetId.IsValid()) - { - if (saveSuccess) - { - fileAssetId = m_assetsInUse[assetId]->GetFileAssetId(); - m_remappedAsset[asset->GetId()] = fileAssetId; - - // Erase the asset first so the smart pointer can deal with it's things. - m_assetsInUse.erase(fileAssetId); - - // Then perform the insert once we know nothing will attempt to delete this while we are operating on it. - m_assetsInUse[fileAssetId] = m_assetsInUse[assetId]; - m_assetsInUse.erase(assetId); - } - - m_savingAssets.erase(assetId); - m_savingAssets.insert(fileAssetId); - - signalId = fileAssetId; - - if (m_queuedCloses.erase(assetId)) - { - m_queuedCloses.insert(fileAssetId); - } - - auto assetIter = m_assetsInUse.find(fileAssetId); - - if (assetIter != m_assetsInUse.end()) - { - AZStd::invoke(onSaveCallback, saveSuccess, m_assetsInUse[fileAssetId]->GetAsset().Get(), previousFileAssetId); - } - else - { - AZ_Error("ScriptCanvas", !saveSuccess, "Unable to find Memory Asset for Asset(%s)", fileAssetId.ToString().c_str()); - AZStd::invoke(onSaveCallback, saveSuccess, asset, previousFileAssetId); - } - } - else - { - if (saveSuccess) - { - // This should be the case when we get a save as from a newly created file. - // - // If we find the 'memory' asset id in the assets in use. This means this was a new file that was saved. - // To maintain all of the look-up stuff, we need to treat this like a remapping stage. - auto assetInUseIter = m_assetsInUse.find(assetId); - if (assetInUseIter != m_assetsInUse.end()) - { - fileAssetId = assetInUseIter->second->GetFileAssetId(); - - if (assetId != fileAssetId) - { - m_remappedAsset[assetId] = fileAssetId; - - m_assetsInUse.erase(fileAssetId); - m_assetsInUse[fileAssetId] = AZStd::move(assetInUseIter->second); - m_assetsInUse.erase(assetId); - - m_savingAssets.erase(assetId); - m_savingAssets.insert(fileAssetId); - - if (m_queuedCloses.erase(assetId)) - { - m_queuedCloses.insert(fileAssetId); - } - } - } - else - { - fileAssetId = CheckAssetId(fileAssetId); - } - - signalId = fileAssetId; - } - - if (onSaveCallback) - { - AZStd::invoke(onSaveCallback, saveSuccess, m_assetsInUse[signalId]->GetAsset().Get(), previousFileAssetId); - } - - AssetTrackerNotificationBus::Broadcast(&AssetTrackerNotifications::OnAssetSaved, m_assetsInUse[signalId], saveSuccess); - } - - SignalSaveComplete(signalId); - }; - - m_savingAssets.insert(assetId); - assetIter->second->SaveAs(path, onSave); - } - else - { - AZ_Assert(false, "Cannot SaveAs into an existing AssetId"); - } +// auto assetIter = m_assetsInUse.find(assetId); +// +// if (assetIter != m_assetsInUse.end()) +// { +// auto onSave = [this, assetId, onSaveCallback](bool saveSuccess, AZ::Data::AssetPtr asset, AZ::Data::AssetId previousFileAssetId) +// { +// AZ::Data::AssetId signalId = assetId; +// AZ::Data::AssetId fileAssetId = asset->GetId(); +// +// // If there is a previous file Id is valid, it means this is a save-as operation and we need to remap the tracking. +// if (previousFileAssetId.IsValid()) +// { +// if (saveSuccess) +// { +// fileAssetId = m_assetsInUse[assetId]->GetFileAssetId(); +// m_remappedAsset[asset->GetId()] = fileAssetId; +// +// // Erase the asset first so the smart pointer can deal with it's things. +// m_assetsInUse.erase(fileAssetId); +// +// // Then perform the insert once we know nothing will attempt to delete this while we are operating on it. +// m_assetsInUse[fileAssetId] = m_assetsInUse[assetId]; +// m_assetsInUse.erase(assetId); +// } +// +// m_savingAssets.erase(assetId); +// m_savingAssets.insert(fileAssetId); +// +// signalId = fileAssetId; +// +// if (m_queuedCloses.erase(assetId)) +// { +// m_queuedCloses.insert(fileAssetId); +// } +// +// auto assetIter = m_assetsInUse.find(fileAssetId); +// +// if (assetIter != m_assetsInUse.end()) +// { +// AZStd::invoke(onSaveCallback, saveSuccess, m_assetsInUse[fileAssetId]->GetAsset().Get(), previousFileAssetId); +// } +// else +// { +// AZ_Error("ScriptCanvas", !saveSuccess, "Unable to find Memory Asset for Asset(%s)", fileAssetId.ToString().c_str()); +// AZStd::invoke(onSaveCallback, saveSuccess, asset, previousFileAssetId); +// } +// } +// else +// { +// if (saveSuccess) +// { +// // This should be the case when we get a save as from a newly created file. +// // +// // If we find the 'memory' asset id in the assets in use. This means this was a new file that was saved. +// // To maintain all of the look-up stuff, we need to treat this like a remapping stage. +// auto assetInUseIter = m_assetsInUse.find(assetId); +// if (assetInUseIter != m_assetsInUse.end()) +// { +// fileAssetId = assetInUseIter->second->GetFileAssetId(); +// +// if (assetId != fileAssetId) +// { +// m_remappedAsset[assetId] = fileAssetId; +// +// m_assetsInUse.erase(fileAssetId); +// m_assetsInUse[fileAssetId] = AZStd::move(assetInUseIter->second); +// m_assetsInUse.erase(assetId); +// +// m_savingAssets.erase(assetId); +// m_savingAssets.insert(fileAssetId); +// +// if (m_queuedCloses.erase(assetId)) +// { +// m_queuedCloses.insert(fileAssetId); +// } +// } +// } +// else +// { +// fileAssetId = CheckAssetId(fileAssetId); +// } +// +// signalId = fileAssetId; +// } +// +// if (onSaveCallback) +// { +// AZStd::invoke(onSaveCallback, saveSuccess, m_assetsInUse[signalId]->GetAsset().Get(), previousFileAssetId); +// } +// +// AssetTrackerNotificationBus::Broadcast(&AssetTrackerNotifications::OnAssetSaved, m_assetsInUse[signalId], saveSuccess); +// } +// +// SignalSaveComplete(signalId); +// }; +// +// m_savingAssets.insert(assetId); +// assetIter->second->SaveAs(path, onSave); +// } +// else +// { +// AZ_Assert(false, "Cannot SaveAs into an existing AssetId"); +// } } bool AssetTracker::Load(AZ::Data::AssetId fileAssetId, AZ::Data::AssetType assetType, Callbacks::OnAssetReadyCallback onAssetReadyCallback) diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerDefinitions.h b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerDefinitions.h index e08ce8b74b..2aebf29b24 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerDefinitions.h +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerDefinitions.h @@ -18,7 +18,7 @@ namespace ScriptCanvasEditor namespace Callbacks { //! Callback used to know when a save operation failed or succeeded - using OnSave = AZStd::function; + using OnSave = AZStd::function; using OnAssetReadyCallback = AZStd::function; using OnAssetCreatedCallback = OnAssetReadyCallback; diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp index c21f01bb88..e8ee2ed97c 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp @@ -124,6 +124,12 @@ namespace ScriptCanvasEditor } } + if (auto entity = scriptCanvasData->GetScriptCanvasEntity()) + { + entity->Init(); + entity->Activate(); + } + return AZ::Success(ScriptCanvasEditor::SourceHandle(scriptCanvasData, {}, path)); } } diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp index 165007b79b..7af1aa3d9f 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp @@ -283,10 +283,11 @@ namespace ScriptCanvasEditor m_undoHelper = AZStd::make_unique(*this); } - ScriptCanvasEditor::Widget::CanvasWidget* ScriptCanvasMemoryAsset::CreateView(QWidget* parent) + ScriptCanvasEditor::Widget::CanvasWidget* ScriptCanvasMemoryAsset::CreateView(QWidget* /*parent*/) { - m_canvasWidget = new Widget::CanvasWidget(m_fileAssetId, parent); - return m_canvasWidget; + //m_canvasWidget = new Widget::CanvasWidget(m_fileAssetId, parent); + //return m_canvasWidget; + return nullptr; } void ScriptCanvasMemoryAsset::ClearView() @@ -430,68 +431,68 @@ namespace ScriptCanvasEditor } } - void ScriptCanvasMemoryAsset::SourceFileFailed(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid) + void ScriptCanvasMemoryAsset::SourceFileFailed(AZStd::string /*relativePath*/, AZStd::string /*scanFolder*/, AZ::Uuid) { - AZStd::string fullPath; - AzFramework::StringFunc::Path::Join(scanFolder.data(), relativePath.data(), fullPath); - AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::NormalizePath, fullPath); - - auto assetPathIdIt = AZStd::find(m_pendingSave.begin(), m_pendingSave.end(), fullPath); - - if (assetPathIdIt != m_pendingSave.end()) - { - if (m_onSaveCallback) - { - m_onSaveCallback(false, m_inMemoryAsset.Get(), AZ::Data::AssetId()); - m_onSaveCallback = nullptr; - } - - m_pendingSave.erase(assetPathIdIt); - } +// AZStd::string fullPath; +// AzFramework::StringFunc::Path::Join(scanFolder.data(), relativePath.data(), fullPath); +// AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::NormalizePath, fullPath); +// +// auto assetPathIdIt = AZStd::find(m_pendingSave.begin(), m_pendingSave.end(), fullPath); +// +// if (assetPathIdIt != m_pendingSave.end()) +// { +// if (m_onSaveCallback) +// { +// m_onSaveCallback(false, m_inMemoryAsset.Get(), AZ::Data::AssetId()); +// m_onSaveCallback = nullptr; +// } +// +// m_pendingSave.erase(assetPathIdIt); +// } } - void ScriptCanvasMemoryAsset::SavingComplete(const AZStd::string& streamName, AZ::Uuid sourceAssetId) + void ScriptCanvasMemoryAsset::SavingComplete(const AZStd::string& /*streamName*/, AZ::Uuid /*sourceAssetId*/) { - AZStd::string normPath = streamName; - AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::NormalizePath, normPath); - - auto assetPathIdIt = AZStd::find(m_pendingSave.begin(), m_pendingSave.end(), normPath); - if (assetPathIdIt != m_pendingSave.end()) - { - AZ::Data::AssetId previousFileAssetId; - - if (sourceAssetId != m_fileAssetId.m_guid) - { - previousFileAssetId = m_fileAssetId; - - // The source file has changed, store the AssetId to the canonical asset on file - SetFileAssetId(sourceAssetId); - - } - else if (!m_fileAssetId.IsValid()) - { - SetFileAssetId(sourceAssetId); - } - - m_formerGraphIdPair = AZStd::make_pair(m_scriptCanvasId, m_graphId); - - m_fileState = Tracker::ScriptCanvasFileState::UNMODIFIED; - - m_pendingSave.erase(assetPathIdIt); - - m_absolutePath = m_saveAsPath; - m_saveAsPath.clear(); - - // Connect to the source asset's bus to monitor for situations we may need to handle - AZ::Data::AssetBus::MultiHandler::BusConnect(m_inMemoryAsset.GetId()); - AZ::Data::AssetBus::MultiHandler::BusConnect(m_fileAssetId); - - if (m_onSaveCallback) - { - m_onSaveCallback(true, m_inMemoryAsset.Get(), previousFileAssetId); - m_onSaveCallback = nullptr; - } - } +// AZStd::string normPath = streamName; +// AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::NormalizePath, normPath); +// +// auto assetPathIdIt = AZStd::find(m_pendingSave.begin(), m_pendingSave.end(), normPath); +// if (assetPathIdIt != m_pendingSave.end()) +// { +// AZ::Data::AssetId previousFileAssetId; +// +// if (sourceAssetId != m_fileAssetId.m_guid) +// { +// previousFileAssetId = m_fileAssetId; +// +// // The source file has changed, store the AssetId to the canonical asset on file +// SetFileAssetId(sourceAssetId); +// +// } +// else if (!m_fileAssetId.IsValid()) +// { +// SetFileAssetId(sourceAssetId); +// } +// +// m_formerGraphIdPair = AZStd::make_pair(m_scriptCanvasId, m_graphId); +// +// m_fileState = Tracker::ScriptCanvasFileState::UNMODIFIED; +// +// m_pendingSave.erase(assetPathIdIt); +// +// m_absolutePath = m_saveAsPath; +// m_saveAsPath.clear(); +// +// // Connect to the source asset's bus to monitor for situations we may need to handle +// AZ::Data::AssetBus::MultiHandler::BusConnect(m_inMemoryAsset.GetId()); +// AZ::Data::AssetBus::MultiHandler::BusConnect(m_fileAssetId); +// +// if (m_onSaveCallback) +// { +// m_onSaveCallback(true, m_inMemoryAsset.Get(), previousFileAssetId); +// m_onSaveCallback = nullptr; +// } +// } } void ScriptCanvasMemoryAsset::FinalizeAssetSave(bool, const AzToolsFramework::SourceControlFileInfo& fileInfo, const AZ::Data::AssetStreamInfo& saveInfo, Callbacks::OnSave onSaveCallback) @@ -525,14 +526,14 @@ namespace ScriptCanvasEditor UndoNotificationBus::Broadcast(&UndoNotifications::OnCanRedoChanged, m_undoState->m_undoStack->CanRedo()); } - void ScriptCanvasMemoryAsset::SetFileAssetId(const AZ::Data::AssetId& fileAssetId) + void ScriptCanvasMemoryAsset::SetFileAssetId(const AZ::Data::AssetId& /*fileAssetId*/) { - m_fileAssetId = fileAssetId; - - if (m_canvasWidget) - { - m_canvasWidget->SetAssetId(fileAssetId); - } +// m_fileAssetId = fileAssetId; +// +// if (m_canvasWidget) +// { +// m_canvasWidget->SetAssetId(fileAssetId); +// } } void ScriptCanvasMemoryAsset::SignalFileStateChanged() @@ -604,27 +605,27 @@ namespace ScriptCanvasEditor // AssetSaveFinalizer ////////////////////////////////////// - bool AssetSaveFinalizer::ValidateStatus(const AzToolsFramework::SourceControlFileInfo& fileInfo) + bool AssetSaveFinalizer::ValidateStatus(const AzToolsFramework::SourceControlFileInfo& /*fileInfo*/) { - auto fileIO = AZ::IO::FileIOBase::GetInstance(); - if (fileInfo.IsLockedByOther()) - { - AZ_Error("Script Canvas", !fileInfo.IsLockedByOther(), "The file is already exclusively opened by another user: %s", fileInfo.m_filePath.data()); - AZStd::invoke(m_onSave, false, m_inMemoryAsset, m_fileAssetId); - return false; - } - else if (fileInfo.IsReadOnly() && fileIO->Exists(fileInfo.m_filePath.c_str())) - { - AZ_Error("Script Canvas", !fileInfo.IsReadOnly(), "File %s is read-only. It cannot be saved." - " If this file is in Perforce it may not have been checked out by the Source Control API.", fileInfo.m_filePath.data()); - AZStd::invoke(m_onSave, false, m_inMemoryAsset, m_fileAssetId); - return false; - } - else if (m_saving) - { - AZ_Warning("Script Canvas", false, "Trying to save the same file twice. Will result in one save callback being ignored."); - return false; - } +// auto fileIO = AZ::IO::FileIOBase::GetInstance(); +// if (fileInfo.IsLockedByOther()) +// { +// AZ_Error("Script Canvas", !fileInfo.IsLockedByOther(), "The file is already exclusively opened by another user: %s", fileInfo.m_filePath.data()); +// AZStd::invoke(m_onSave, false, m_inMemoryAsset, m_fileAssetId); +// return false; +// } +// else if (fileInfo.IsReadOnly() && fileIO->Exists(fileInfo.m_filePath.c_str())) +// { +// AZ_Error("Script Canvas", !fileInfo.IsReadOnly(), "File %s is read-only. It cannot be saved." +// " If this file is in Perforce it may not have been checked out by the Source Control API.", fileInfo.m_filePath.data()); +// AZStd::invoke(m_onSave, false, m_inMemoryAsset, m_fileAssetId); +// return false; +// } +// else if (m_saving) +// { +// AZ_Warning("Script Canvas", false, "Trying to save the same file twice. Will result in one save callback being ignored."); +// return false; +// } return true; } diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h index 8dbaf5b31a..90468f5d8c 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h @@ -163,7 +163,7 @@ namespace ScriptCanvasEditor public: static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; - using BusIdType = AZ::Data::AssetId; + using BusIdType = SourceHandle; virtual void OnAssetVisualized() {}; virtual void OnAssetUnloaded() {}; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp index 359d262d6c..722e9d1c71 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp @@ -36,7 +36,7 @@ namespace ScriptCanvasEditor { namespace Widget { - CanvasWidget::CanvasWidget(const AZ::Data::AssetId& assetId, QWidget* parent) + CanvasWidget::CanvasWidget(const ScriptCanvasEditor::SourceHandle& assetId, QWidget* parent) : QWidget(parent) , ui(new Ui::CanvasWidget()) , m_attached(false) @@ -78,7 +78,7 @@ namespace ScriptCanvasEditor m_scriptCanvasId = scriptCanvasId; } - void CanvasWidget::SetAssetId(const AZ::Data::AssetId& assetId) + void CanvasWidget::SetAssetId(const ScriptCanvasEditor::SourceHandle& assetId) { m_assetId = assetId; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.h index 9abb41aacc..fc04486c36 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.h @@ -21,6 +21,7 @@ AZ_POP_DISABLE_WARNING #include #include +#include #endif class QVBoxLayout; @@ -46,13 +47,13 @@ namespace ScriptCanvasEditor Q_OBJECT public: AZ_CLASS_ALLOCATOR(CanvasWidget, AZ::SystemAllocator, 0); - CanvasWidget(const AZ::Data::AssetId& assetId, QWidget* parent = nullptr); + CanvasWidget(const ScriptCanvasEditor::SourceHandle& assetId, QWidget* parent = nullptr); ~CanvasWidget() override; void SetDefaultBorderColor(AZ::Color defaultBorderColor); void ShowScene(const ScriptCanvas::ScriptCanvasId& scriptCanvasId); - void SetAssetId(const AZ::Data::AssetId& assetId); + void SetAssetId(const ScriptCanvasEditor::SourceHandle& assetId); const GraphCanvas::ViewId& GetViewId() const; @@ -69,7 +70,7 @@ namespace ScriptCanvasEditor void SetupGraphicsView(); - AZ::Data::AssetId m_assetId; + ScriptCanvasEditor::SourceHandle m_assetId; AZStd::unique_ptr ui; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp index 6db4b5bd3e..ce8c280b35 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp @@ -23,6 +23,8 @@ #include +#include + namespace ScriptCanvasEditor { namespace Widget @@ -31,7 +33,7 @@ namespace ScriptCanvasEditor // GraphTabBar //////////////// - GraphTabBar::GraphTabBar(QWidget* parent /*= nullptr*/) + GraphTabBar::GraphTabBar(QWidget* parent) : AzQtComponents::TabBar(parent) { setTabsClosable(true); @@ -49,40 +51,81 @@ namespace ScriptCanvasEditor InsertGraphTab(count(), assetId); } - int GraphTabBar::InsertGraphTab([[maybe_unused]] int tabIndex, [[maybe_unused]] ScriptCanvasEditor::SourceHandle assetId) + void GraphTabBar::ClearTabView(int tabIndex) { - // #sc_editor_asset - // if (!SelectTab(assetId)) -// { -// AZStd::shared_ptr memoryAsset; -// AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); -// -// if (memoryAsset) -// { -// ScriptCanvas::AssetDescription assetDescription = memoryAsset->GetAsset().Get()->GetAssetDescription(); -// -// QIcon tabIcon = QIcon(assetDescription.GetIconPathImpl()); -// int newTabIndex = qobject_cast(parent())->insertTab(tabIndex, new QWidget(), tabIcon, ""); -// -// CanvasWidget* canvasWidget = memoryAsset->CreateView(this); -// -// canvasWidget->SetDefaultBorderColor(assetDescription.GetDisplayColorImpl()); -// -// AZStd::string tabName; -// AzFramework::StringFunc::Path::GetFileName(memoryAsset->GetAbsolutePath().c_str(), tabName); -// -// ConfigureTab(newTabIndex, assetId, tabName); -// -// // new graphs will need to use their in-memory assetid which we'll need to update -// // upon saving the asset -// if (!memoryAsset->GetFileAssetId().IsValid()) -// { -// setTabData(newTabIndex, QVariant::fromValue(memoryAsset->GetId())); -// } -// -// return newTabIndex; -// } -// } + if (tabIndex < count()) + { + if (QVariant tabDataVariant = tabData(tabIndex); tabDataVariant.isValid()) + { + GraphTabMetadata replacement = tabDataVariant.value(); + if (replacement.m_canvasWidget) + { + delete replacement.m_canvasWidget; + replacement.m_canvasWidget = nullptr; + tabDataVariant.setValue(replacement); + setTabData(tabIndex, tabDataVariant); + } + } + } + } + + CanvasWidget* GraphTabBar::ModOrCreateTabView(int tabIndex) + { + if (tabIndex < count()) + { + if (QVariant tabDataVariant = tabData(tabIndex); tabDataVariant.isValid()) + { + if (!tabDataVariant.value().m_canvasWidget) + { + CanvasWidget* canvasWidget = new CanvasWidget(tabDataVariant.value().m_assetId, this); + canvasWidget->SetDefaultBorderColor(ScriptCanvasAssetDescription().GetDisplayColorImpl()); + GraphTabMetadata replacement = tabDataVariant.value(); + replacement.m_canvasWidget = canvasWidget; + tabDataVariant.setValue(replacement); + setTabData(tabIndex, tabDataVariant); + } + + return tabDataVariant.value().m_canvasWidget; + } + } + + return nullptr; + } + + CanvasWidget* GraphTabBar::ModTabView(int tabIndex) + { + if (tabIndex < count()) + { + if (QVariant tabDataVariant = tabData(tabIndex); tabDataVariant.isValid()) + { + return tabDataVariant.value().m_canvasWidget; + } + } + + return nullptr; + } + + int GraphTabBar::InsertGraphTab(int tabIndex, ScriptCanvasEditor::SourceHandle assetId) + { + if (!SelectTab(assetId)) + { + QIcon tabIcon = QIcon(ScriptCanvasAssetDescription().GetIconPathImpl()); + tabIndex = qobject_cast(parent())->insertTab(tabIndex, new QWidget(), tabIcon, ""); + GraphTabMetadata metaData; + CanvasWidget* canvasWidget = new CanvasWidget(assetId, this); + canvasWidget->SetDefaultBorderColor(ScriptCanvasAssetDescription().GetDisplayColorImpl()); + metaData.m_canvasWidget = canvasWidget; + + AZStd::string tabName; + AzFramework::StringFunc::Path::GetFileName(assetId.Path().c_str(), tabName); + + // #sc_editor_asset filestate + Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::INVALID; + // AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, fileAssetId); + SetTabText(tabIndex, tabName.c_str(), fileState); + setTabData(tabIndex, QVariant::fromValue(metaData)); + return tabIndex; + } return -1; } @@ -98,31 +141,10 @@ namespace ScriptCanvasEditor return false; } - void GraphTabBar::ConfigureTab(int tabIndex, ScriptCanvasEditor::SourceHandle fileAssetId, const AZStd::string& tabName) - { - if (fileAssetId.IsValid()) - { - QVariant tabDataVariant = tabData(tabIndex); - - if (tabDataVariant.isValid()) - { - // #se_editor_asset - // auto tabAssetId = tabDataVariant.value(); - // MemoryAssetNotificationBus::MultiHandler::BusDisconnect(tabAssetId); - } - - setTabData(tabIndex, QVariant::fromValue(fileAssetId)); - - // #se_editor_asset - // MemoryAssetNotificationBus::MultiHandler::BusConnect(fileAssetId); - } - - // #se_editor_asset - Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::INVALID; - // AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, fileAssetId); - - SetTabText(tabIndex, tabName.c_str(), fileState); - } +// void GraphTabBar::ConfigureTab(int /*tabIndex*/, ScriptCanvasEditor::SourceHandle fileAssetId, const AZStd::string& tabName) +// { +// +// } int GraphTabBar::FindTab(ScriptCanvasEditor::SourceHandle assetId) const { @@ -131,8 +153,8 @@ namespace ScriptCanvasEditor QVariant tabDataVariant = tabData(tabIndex); if (tabDataVariant.isValid()) { - auto tabAssetId = tabDataVariant.value(); - if (tabAssetId == assetId) + auto tabAssetId = tabDataVariant.value(); + if (tabAssetId.m_assetId == assetId) { return tabIndex; } @@ -141,18 +163,56 @@ namespace ScriptCanvasEditor return -1; } + ScriptCanvasEditor::SourceHandle GraphTabBar::FindTabByPath(AZStd::string_view path) const + { + ScriptCanvasEditor::SourceHandle candidate(nullptr, {}, path); + + for (int index = 0; index < count(); ++index) + { + QVariant tabdata = tabData(index); + if (tabdata.isValid()) + { + auto tabAssetId = tabdata.value(); + if (tabAssetId.m_assetId.AnyEquals(candidate)) + { + return tabAssetId.m_assetId; + } + } + } + + return {}; + } + ScriptCanvasEditor::SourceHandle GraphTabBar::FindAssetId(int tabIndex) { QVariant dataVariant = tabData(tabIndex); if (dataVariant.isValid()) { - auto tabAssetId = dataVariant.value(); - return tabAssetId; + auto tabAssetId = dataVariant.value(); + return tabAssetId.m_assetId; } return ScriptCanvasEditor::SourceHandle(); } + ScriptCanvas::ScriptCanvasId GraphTabBar::FindScriptCanvasIdFromGraphCanvasId(const GraphCanvas::GraphId& graphCanvasGraphId) const + { + for (int index = 0; index < count(); ++index) + { + QVariant tabdata = tabData(index); + if (tabdata.isValid()) + { + auto tabAssetId = tabdata.value(); + if (tabAssetId.m_assetId && tabAssetId.m_assetId.Get()->GetGraphCanvasGraphId() == graphCanvasGraphId) + { + return tabAssetId.m_assetId.Get()->GetScriptCanvasId(); + } + } + } + + return ScriptCanvas::ScriptCanvasId{}; + } + void GraphTabBar::CloseTab(int index) { if (index >= 0 && index < count()) @@ -160,10 +220,11 @@ namespace ScriptCanvasEditor QVariant tabdata = tabData(index); if (tabdata.isValid()) { - auto tabAssetId = tabdata.value(); + // #sc_editor_asset fix tabData + auto tabAssetId = tabdata.value(); - MemoryAssetNotificationBus::MultiHandler::BusDisconnect(tabAssetId); - AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::ClearView, tabAssetId); + //MemoryAssetNotificationBus::MultiHandler::BusDisconnect(tabAssetId); + //AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::ClearView, tabAssetId); } qobject_cast(parent())->removeTab(index); @@ -191,10 +252,10 @@ namespace ScriptCanvasEditor QVariant tabdata = tabData(tabIndex); if (tabdata.isValid()) { - auto tabAssetId = tabdata.value(); + auto tabAssetId = tabdata.value(); - Tracker::ScriptCanvasFileState fileState; - AssetTrackerRequestBus::BroadcastResult(fileState , &AssetTrackerRequests::GetFileState, tabAssetId); + Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::INVALID; + //AssetTrackerRequestBus::BroadcastResult(fileState , &AssetTrackerRequests::GetFileState, tabAssetId); isModified = fileState == Tracker::ScriptCanvasFileState::NEW || fileState == Tracker::ScriptCanvasFileState::MODIFIED; } @@ -269,7 +330,7 @@ namespace ScriptCanvasEditor void GraphTabBar::OnFileStateChanged(Tracker::ScriptCanvasFileState ) { - // #se_editor_asset + // #sc_editor_asset // const AZ::Data::AssetId* fileAssetId = MemoryAssetNotificationBus::GetCurrentBusId(); // if (fileAssetId) @@ -332,7 +393,7 @@ namespace ScriptCanvasEditor return; } - auto assetId = tabdata.value(); + auto assetId = tabdata.value(); // #sc_editor_asset // ScriptCanvasEditor::GeneralRequestBus::Broadcast(&ScriptCanvasEditor::GeneralRequests::OnChangeActiveGraphTab, assetId); @@ -346,7 +407,7 @@ namespace ScriptCanvasEditor void GraphTabBar::SetFileState(ScriptCanvasEditor::SourceHandle, Tracker::ScriptCanvasFileState ) { - // #se_editor_asset + // #sc_editor_asset // int index = FindTab(assetId); // if (index >= 0 && index < count()) @@ -354,7 +415,7 @@ namespace ScriptCanvasEditor // QVariant tabdata = tabData(index); // if (tabdata.isValid()) // { -// auto tabAssetId = tabdata.value(); +// auto tabAssetId = tabdata.value(); // // AZStd::string tabName; // AssetTrackerRequestBus::BroadcastResult(tabName, &AssetTrackerRequests::GetTabName, tabAssetId); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h index 490c17cc29..12e73b4ae5 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h @@ -16,6 +16,7 @@ #include #include +#include #include #endif @@ -26,11 +27,13 @@ namespace ScriptCanvasEditor { namespace Widget { + class CanvasWidget; + struct GraphTabMetadata { - AZ::Data::AssetId m_assetId; + SourceHandle m_assetId; QWidget* m_hostWidget = nullptr; - QString m_tabName; + CanvasWidget* m_canvasWidget = nullptr; Tracker::ScriptCanvasFileState m_fileState = Tracker::ScriptCanvasFileState::INVALID; }; @@ -46,16 +49,22 @@ namespace ScriptCanvasEditor ~GraphTabBar() override = default; void AddGraphTab(ScriptCanvasEditor::SourceHandle assetId); + void CloseTab(int index); + void CloseAllTabs(); + int InsertGraphTab(int tabIndex, ScriptCanvasEditor::SourceHandle assetId); bool SelectTab(ScriptCanvasEditor::SourceHandle assetId); - void ConfigureTab(int tabIndex, ScriptCanvasEditor::SourceHandle fileAssetId, const AZStd::string& tabName); + // void ConfigureTab(int tabIndex, ScriptCanvasEditor::SourceHandle fileAssetId, const AZStd::string& tabName); int FindTab(ScriptCanvasEditor::SourceHandle assetId) const; + ScriptCanvasEditor::SourceHandle FindTabByPath(AZStd::string_view path) const; ScriptCanvasEditor::SourceHandle FindAssetId(int tabIndex); + ScriptCanvas::ScriptCanvasId FindScriptCanvasIdFromGraphCanvasId(const GraphCanvas::GraphId& graphCanvasGraphId) const; - void CloseTab(int index); - void CloseAllTabs(); + void ClearTabView(int tabIndex); + CanvasWidget* ModOrCreateTabView(int tabIndex); + CanvasWidget* ModTabView(int tabIndex); void OnContextMenu(const QPoint& point); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp index 732aacc993..a9ffe30fb1 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp @@ -122,7 +122,11 @@ namespace ScriptCanvasEditor { } - ExecutionLogTreeItem* DebugLogRootItem::CreateExecutionItem(const LoggingDataId& loggingDataId, const ScriptCanvas::NodeTypeIdentifier& nodeType, const ScriptCanvas::GraphInfo& graphInfo, const ScriptCanvas::NamedNodeId& nodeId) + ExecutionLogTreeItem* DebugLogRootItem::CreateExecutionItem + ( [[maybe_unused]] const LoggingDataId& loggingDataId + , [[maybe_unused]] const ScriptCanvas::NodeTypeIdentifier& nodeType + , [[maybe_unused]] const ScriptCanvas::GraphInfo& graphInfo + , [[maybe_unused]] const ScriptCanvas::NamedNodeId& nodeId) { ExecutionLogTreeItem* treeItem = nullptr; @@ -136,11 +140,13 @@ namespace ScriptCanvasEditor if (m_updatePolicy == UpdatePolicy::SingleTime) { - treeItem = CreateChildNodeWithoutAddSignal(loggingDataId, nodeType, graphInfo, nodeId); + // #sc_editor_asset + // treeItem = CreateChildNodeWithoutAddSignal(loggingDataId, nodeType, graphInfo, nodeId); } else { - treeItem = CreateChildNode(loggingDataId, nodeType, graphInfo, nodeId); + // #sc_editor_asset + // treeItem = CreateChildNode(loggingDataId, nodeType, graphInfo, nodeId); } return treeItem; @@ -185,7 +191,11 @@ namespace ScriptCanvasEditor // ExecutionLogTreeItem ///////////////////////// - ExecutionLogTreeItem::ExecutionLogTreeItem(const LoggingDataId& loggingDataId, const ScriptCanvas::NodeTypeIdentifier& nodeType, const ScriptCanvas::GraphInfo& graphInfo, const ScriptCanvas::NamedNodeId& nodeId) + ExecutionLogTreeItem::ExecutionLogTreeItem + ( const LoggingDataId& loggingDataId + , const ScriptCanvas::NodeTypeIdentifier& nodeType + , const SourceHandle& graphInfo + , const ScriptCanvas::NamedNodeId& nodeId) : m_loggingDataId(loggingDataId) , m_nodeType(nodeType) , m_graphInfo(graphInfo) @@ -196,7 +206,9 @@ namespace ScriptCanvasEditor m_paletteConfiguration.SetColorPalette("MethodNodeTitlePalette"); AZ::NamedEntityId entityName; - LoggingDataRequestBus::EventResult(entityName, m_loggingDataId, &LoggingDataRequests::FindNamedEntityId, m_graphInfo.m_runtimeEntity); + + // #sc_editor_asset restore this + //LoggingDataRequestBus::EventResult(entityName, m_loggingDataId, &LoggingDataRequests::FindNamedEntityId, m_graphInfo.m_runtimeEntity); m_sourceEntityName = entityName.ToString().c_str(); m_displayName = nodeId.m_name.c_str(); @@ -207,7 +219,7 @@ namespace ScriptCanvasEditor m_inputName = "---"; m_outputName = "---"; - GeneralAssetNotificationBus::Handler::BusConnect(GetAssetId()); + GeneralAssetNotificationBus::Handler::BusConnect(graphInfo); } QVariant ExecutionLogTreeItem::Data(const QModelIndex& index, int role) const @@ -502,12 +514,13 @@ namespace ScriptCanvasEditor const ScriptCanvas::GraphIdentifier& ExecutionLogTreeItem::GetGraphIdentifier() const { - return m_graphInfo.m_graphIdentifier; + // #sc_editor_asset + return m_graphIdentifier; } - const AZ::Data::AssetId& ExecutionLogTreeItem::GetAssetId() const + AZ::Data::AssetId ExecutionLogTreeItem::GetAssetId() const { - return m_graphInfo.m_graphIdentifier.m_assetId; + return m_graphInfo.Id(); } AZ::EntityId ExecutionLogTreeItem::GetScriptCanvasAssetNodeId() const diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.h index 862b231f3a..5b6d23590b 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.h @@ -131,7 +131,12 @@ namespace ScriptCanvasEditor AZ_CLASS_ALLOCATOR(ExecutionLogTreeItem, AZ::SystemAllocator, 0); AZ_RTTI(ExecutionLogTreeItem, "{71139142-A30C-4A16-81CC-D51314AEAF7D}", DebugLogTreeItem); - ExecutionLogTreeItem(const LoggingDataId& loggingDataId, const ScriptCanvas::NodeTypeIdentifier& nodeType, const ScriptCanvas::GraphInfo& graphInfo, const ScriptCanvas::NamedNodeId& nodeId); + ExecutionLogTreeItem + ( const LoggingDataId& loggingDataId + , const ScriptCanvas::NodeTypeIdentifier& nodeType + , const SourceHandle& graphInfo + , const ScriptCanvas::NamedNodeId& nodeId); + ~ExecutionLogTreeItem() override = default; QVariant Data(const QModelIndex& index, int role) const override final; @@ -163,7 +168,7 @@ namespace ScriptCanvasEditor //// const ScriptCanvas::GraphIdentifier& GetGraphIdentifier() const; - const AZ::Data::AssetId& GetAssetId() const; + AZ::Data::AssetId GetAssetId() const; AZ::EntityId GetScriptCanvasAssetNodeId() const; GraphCanvas::NodeId GetGraphCanvasNodeId() const; @@ -184,7 +189,8 @@ namespace ScriptCanvasEditor LoggingDataId m_loggingDataId; ScriptCanvas::NodeTypeIdentifier m_nodeType; - ScriptCanvas::GraphInfo m_graphInfo; + SourceHandle m_graphInfo; + ScriptCanvas::GraphIdentifier m_graphIdentifier; QString m_sourceEntityName; QString m_graphName; QString m_relativeGraphPath; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index 32db8451cf..6bd5925fbe 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -819,16 +819,10 @@ namespace ScriptCanvasEditor void MainWindow::SignalActiveSceneChanged(ScriptCanvasEditor::SourceHandle assetId) { - // #se_editor_asset - /* - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); - AZ::EntityId graphId; - - if (memoryAsset) + if (assetId) { - graphId = memoryAsset->GetGraphId(); + EditorGraphRequestBus::EventResult(graphId, assetId.Get()->GetScriptCanvasId(), &EditorGraphRequests::GetGraphCanvasGraphId); } m_autoSaveTimer.stop(); @@ -847,18 +841,20 @@ namespace ScriptCanvasEditor GraphCanvas::ViewId viewId; GraphCanvas::SceneRequestBus::EventResult(viewId, graphId, &GraphCanvas::SceneRequests::GetViewId); - AZ_Assert(viewId.IsValid(), "SceneRequest must return a valid ViewId"); if (viewId.IsValid()) { GraphCanvas::ViewNotificationBus::Handler::BusDisconnect(); GraphCanvas::ViewNotificationBus::Handler::BusConnect(viewId); - enabled = memoryAsset->GetScriptCanvasId().IsValid(); + enabled = true; + } + else + { + AZ_Error("ScriptCanvasEditor", viewId.IsValid(), "SceneRequest must return a valid ViewId"); } } UpdateMenuState(enabled); - */ } void MainWindow::UpdateRecentMenu() @@ -938,7 +934,7 @@ namespace ScriptCanvasEditor if (shouldSaveResults == UnsavedChangesOptions::SAVE) { - // #se_editor_asset + // #sc_editor_asset // Callbacks::OnSave saveCB = [this](bool isSuccessful, AZ::Data::AssetPtr, ScriptCanvasEditor::SourceHandle) // { // if (isSuccessful) @@ -1138,7 +1134,7 @@ namespace ScriptCanvasEditor void MainWindow::MarkAssetModified(const ScriptCanvasEditor::SourceHandle& /*assetId*/) { -// #se_editor_asset if (!assetId.IsValid()) +// #sc_editor_asset if (!assetId.IsValid()) // { // return; // } @@ -1159,7 +1155,7 @@ namespace ScriptCanvasEditor void MainWindow::RefreshScriptCanvasAsset(const AZ::Data::Asset& /*asset*/) { - // #se_editor_asset + // #sc_editor_asset /* ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, asset.GetId()); @@ -1192,12 +1188,9 @@ namespace ScriptCanvasEditor */ } - AZ::Outcome MainWindow::OpenScriptCanvasAssetId(const ScriptCanvasEditor::SourceHandle& /*fileAssetId*/) + AZ::Outcome MainWindow::OpenScriptCanvasAssetId(const ScriptCanvasEditor::SourceHandle& fileAssetId) { - // #se_editor_asset - return AZ::Failure(AZStd::string("rewrite MainWindow::OpenScriptCanvasAssetId")); - /* - if (!fileAssetId.IsValid()) + if (fileAssetId.Id().IsNull()) { return AZ::Failure(AZStd::string("Unable to open asset with invalid asset id")); } @@ -1210,79 +1203,47 @@ namespace ScriptCanvasEditor return AZ::Success(outTabIndex); } - AZ::Data::AssetInfo assetInfo; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, fileAssetId); + outTabIndex = CreateAssetTab(fileAssetId); - if (assetInfo.m_relativePath.empty()) + if (!m_isRestoringWorkspace) { - return AZ::Failure(AZStd::string("Unknown AssetId")); + SetActiveAsset(fileAssetId); } - if (assetInfo.m_assetType != azrtti_typeid()) - { - return AZ::Failure(AZStd::string("Invalid AssetId provided, it's not a Script Canvas supported type")); - } - - AssetTrackerRequests::OnAssetReadyCallback onAssetReady = [this, fileAssetId, &outTabIndex](ScriptCanvasMemoryAsset& asset) - { - if (!asset.IsSourceInError()) - { - outTabIndex = CreateAssetTab(asset.GetFileAssetId()); - - if (!m_isRestoringWorkspace) - { - SetActiveAsset(fileAssetId); - } - - UpdateWorkspaceStatus(asset); - } - else - { - outTabIndex = -1; - m_loadingAssets.erase(fileAssetId); - } - }; - - m_loadingAssets.insert(fileAssetId); - - AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::Load, fileAssetId, assetInfo.m_assetType, onAssetReady); - if (outTabIndex >= 0) { + AddRecentFile(fileAssetId.Path().c_str()); + OpenScriptCanvasAssetImplementation(fileAssetId); return AZ::Success(outTabIndex); } else { return AZ::Failure(AZStd::string("Specified asset is in an error state and cannot be properly displayed.")); } - */ } - AZ::Outcome MainWindow::OpenScriptCanvasAsset(const ScriptCanvasMemoryAsset& /*scriptCanvasAsset*/, int /*tabIndex*/ /*= -1*/) + AZ::Outcome MainWindow::OpenScriptCanvasAssetImplementation(const SourceHandle& scriptCanvasAsset, int tabIndex) { - // #se_editor_asset - return AZ::Failure(AZStd::string("rewrite MainWindow::OpenScriptCanvasAsset")); - /* - const ScriptCanvasEditor::SourceHandle& fileAssetId = scriptCanvasAsset.GetFileAssetId(); + const ScriptCanvasEditor::SourceHandle& fileAssetId = scriptCanvasAsset; if (!fileAssetId.IsValid()) { return AZ::Failure(AZStd::string("Unable to open asset with invalid asset id")); } - if (scriptCanvasAsset.IsSourceInError()) + if (!scriptCanvasAsset.IsValid()) { if (!m_isRestoringWorkspace) { - AZStd::string errorPath = scriptCanvasAsset.GetAbsolutePath(); + AZStd::string errorPath = scriptCanvasAsset.Path(); if (errorPath.empty()) { errorPath = m_errorFilePath; } - if (m_queuedFocusOverride == fileAssetId) + if (m_queuedFocusOverride.AnyEquals(fileAssetId)) { - m_queuedFocusOverride.SetInvalid(); + m_queuedFocusOverride = fileAssetId; } QMessageBox::warning(this, "Unable to open source file", QString("Source File(%1) is in error and cannot be opened").arg(errorPath.c_str()), QMessageBox::StandardButton::Ok); @@ -1307,18 +1268,14 @@ namespace ScriptCanvasEditor if (outTabIndex == -1) { - return AZ::Failure(AZStd::string::format("Unable to open existing Script Canvas Asset with id %s in the Script Canvas Editor", AssetHelpers::AssetIdToString(fileAssetId).c_str())); + return AZ::Failure(AZStd::string::format("Unable to open existing Script Canvas Asset with id %s in the Script Canvas Editor" + , fileAssetId.ToString().c_str())); } - AZStd::string assetPath = scriptCanvasAsset.GetAbsolutePath(); + AZStd::string assetPath = scriptCanvasAsset.Path(); if (!assetPath.empty() && !m_loadingNewlySavedFile) { - const size_t eraseCount = m_loadingWorkspaceAssets.erase(fileAssetId); - - if (eraseCount == 0) - { - AddRecentFile(assetPath.c_str()); - } + AddRecentFile(assetPath.c_str()); } if (!m_isRestoringWorkspace) @@ -1326,47 +1283,34 @@ namespace ScriptCanvasEditor SetActiveAsset(fileAssetId); } - GraphCanvas::GraphId graphCanvasGraphId = GetGraphCanvasGraphId(scriptCanvasAsset.GetScriptCanvasId()); + GraphCanvas::GraphId graphCanvasGraphId = GetGraphCanvasGraphId(scriptCanvasAsset.Get()->GetScriptCanvasId()); GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId, &GraphCanvas::AssetEditorNotifications::OnGraphLoaded, graphCanvasGraphId); GeneralAssetNotificationBus::Event(fileAssetId, &GeneralAssetNotifications::OnAssetVisualized); - AssetTrackerNotificationBus::MultiHandler::BusConnect(fileAssetId); - return AZ::Success(outTabIndex); - */ } - AZ::Outcome MainWindow::OpenScriptCanvasAsset(ScriptCanvasEditor::SourceHandle /*scriptCanvasAssetId*/, int /*tabIndex*/ /*= -1*/) + AZ::Outcome MainWindow::OpenScriptCanvasAsset(ScriptCanvasEditor::SourceHandle scriptCanvasAssetId, int tabIndex) { - // #se_editor_asset - return AZ::Failure(AZStd::string("rewrite MainWindow::OpenScriptCanvasAsset")); - /* - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, scriptCanvasAssetId); - - // If the asset is already tracked we can go directly to opening it. - if (memoryAsset) + if (scriptCanvasAssetId) { - return OpenScriptCanvasAsset(*memoryAsset, tabIndex); + return OpenScriptCanvasAssetImplementation(scriptCanvasAssetId, tabIndex); } else { return OpenScriptCanvasAssetId(scriptCanvasAssetId); } - */ } - int MainWindow::CreateAssetTab(const ScriptCanvasEditor::SourceHandle& /*assetId*/, int /*tabIndex*/) + int MainWindow::CreateAssetTab(const ScriptCanvasEditor::SourceHandle& assetId, int tabIndex) { - // #se_editor_asset - return -1; - // return m_tabBar->InsertGraphTab(tabIndex, assetId); + return m_tabBar->InsertGraphTab(tabIndex, assetId); } AZ::Outcome MainWindow::UpdateScriptCanvasAsset(const AZ::Data::Asset& /*scriptCanvasAsset*/) { - // #se_editor_asset + // #sc_editor_asset return AZ::Failure(AZStd::string("rewrite MainWindow::UpdateScriptCanvasAsset")); /* @@ -1391,7 +1335,7 @@ namespace ScriptCanvasEditor void MainWindow::RemoveScriptCanvasAsset(const ScriptCanvasEditor::SourceHandle& /*assetId*/) { - // #se_editor_asset move what is necessary to the widget + // #sc_editor_asset move what is necessary to the widget /* AssetHelpers::PrintInfo("RemoveScriptCanvasAsset : %s", AssetHelpers::AssetIdToString(assetId).c_str()); @@ -1417,7 +1361,7 @@ namespace ScriptCanvasEditor QVariant tabdata = m_tabBar->tabData(tabIndex); if (tabdata.isValid()) { - auto tabAssetId = tabdata.value(); + auto tabAssetId = tabdata.value(); SetActiveAsset(tabAssetId); } */ @@ -1465,7 +1409,7 @@ namespace ScriptCanvasEditor bool MainWindow::IsScriptCanvasAssetOpen(const ScriptCanvasEditor::SourceHandle& /*assetId*/) const { - // #se_editor_asset + // #sc_editor_asset return false; } @@ -1481,7 +1425,7 @@ namespace ScriptCanvasEditor void MainWindow::GetSuggestedFullFilenameToSaveAs(const ScriptCanvasEditor::SourceHandle& /*assetId*/, AZStd::string& /*filePath*/, AZStd::string& /*fileFilter*/) { - // #se_editor_asset + // #sc_editor_asset /* ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); @@ -1528,18 +1472,50 @@ namespace ScriptCanvasEditor void MainWindow::OpenFile(const char* fullPath) { - AZ::Outcome outcome = LoadFromFile(fullPath); - - if (!outcome.IsSuccess()) + auto tabIndex = m_tabBar->FindTabByPath(fullPath); + if (tabIndex.IsValid()) { + SetActiveAsset(tabIndex); + return; + } + + AZStd::string watchFolder; + AZ::Data::AssetInfo assetInfo; + bool sourceInfoFound{}; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult + ( sourceInfoFound + , &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, fullPath, assetInfo, watchFolder); + + if (!sourceInfoFound) + { + QMessageBox::warning(this, "Invalid Source Asset", QString("'%1' is not a valid asset path.").arg(fullPath), QMessageBox::Ok); m_errorFilePath = fullPath; AZ_Warning("ScriptCanvas", false, "Unable to open file as a ScriptCanvas graph: %s", fullPath); + return; + } + + AZ::Outcome outcome = LoadFromFile(fullPath); + if (!outcome.IsSuccess()) + { + QMessageBox::warning(this, "Invalid Source File", QString("'%1' is not a valid file path.").arg(fullPath), QMessageBox::Ok); + m_errorFilePath = fullPath; + AZ_Warning("ScriptCanvas", false, "Unable to open file as a ScriptCanvas graph: %s", fullPath); + return; + } + + m_errorFilePath.clear(); + m_activeGraph = ScriptCanvasEditor::SourceHandle(outcome.TakeValue(), assetInfo.m_assetId.m_guid, fullPath); + + auto openOutcome = OpenScriptCanvasAsset(m_activeGraph); + if (openOutcome) + { + RunGraphValidation(false); + SetRecentAssetId(m_activeGraph); + SetActiveAsset(m_activeGraph); } else { - m_errorFilePath.clear(); - m_activeGraph = outcome.TakeValue(); - return; + AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data()); } #if defined(EDITOR_ASSET_SUPPORT_ENABLED) @@ -1770,7 +1746,7 @@ namespace ScriptCanvasEditor bool MainWindow::OnFileSave(const Callbacks::OnSave& saveCB) { - return SaveAssetImpl(m_activeGraph, saveCB); + return SaveAssetAsImpl(m_activeGraph, saveCB); } bool MainWindow::OnFileSaveAs(const Callbacks::OnSave& saveCB) @@ -1798,7 +1774,7 @@ namespace ScriptCanvasEditor else if (fileState == Tracker::ScriptCanvasFileState::MODIFIED || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED) { - SaveAsset(assetId, saveCB); + SaveAs(assetId.Path(), assetId, saveCB); saveSuccessful = true; } @@ -1878,7 +1854,7 @@ namespace ScriptCanvasEditor return false; } - SaveNewAsset(internalStringFile, inMemoryAssetId, saveCB); + SaveAs(internalStringFile, inMemoryAssetId, saveCB); m_newlySavedFile = internalStringFile; @@ -1893,7 +1869,7 @@ namespace ScriptCanvasEditor void MainWindow::OnSaveCallback(bool /*saveSuccess*/, AZ::Data::AssetPtr /*fileAsset*/, ScriptCanvasEditor::SourceHandle /*previousFileAssetId*/) { - // #se_editor_asset yikes...just save the thing...move to ::SaveAsset maybe + // #sc_editor_asset yikes...just save the thing...move to ::SaveAsset maybe /* ScriptCanvasMemoryAsset::pointer memoryAsset; @@ -1915,7 +1891,7 @@ namespace ScriptCanvasEditor if (saveTabIndex != m_tabBar->currentIndex()) { // Invalidate the file asset id so we don't delete trigger the asset flow. - m_tabBar->setTabData(saveTabIndex, QVariant::fromValue(ScriptCanvasEditor::SourceHandle())); + m_tabBar->setTabData(saveTabIndex, QVariant::fromValue(GraphTabMetaData)); m_tabBar->CloseTab(saveTabIndex); saveTabIndex = -1; @@ -1936,6 +1912,7 @@ namespace ScriptCanvasEditor AzFramework::StringFunc::Path::GetFileName(memoryAsset->GetAbsolutePath().c_str(), tabName); // Update the tab's assetId to the file asset Id (necessary when saving a new asset) + // used to be configure tab...sets the name and file state m_tabBar->ConfigureTab(saveTabIndex, fileAssetId, tabName); GeneralAssetNotificationBus::Event(memoryAsset->GetId(), &GeneralAssetNotifications::OnAssetVisualized); @@ -2027,53 +2004,11 @@ namespace ScriptCanvasEditor return OnFileSave(saveCB); } - void MainWindow::SaveAsset(ScriptCanvasEditor::SourceHandle /*assetId*/, const Callbacks::OnSave& /*onSave*/) - { - /* - PrepareAssetForSave(assetId); - - auto onSaveCallback = [this, onSave](bool saveSuccess, AZ::Data::AssetPtr asset, ScriptCanvasEditor::SourceHandle previousAssetId) - { - OnSaveCallback(saveSuccess, asset, previousAssetId); - if (onSave) - { - AZStd::invoke(onSave, saveSuccess, asset, previousAssetId); - } - }; - - AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::Save, assetId, onSaveCallback); - UpdateSaveState(); - - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeGraph); - - // Disable the current view if we are saving. - if (memoryAsset) - { - DisableAssetView(memoryAsset); - } - - BlockCloseRequests(); - */ - } - - void MainWindow::SaveNewAsset(AZStd::string_view /*path*/, ScriptCanvasEditor::SourceHandle /*inMemoryAssetId*/, const Callbacks::OnSave& /*onSave*/) + void MainWindow::SaveAs(AZStd::string_view /*path*/, ScriptCanvasEditor::SourceHandle /*inMemoryAssetId*/, const Callbacks::OnSave& /*onSave*/) { /* PrepareAssetForSave(inMemoryAssetId); - auto onSaveCallback = [this, onSave](bool saveSuccess, AZ::Data::AssetPtr asset, ScriptCanvasEditor::SourceHandle previousAssetId) - { - OnSaveCallback(saveSuccess, asset, previousAssetId); - if (onSave) - { - AZStd::invoke(onSave, saveSuccess, asset, previousAssetId); - } - }; - AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::SaveAs, inMemoryAssetId, path, onSaveCallback); - - UpdateSaveState(); - ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, inMemoryAssetId); @@ -2083,6 +2018,44 @@ namespace ScriptCanvasEditor DisableAssetView(memoryAsset); } + auto onSaveCallback = [this, onSave](bool saveSuccess, AZ::Data::AssetPtr asset, ScriptCanvasEditor::SourceHandle previousAssetId) + { + OnSaveCallback(saveSuccess, asset, previousAssetId); + if (onSave) + { + AZStd::invoke(onSave, saveSuccess, asset, previousAssetId); + } + }; + + AZ::Data::AssetStreamInfo streamInfo; + streamInfo.m_streamFlags = AZ::IO::OpenMode::ModeWrite; + streamInfo.m_streamName = m_saveAsPath; + + if (!streamInfo.IsValid()) + { + return; + } + + bool sourceControlActive = false; + AzToolsFramework::SourceControlConnectionRequestBus::BroadcastResult(sourceControlActive, &AzToolsFramework::SourceControlConnectionRequests::IsActive); + // If Source Control is active then use it to check out the file before saving otherwise query the file info and save only if the file is not read-only + if (sourceControlActive) + { + AzToolsFramework::SourceControlCommandBus::Broadcast(&AzToolsFramework::SourceControlCommandBus::Events::RequestEdit, + streamInfo.m_streamName.c_str(), + true, + [this, streamInfo, onSaveCallback](bool success, AzToolsFramework::SourceControlFileInfo info) { FinalizeAssetSave(success, info, streamInfo, onSaveCallback); } + ); + } + else + { + AzToolsFramework::SourceControlCommandBus::Broadcast(&AzToolsFramework::SourceControlCommandBus::Events::GetFileInfo, + streamInfo.m_streamName.c_str(), + [this, streamInfo, onSaveCallback](bool success, AzToolsFramework::SourceControlFileInfo info) { FinalizeAssetSave(success, info, streamInfo, onSaveCallback); } + ); + } + + UpdateSaveState(); BlockCloseRequests(); */ } @@ -2503,7 +2476,6 @@ namespace ScriptCanvasEditor if (eraseCount == 0) { AZStd::string fullPath = AZStd::string::format("%s/%s", rootFilePath.c_str(), assetInfo.m_relativePath.c_str()); - AddRecentFile(fullPath.c_str()); } } } @@ -2566,69 +2538,55 @@ namespace ScriptCanvasEditor AZ::EntityId MainWindow::GetActiveGraphCanvasGraphId() const { - // #se_editor_asset + AZ::EntityId graphId{}; - // AZ::EntityId graphId; - // AssetTrackerRequestBus::BroadcastResult(graphId, &AssetTrackerRequests::GetGraphId, m_activeGraph); - /* - * Falls through to this, which falls through to editor graph, move to canvas widget - AZ::EntityId ScriptCanvasMemoryAsset::GetGraphId() - { - if (!m_graphId.IsValid()) + if (m_activeGraph) { - EditorGraphRequestBus::EventResult(m_graphId, m_scriptCanvasId, &EditorGraphRequests::GetGraphCanvasGraphId); + EditorGraphRequestBus::EventResult + ( graphId, m_activeGraph.Get()->GetScriptCanvasId(), &EditorGraphRequests::GetGraphCanvasGraphId); } - return m_graphId; - } - */ - return AZ::EntityId{}; + return graphId; } ScriptCanvas::ScriptCanvasId MainWindow::GetActiveScriptCanvasId() const { - // ScriptCanvas::ScriptCanvasId sceneId; - // AssetTrackerRequestBus::BroadcastResult(sceneId, &AssetTrackerRequests::GetScriptCanvasId, m_activeGraph); - // #se_editor_asset - return ScriptCanvas::ScriptCanvasId{}; + return FindScriptCanvasIdByAssetId(m_activeGraph); } - GraphCanvas::GraphId MainWindow::GetGraphCanvasGraphId(const ScriptCanvas::ScriptCanvasId& /*scriptCanvasId*/) const + GraphCanvas::GraphId MainWindow::GetGraphCanvasGraphId(const ScriptCanvas::ScriptCanvasId& scriptCanvasId) const { - // #se_editor_asset - // AZ::EntityId graphCanvasId; - // AssetTrackerRequestBus::BroadcastResult(graphCanvasId, &AssetTrackerRequests::GetGraphCanvasId, scriptCanvasId); - // move to widget - return AZ::EntityId{}; + AZ::EntityId graphId{}; + EditorGraphRequestBus::EventResult(graphId, scriptCanvasId, &EditorGraphRequests::GetGraphCanvasGraphId); + return graphId; } - GraphCanvas::GraphId MainWindow::FindGraphCanvasGraphIdByAssetId(const ScriptCanvasEditor::SourceHandle& /*assetId*/) const + GraphCanvas::GraphId MainWindow::FindGraphCanvasGraphIdByAssetId(const ScriptCanvasEditor::SourceHandle& assetId) const { - // #se_editor_asset - // AZ::EntityId graphId; - // AssetTrackerRequestBus::BroadcastResult(graphId, &AssetTrackerRequests::GetGraphId, assetId); - return AZ::EntityId{}; + AZ::EntityId graphId{}; + + if (assetId) + { + EditorGraphRequestBus::EventResult + ( graphId, assetId.Get()->GetScriptCanvasId(), &EditorGraphRequests::GetGraphCanvasGraphId); + } + + return graphId; } - ScriptCanvas::ScriptCanvasId MainWindow::FindScriptCanvasIdByAssetId(const ScriptCanvasEditor::SourceHandle& /*assetId*/) const + ScriptCanvas::ScriptCanvasId MainWindow::FindScriptCanvasIdByAssetId(const ScriptCanvasEditor::SourceHandle& assetId) const { - // #se_editor_asset - // ScriptCanvas::ScriptCanvasId scriptCanvasId; - // AssetTrackerRequestBus::BroadcastResult(scriptCanvasId, &AssetTrackerRequests::GetScriptCanvasId, assetId); - return ScriptCanvas::ScriptCanvasId{}; + return assetId ? assetId.Get()->GetScriptCanvasId() : ScriptCanvas::ScriptCanvasId{}; } - ScriptCanvas::ScriptCanvasId MainWindow::GetScriptCanvasId(const GraphCanvas::GraphId& /*graphCanvasGraphId*/) const + ScriptCanvas::ScriptCanvasId MainWindow::GetScriptCanvasId(const GraphCanvas::GraphId& graphCanvasGraphId) const { - // #se_editor_asset - // ScriptCanvas::ScriptCanvasId scriptCanvasId; - // AssetTrackerRequestBus::BroadcastResult(scriptCanvasId, &AssetTrackerRequests::GetScriptCanvasIdFromGraphId, graphCanvasGraphId); - return ScriptCanvas::ScriptCanvasId{}; + return m_tabBar->FindScriptCanvasIdFromGraphCanvasId(graphCanvasGraphId); } bool MainWindow::IsInUndoRedo(const AZ::EntityId& graphCanvasGraphId) const { - // #se_editor_asset + // #sc_editor_asset bool isActive = false; UndoRequestBus::EventResult(isActive, GetScriptCanvasId(graphCanvasGraphId), &UndoRequests::IsActive); return isActive; @@ -2660,8 +2618,8 @@ namespace ScriptCanvasEditor QVariant tabdata = m_tabBar->tabData(tabIndex); if (tabdata.isValid()) { - auto tabAssetId = tabdata.value(); - if (tabAssetId == assetId) + auto tabAssetId = tabdata.value(); + if (tabAssetId.m_assetId == assetId) { return tabdata; } @@ -2681,21 +2639,15 @@ namespace ScriptCanvasEditor return false; } - void MainWindow::ReconnectSceneBuses(ScriptCanvasEditor::SourceHandle /*previousAssetId*/, ScriptCanvasEditor::SourceHandle /*nextAssetId*/) + void MainWindow::ReconnectSceneBuses(ScriptCanvasEditor::SourceHandle previousAsset, ScriptCanvasEditor::SourceHandle nextAsset) { - // #se_editor_asset - /* - ScriptCanvasMemoryAsset::pointer previousAsset; - AssetTrackerRequestBus::BroadcastResult(previousAsset, &AssetTrackerRequests::GetAsset, previousAssetId); - - ScriptCanvasMemoryAsset::pointer nextAsset; - AssetTrackerRequestBus::BroadcastResult(nextAsset, &AssetTrackerRequests::GetAsset, nextAssetId); - + // #sc_editor_asset + // Disconnect previous asset AZ::EntityId previousScriptCanvasSceneId; if (previousAsset) { - previousScriptCanvasSceneId = previousAsset->GetScriptCanvasId(); + previousScriptCanvasSceneId = previousAsset.Get()->GetScriptCanvasId(); GraphCanvas::SceneNotificationBus::MultiHandler::BusDisconnect(previousScriptCanvasSceneId); } @@ -2703,7 +2655,8 @@ namespace ScriptCanvasEditor if (nextAsset) { // Connect the next asset - nextAssetGraphCanvasId = nextAsset->GetGraphId(); + EditorGraphRequestBus::EventResult(nextAssetGraphCanvasId, nextAsset.Get()->GetScriptCanvasId(), &EditorGraphRequests::GetGraphCanvasGraphId); + if (nextAssetGraphCanvasId.IsValid()) { GraphCanvas::SceneNotificationBus::MultiHandler::BusConnect(nextAssetGraphCanvasId); @@ -2716,13 +2669,12 @@ namespace ScriptCanvasEditor // Notify about the graph refresh GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId, &GraphCanvas::AssetEditorNotifications::OnGraphRefreshed, previousScriptCanvasSceneId, nextAssetGraphCanvasId); - */ } - void MainWindow::SetActiveAsset(const ScriptCanvasEditor::SourceHandle& /*fileAssetId*/) + void MainWindow::SetActiveAsset(const ScriptCanvasEditor::SourceHandle& fileAssetId) { - // #se_editor_asset - /* + // #sc_editor_asset + if (m_activeGraph == fileAssetId) { return; @@ -2745,98 +2697,61 @@ namespace ScriptCanvasEditor if (m_activeGraph.IsValid()) { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeGraph); - // If we are saving the asset, the Id may have changed from the in-memory to the file asset Id, in that case, // there's no need to hide the view or remove the widget - if (memoryAsset && memoryAsset->GetView()) + auto oldTab = m_tabBar->FindTab(m_activeGraph); + if (auto view = m_tabBar->ModTabView(oldTab)) { - memoryAsset->GetView()->hide(); - m_layout->removeWidget(memoryAsset->GetView()); + view->hide(); + m_layout->removeWidget(view); + m_tabBar->ClearTabView(oldTab); } } if (fileAssetId.IsValid()) { ScriptCanvasEditor::SourceHandle previousAssetId = m_activeGraph; - m_activeGraph = fileAssetId; RefreshActiveAsset(); - ReconnectSceneBuses(previousAssetId, m_activeGraph); } else { ScriptCanvasEditor::SourceHandle previousAssetId = m_activeGraph; - m_activeGraph.Clear(); m_emptyCanvas->show(); - ReconnectSceneBuses(previousAssetId, m_activeGraph); - SignalActiveSceneChanged(ScriptCanvasEditor::SourceHandle()); } UpdateUndoCache(fileAssetId); - - RefreshSelection(); - */ + RefreshSelection(); } void MainWindow::RefreshActiveAsset() { - // #se_editor_asset - /* if (m_activeGraph.IsValid()) { AssetHelpers::PrintInfo("RefreshActiveAsset : m_activeGraph (%s)", m_activeGraph.ToString().c_str()); - - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeGraph); - - if (memoryAsset) + if (auto view = m_tabBar->ModOrCreateTabView(m_tabBar->FindTab(m_activeGraph))) { - AZ::EntityId sceneEntityId = memoryAsset->GetScriptCanvasId(); - - const auto& scriptCanvasAsset = memoryAsset->GetAsset(); - - if (scriptCanvasAsset.IsReady() && scriptCanvasAsset.Get()->GetScriptCanvasEntity()->GetState() == AZ::Entity::State::Active) - { - if (!memoryAsset->GetView()) - { - memoryAsset->CreateView(m_tabBar); - } - - auto view = memoryAsset->GetView(); - AZ_Assert(view, "Asset should have a view"); - if (view) - { - AssetHelpers::PrintInfo("RefreshActiveAsset : m_activeGraph (%s)", m_activeGraph.ToString().c_str()); - - view->ShowScene(sceneEntityId); - m_layout->addWidget(view); - view->show(); - - m_emptyCanvas->hide(); - } - - SignalActiveSceneChanged(m_activeGraph); - } + view->ShowScene(m_activeGraph.Get()->GetScriptCanvasId()); + m_layout->addWidget(view); + view->show(); + m_emptyCanvas->hide(); + SignalActiveSceneChanged(m_activeGraph); } else { - // If we couldn't load a memory asset for our active asset. Just set ourselves to invalid. SetActiveAsset({}); } } - */ } void MainWindow::Clear() { m_tabBar->CloseAllTabs(); - // #se_editor_asset + // #sc_editor_asset // // AssetTrackerRequests::AssetList assets; // AssetTrackerRequestBus::BroadcastResult(assets, &AssetTrackerRequests::GetAssets); @@ -2855,12 +2770,12 @@ namespace ScriptCanvasEditor QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) { - auto fileAssetId = tabdata.value(); + auto fileAssetId = tabdata.value(); Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::NEW; bool isSaving = false; - // #se_editor_asset Get from widgets + // #sc_editor_asset Get from widgets /* AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, fileAssetId); AssetTrackerRequestBus::BroadcastResult(isSaving, &AssetTrackerRequests::IsSaving, fileAssetId); @@ -2874,9 +2789,9 @@ namespace ScriptCanvasEditor UnsavedChangesOptions saveDialogResults = UnsavedChangesOptions::CONTINUE_WITHOUT_SAVING; if (!isSaving && (fileState == Tracker::ScriptCanvasFileState::NEW || fileState == Tracker::ScriptCanvasFileState::MODIFIED || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED)) { - SetActiveAsset(fileAssetId); + SetActiveAsset(fileAssetId.m_assetId); - // #se_editor_asset + // #sc_editor_asset AZStd::string tabName = "Get from widget"; // AssetTrackerRequestBus::BroadcastResult(tabName, &AssetTrackerRequests::GetTabName, fileAssetId); @@ -2885,7 +2800,7 @@ namespace ScriptCanvasEditor if (saveDialogResults == UnsavedChangesOptions::SAVE) { - // #se_editor_asset + // #sc_editor_asset // auto saveCB = [this](bool isSuccessful, AZ::Data::AssetPtr asset, ScriptCanvasEditor::SourceHandle) // { // if (isSuccessful) @@ -2927,10 +2842,9 @@ namespace ScriptCanvasEditor QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) { - auto assetId = tabdata.value(); - SaveAssetImpl(assetId, nullptr); + auto assetId = tabdata.value(); + SaveAssetAsImpl(assetId.m_assetId, nullptr); } - } void MainWindow::CloseAllTabs() @@ -2946,7 +2860,7 @@ namespace ScriptCanvasEditor QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) { - auto assetId = tabdata.value(); + auto assetId = tabdata.value().m_assetId; m_isClosingTabs = true; m_skipTabOnClose = assetId; @@ -2956,7 +2870,7 @@ namespace ScriptCanvasEditor void MainWindow::CopyPathToClipboard(int /*index*/) { - // #se_editor_asset + // #sc_editor_asset /* QVariant tabdata = m_tabBar->tabData(index); @@ -2964,7 +2878,7 @@ namespace ScriptCanvasEditor { QClipboard* clipBoard = QGuiApplication::clipboard(); - auto assetId = tabdata.value(); + auto assetId = tabdata.value(); ScriptCanvasMemoryAsset::pointer memoryAsset; AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); @@ -3006,9 +2920,9 @@ namespace ScriptCanvasEditor QVariant tabdata = m_tabBar->tabData(tab); if (tabdata.isValid()) { - auto assetId = tabdata.value(); + auto assetId = tabdata.value(); - if (assetId != m_skipTabOnClose) + if (assetId.m_assetId != m_skipTabOnClose) { break; } @@ -3027,7 +2941,7 @@ namespace ScriptCanvasEditor QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) { - auto tabAssetId = tabdata.value(); + auto tabAssetId = tabdata.value(); if (tabAssetId == m_activeGraph) { @@ -3694,7 +3608,7 @@ namespace ScriptCanvasEditor void MainWindow::UpdateSaveState() { - // #se_editor_asset todo, consider making blocking + // #sc_editor_asset todo, consider making blocking // bool enabled = m_activeGraph.IsValid(); // bool isSaving = false; // bool hasModifications = false; @@ -3910,7 +3824,7 @@ namespace ScriptCanvasEditor AZ::EntityId MainWindow::FindEditorNodeIdByAssetNodeId(const ScriptCanvasEditor::SourceHandle& /*assetId*/, AZ::EntityId /*assetNodeId*/) const { - // #se_editor_asset + // #sc_editor_asset return AZ::EntityId{}; // AZ::EntityId editorEntityId; // AssetTrackerRequestBus::BroadcastResult(editorEntityId, &AssetTrackerRequests::GetEditorEntityIdFromSceneEntityId, assetId, assetNodeId); @@ -3919,7 +3833,7 @@ namespace ScriptCanvasEditor AZ::EntityId MainWindow::FindAssetNodeIdByEditorNodeId(const ScriptCanvasEditor::SourceHandle& /*assetId*/, AZ::EntityId /*editorNodeId*/) const { - // #se_editor_asset + // #sc_editor_asset return AZ::EntityId{}; // AZ::EntityId sceneEntityId; // AssetTrackerRequestBus::BroadcastResult(sceneEntityId, &AssetTrackerRequests::GetSceneEntityIdFromEditorEntityId, assetId, editorNodeId); @@ -4413,7 +4327,7 @@ namespace ScriptCanvasEditor void MainWindow::OnAssignToSelectedEntities() { - // #se_editor_asset consider cutting + // #sc_editor_asset consider cutting // Tracker::ScriptCanvasFileState fileState; // AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, m_activeGraph); // @@ -4487,7 +4401,7 @@ namespace ScriptCanvasEditor ScriptCanvasEditor::Tracker::ScriptCanvasFileState MainWindow::GetAssetFileState(ScriptCanvasEditor::SourceHandle /*assetId*/) const { - // #se_editor_asset + // #sc_editor_asset return Tracker::ScriptCanvasFileState::INVALID; // Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::INVALID; // AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, assetId); @@ -4540,7 +4454,7 @@ namespace ScriptCanvasEditor if (usableRequestBus) { ScriptCanvasMemoryAsset::pointer memoryAsset; - // #se_editor_asset + // #sc_editor_asset // AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeGraph); if (memoryAsset) @@ -4597,6 +4511,7 @@ namespace ScriptCanvasEditor m_filesToOpen.pop_front(); OpenFile(nextFile.toUtf8().data()); + OpenNextFile(); } else { diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h index 1c98769463..ee93308035 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h @@ -230,7 +230,7 @@ namespace ScriptCanvasEditor , private VariablePaletteRequestBus::Handler , private ScriptCanvas::BatchOperationNotificationBus::Handler , private AssetGraphSceneBus::Handler - , private AssetTrackerNotificationBus::MultiHandler + //, private AssetTrackerNotificationBus::MultiHandler #if SCRIPTCANVAS_EDITOR //, public IEditorNotifyListener #endif @@ -421,7 +421,7 @@ namespace ScriptCanvasEditor //! GeneralRequestBus AZ::Outcome OpenScriptCanvasAssetId(const SourceHandle& assetId) override; AZ::Outcome OpenScriptCanvasAsset(SourceHandle scriptCanvasAssetId, int tabIndex = -1) override; - AZ::Outcome OpenScriptCanvasAsset(const ScriptCanvasMemoryAsset& scriptCanvasAsset, int tabIndex = -1); + AZ::Outcome OpenScriptCanvasAssetImplementation(const SourceHandle& sourceHandle, int tabIndex = -1); int CloseScriptCanvasAsset(const SourceHandle& assetId) override; bool CreateScriptCanvasAssetFor(const TypeDefs::EntityComponentId& requestingEntityId) override; @@ -556,8 +556,7 @@ namespace ScriptCanvasEditor bool ActivateAndSaveAsset(const ScriptCanvasEditor::SourceHandle& unsavedAssetId, const Callbacks::OnSave& onSave); - void SaveNewAsset(AZStd::string_view path, ScriptCanvasEditor::SourceHandle assetId, const Callbacks::OnSave& onSave); - void SaveAsset(ScriptCanvasEditor::SourceHandle assetId, const Callbacks::OnSave& onSave); + void SaveAs(AZStd::string_view path, ScriptCanvasEditor::SourceHandle assetId, const Callbacks::OnSave& onSave); void OpenFile(const char* fullPath); void CreateMenus(); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp index 09c21fe43f..15e2192ee8 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp @@ -190,12 +190,27 @@ namespace ScriptCanvas namespace ScriptCanvasEditor { + SourceHandle::SourceHandle(const SourceHandle& data, const AZ::Uuid& id, AZStd::string_view path) + : m_data(data.m_data) + , m_id(id) + , m_path(path) + { + + } + SourceHandle::SourceHandle(ScriptCanvas::DataPtr graph, const AZ::Uuid& id, AZStd::string_view path) : m_data(graph) , m_id(id) , m_path(path) {} + bool SourceHandle::AnyEquals(const SourceHandle& other) const + { + return m_data == other.m_data + || m_id == other.m_id + || m_path == other.m_path; + } + void SourceHandle::Clear() { m_data = nullptr; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h index 4c1734413c..1a81345054 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h @@ -326,8 +326,12 @@ namespace ScriptCanvasEditor SourceHandle() = default; + SourceHandle(const SourceHandle& data, const AZ::Uuid& id, AZStd::string_view path); + SourceHandle(ScriptCanvas::DataPtr graph, const AZ::Uuid& id, AZStd::string_view path); + bool AnyEquals(const SourceHandle& other) const; + void Clear(); GraphPtrConst Get() const; @@ -391,11 +395,28 @@ namespace AZStd { using argument_type = ScriptCanvas::SlotId; using result_type = AZStd::size_t; - AZ_FORCE_INLINE size_t operator()(const argument_type& ref) const + + inline size_t operator()(const argument_type& ref) const { return AZStd::hash()(ref.m_id); } }; + + template<> + struct hash + { + using argument_type = ScriptCanvasEditor::SourceHandle; + using result_type = AZStd::size_t; + + inline size_t operator()(const argument_type& handle) const + { + size_t h = 0; + hash_combine(h, handle.Id()); + hash_combine(h, handle.Path()); + hash_combine(h, handle.Get()); + return h; + } + }; } #define SCRIPT_CANVAS_INFINITE_LOOP_DETECTION_COUNT (2000000) From 12b52044d349e07e5637210e8ac63b1c97165cfc Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 3 Nov 2021 21:12:29 -0700 Subject: [PATCH 005/128] it renders! Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Source/Components/SceneComponent.cpp | 1 + .../Editor/Assets/ScriptCanvasFileHandling.cpp | 6 +++++- .../Code/Editor/Components/EditorGraph.cpp | 2 +- .../Code/Editor/View/Widgets/GraphTabBar.cpp | 1 + .../Code/Editor/View/Windows/MainWindow.cpp | 15 ++++----------- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Gems/GraphCanvas/Code/Source/Components/SceneComponent.cpp b/Gems/GraphCanvas/Code/Source/Components/SceneComponent.cpp index 52e7892364..e821ea9be2 100644 --- a/Gems/GraphCanvas/Code/Source/Components/SceneComponent.cpp +++ b/Gems/GraphCanvas/Code/Source/Components/SceneComponent.cpp @@ -669,6 +669,7 @@ namespace GraphCanvas { GeometryNotificationBus::Handler::BusDisconnect(); SceneNotificationBus::Handler::BusDisconnect(); + AZ::SystemTickBus::Handler::BusDisconnect(); } void GestureSceneHelper::TrackElement(const AZ::EntityId& elementId) diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp index e8ee2ed97c..0acbf640b0 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp @@ -99,7 +99,11 @@ namespace ScriptCanvasEditor } const auto& asString = fileStringOutcome.GetValue(); - DataPtr scriptCanvasData = Graph::Create(); + 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); diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp index 4a03a60db8..951f2253b1 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp @@ -490,7 +490,7 @@ namespace ScriptCanvasEditor EditorGraphRequestBus::Handler::BusDisconnect(); SceneCounterRequestBus::Handler::BusDisconnect(); NodeCreationNotificationBus::Handler::BusDisconnect(); - + AZ::SystemTickBus::Handler::BusDisconnect(); GraphCanvas::SceneNotificationBus::Handler::BusDisconnect(); GraphCanvas::GraphModelRequestBus::Handler::BusDisconnect(); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp index ce8c280b35..11fefe59bf 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp @@ -115,6 +115,7 @@ namespace ScriptCanvasEditor CanvasWidget* canvasWidget = new CanvasWidget(assetId, this); canvasWidget->SetDefaultBorderColor(ScriptCanvasAssetDescription().GetDisplayColorImpl()); metaData.m_canvasWidget = canvasWidget; + metaData.m_assetId = assetId; AZStd::string tabName; AzFramework::StringFunc::Path::GetFileName(assetId.Path().c_str(), tabName); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index 6bd5925fbe..ecc3d52e5f 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -1278,16 +1278,9 @@ namespace ScriptCanvasEditor AddRecentFile(assetPath.c_str()); } - if (!m_isRestoringWorkspace) - { - SetActiveAsset(fileAssetId); - } - GraphCanvas::GraphId graphCanvasGraphId = GetGraphCanvasGraphId(scriptCanvasAsset.Get()->GetScriptCanvasId()); GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId, &GraphCanvas::AssetEditorNotifications::OnGraphLoaded, graphCanvasGraphId); - GeneralAssetNotificationBus::Event(fileAssetId, &GeneralAssetNotifications::OnAssetVisualized); - return AZ::Success(outTabIndex); } @@ -1504,14 +1497,14 @@ namespace ScriptCanvasEditor } m_errorFilePath.clear(); - m_activeGraph = ScriptCanvasEditor::SourceHandle(outcome.TakeValue(), assetInfo.m_assetId.m_guid, fullPath); + auto activeGraph = ScriptCanvasEditor::SourceHandle(outcome.TakeValue(), assetInfo.m_assetId.m_guid, fullPath); - auto openOutcome = OpenScriptCanvasAsset(m_activeGraph); + auto openOutcome = OpenScriptCanvasAsset(activeGraph); if (openOutcome) { RunGraphValidation(false); - SetRecentAssetId(m_activeGraph); - SetActiveAsset(m_activeGraph); + SetActiveAsset(activeGraph); + SetRecentAssetId(activeGraph); } else { From ea5eba6e3f45553141ae4f5b119aa3022eb6fa6e Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Thu, 4 Nov 2021 15:58:19 -0700 Subject: [PATCH 006/128] add file state for graphs Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Assets/ScriptCanvasFileHandling.cpp | 3 + .../Code/Editor/Components/EditorGraph.cpp | 30 ++++---- .../ScriptCanvas/Components/EditorGraph.h | 5 +- .../Code/Editor/SystemComponent.cpp | 4 +- .../Code/Editor/View/Widgets/GraphTabBar.cpp | 75 ++++++++++++++----- .../Code/Editor/View/Widgets/GraphTabBar.h | 10 ++- .../VariablePanel/GraphVariablesTableView.cpp | 5 +- .../Code/Editor/View/Windows/MainWindow.cpp | 33 ++------ .../Code/Editor/View/Windows/MainWindow.h | 2 +- .../Code/Include/ScriptCanvas/Core/Core.h | 1 + .../Code/Include/ScriptCanvas/Core/Graph.cpp | 5 -- .../Code/Include/ScriptCanvas/Core/Graph.h | 4 +- .../Code/Include/ScriptCanvas/Core/GraphBus.h | 3 - .../ScriptCanvas/Variable/GraphVariable.cpp | 8 -- .../ScriptCanvas/Variable/GraphVariable.h | 4 +- 15 files changed, 99 insertions(+), 93 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp index 0acbf640b0..42dcf81a8d 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp @@ -132,6 +132,9 @@ namespace ScriptCanvasEditor { entity->Init(); entity->Activate(); + + auto graph = entity->FindComponent(); + graph->MarkOwnership(*scriptCanvasData); } return AZ::Success(ScriptCanvasEditor::SourceHandle(scriptCanvasData, {}, path)); diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp index 951f2253b1..770d56860f 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp @@ -1030,14 +1030,16 @@ namespace ScriptCanvasEditor { AZStd::any* connectionUserData = nullptr; GraphCanvas::ConnectionRequestBus::EventResult(connectionUserData, connectionId, &GraphCanvas::ConnectionRequests::GetUserData); - auto scConnectionId = connectionUserData && connectionUserData->is() ? *AZStd::any_cast(connectionUserData) : AZ::EntityId(); + auto scConnectionId = connectionUserData && connectionUserData->is() + ? *AZStd::any_cast(connectionUserData) + : AZ::EntityId(); - ScriptCanvas::Connection* connection = AZ::EntityUtils::FindFirstDerivedComponent(scConnectionId); - - if (connection) + if (ScriptCanvas::Connection* connection = AZ::EntityUtils::FindFirstDerivedComponent(scConnectionId)) { - ScriptCanvas::GraphNotificationBus::Event(GetScriptCanvasId(), &ScriptCanvas::GraphNotifications::OnDisonnectionComplete, connectionId); - + ScriptCanvas::GraphNotificationBus::Event + ( GetScriptCanvasId() + , &ScriptCanvas::GraphNotifications::OnDisonnectionComplete + , connectionId); DisconnectById(scConnectionId); } } @@ -1047,12 +1049,12 @@ namespace ScriptCanvasEditor if (AZ::Entity* entity = aznew AZ::Entity("Script Canvas Graph")) { auto graph = entity->CreateComponent(); - graph->SetAssetType(azrtti_typeid()); entity->CreateComponent(graph->GetScriptCanvasId()); if (ScriptCanvas::DataPtr data = AZStd::make_shared()) { data->m_scriptCanvasEntity.reset(entity); + graph->MarkOwnership(*data); return data; } } @@ -1060,6 +1062,11 @@ namespace ScriptCanvasEditor return nullptr; } + void Graph::MarkOwnership(ScriptCanvas::ScriptCanvasData& owner) + { + m_owner = &owner; + } + bool Graph::CreateConnection(const GraphCanvas::ConnectionId& connectionId, const GraphCanvas::Endpoint& sourcePoint, const GraphCanvas::Endpoint& targetPoint) { if (!sourcePoint.IsValid() || !targetPoint.IsValid()) @@ -1340,8 +1347,8 @@ namespace ScriptCanvasEditor void Graph::SignalDirty() { - // #sc_editor_asset - // GeneralRequestBus::Broadcast(&GeneralRequests::SignalSceneDirty, GetAssetId()); + SourceHandle handle(ScriptCanvas::DataPtr(m_owner), {}, {}); + GeneralRequestBus::Broadcast(&GeneralRequests::SignalSceneDirty, handle); } void Graph::HighlightNodesByType(const ScriptCanvas::NodeTypeIdentifier& nodeTypeIdentifier) @@ -3372,11 +3379,6 @@ namespace ScriptCanvasEditor } } - void Graph::SetAssetType(AZ::Data::AssetType assetType) - { - m_assetType = assetType; - } - void Graph::ReportError(const ScriptCanvas::Node& node, const AZStd::string& errorSource, const AZStd::string& errorMessage) { AzQtComponents::ToastConfiguration toastConfiguration(AzQtComponents::ToastType::Error, errorSource.c_str(), errorMessage.c_str()); diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h index c0c8584cbd..526c929664 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h @@ -304,12 +304,12 @@ namespace ScriptCanvasEditor void OnUndoRedoEnd() override; //// - void SetAssetType(AZ::Data::AssetType); - void ReportError(const ScriptCanvas::Node& node, const AZStd::string& errorSource, const AZStd::string& errorMessage) override; const GraphStatisticsHelper& GetNodeUsageStatistics() const; + void MarkOwnership(ScriptCanvas::ScriptCanvasData& owner); + // Finds and returns all nodes within the graph that are of the specified type template AZStd::vector GetNodesOfType() const @@ -393,5 +393,6 @@ namespace ScriptCanvasEditor bool m_saveFormatConverted = true; ScriptCanvasEditor::SourceHandle m_assetId; + ScriptCanvas::ScriptCanvasData* m_owner; }; } diff --git a/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp b/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp index 0246071172..ab8cd0e61b 100644 --- a/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp @@ -173,13 +173,11 @@ namespace ScriptCanvasEditor outCreatableTypes.insert(m_creatableTypes.begin(), m_creatableTypes.end()); } - void SystemComponent::CreateEditorComponentsOnEntity(AZ::Entity* entity, const AZ::Data::AssetType& assetType) + void SystemComponent::CreateEditorComponentsOnEntity(AZ::Entity* entity, [[maybe_unused]] const AZ::Data::AssetType& assetType) { if (entity) { auto graph = entity->CreateComponent(); - graph->SetAssetType(assetType); - entity->CreateComponent(graph->GetScriptCanvasId()); } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp index 11fefe59bf..029d713277 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp @@ -105,6 +105,44 @@ namespace ScriptCanvasEditor return nullptr; } + AZStd::optional GraphTabBar::GetTabData(int tabIndex) const + { + if (tabIndex < count()) + { + if (QVariant tabDataVariant = tabData(tabIndex); tabDataVariant.isValid()) + { + return tabDataVariant.value(); + } + } + + return AZStd::nullopt; + } + + AZStd::optional GraphTabBar::GetTabData(ScriptCanvasEditor::SourceHandle assetId) const + { + return GetTabData(FindTab(assetId)); + } + + void GraphTabBar::SetTabData(const GraphTabMetadata& metadata, int tabIndex) + { + if (tabIndex < count()) + { + setTabData(tabIndex, QVariant::fromValue(metadata)); + } + } + + void GraphTabBar::SetTabData(const GraphTabMetadata& metadata, ScriptCanvasEditor::SourceHandle assetId) + { + auto index = FindTab(assetId); + auto replacement = GetTabData(assetId); + + if (index >= 0 && replacement) + { + replacement->m_assetId = assetId; + SetTabData(metadata, index); + } + } + int GraphTabBar::InsertGraphTab(int tabIndex, ScriptCanvasEditor::SourceHandle assetId) { if (!SelectTab(assetId)) @@ -119,6 +157,7 @@ namespace ScriptCanvasEditor AZStd::string tabName; AzFramework::StringFunc::Path::GetFileName(assetId.Path().c_str(), tabName); + metaData.m_name = tabName.c_str(); // #sc_editor_asset filestate Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::INVALID; @@ -381,6 +420,23 @@ namespace ScriptCanvasEditor Q_EMIT TabRemoved(index); } + void GraphTabBar::UpdateFileState(const ScriptCanvasEditor::SourceHandle& assetId, Tracker::ScriptCanvasFileState fileState) + { + auto tabData = GetTabData(assetId); + if (tabData && tabData->m_fileState != fileState) + { + int index = FindTab(assetId); + tabData->m_fileState = fileState; + SetTabData(*tabData, assetId); + SetTabText(index, tabData->m_name, fileState); + + if (index == currentIndex()) + { + Q_EMIT OnActiveFileStateChanged(); + } + } + } + void GraphTabBar::currentChangedTab(int index) { if (index < 0) @@ -406,25 +462,6 @@ namespace ScriptCanvasEditor } } - void GraphTabBar::SetFileState(ScriptCanvasEditor::SourceHandle, Tracker::ScriptCanvasFileState ) - { - // #sc_editor_asset - // int index = FindTab(assetId); - -// if (index >= 0 && index < count()) -// { -// QVariant tabdata = tabData(index); -// if (tabdata.isValid()) -// { -// auto tabAssetId = tabdata.value(); -// -// AZStd::string tabName; -// AssetTrackerRequestBus::BroadcastResult(tabName, &AssetTrackerRequests::GetTabName, tabAssetId); -// SetTabText(index, tabName.c_str(), fileState); -// } -// } - } - #include } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h index 12e73b4ae5..48f327b244 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h @@ -35,6 +35,7 @@ namespace ScriptCanvasEditor QWidget* m_hostWidget = nullptr; CanvasWidget* m_canvasWidget = nullptr; Tracker::ScriptCanvasFileState m_fileState = Tracker::ScriptCanvasFileState::INVALID; + QString m_name; }; class GraphTabBar @@ -48,6 +49,11 @@ namespace ScriptCanvasEditor GraphTabBar(QWidget* parent = nullptr); ~GraphTabBar() override = default; + AZStd::optional GetTabData(int index) const; + AZStd::optional GetTabData(ScriptCanvasEditor::SourceHandle assetId) const; + void SetTabData(const GraphTabMetadata& data, int index); + void SetTabData(const GraphTabMetadata& data, ScriptCanvasEditor::SourceHandle assetId); + void AddGraphTab(ScriptCanvasEditor::SourceHandle assetId); void CloseTab(int index); void CloseAllTabs(); @@ -78,6 +84,8 @@ namespace ScriptCanvasEditor // The host widget field of the tabMetadata is not used and will not overwrite the tab data void SetTabText(int tabIndex, const QString& path, Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::INVALID); + void UpdateFileState(const ScriptCanvasEditor::SourceHandle& assetId, Tracker::ScriptCanvasFileState fileState); + Q_SIGNALS: void TabInserted(int index); void TabRemoved(int index); @@ -101,8 +109,6 @@ namespace ScriptCanvasEditor // Called when the selected tab changes void currentChangedTab(int index); - void SetFileState(ScriptCanvasEditor::SourceHandle, Tracker::ScriptCanvasFileState fileState); - int m_signalSaveOnChangeTo = -1; }; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/GraphVariablesTableView.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/GraphVariablesTableView.cpp index 5b78c62bac..1af554dd32 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/GraphVariablesTableView.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/GraphVariablesTableView.cpp @@ -716,10 +716,7 @@ namespace ScriptCanvasEditor void GraphVariablesModel::SetActiveScene(const ScriptCanvas::ScriptCanvasId& scriptCanvasId) { ScriptCanvas::GraphVariableManagerNotificationBus::Handler::BusDisconnect(); - - m_assetType = AZ::Data::AssetType::CreateNull(); - ScriptCanvas::GraphRequestBus::EventResult(m_assetType, scriptCanvasId, &ScriptCanvas::GraphRequests::GetAssetType); - + m_assetType = azrtti_typeid(); m_scriptCanvasId = scriptCanvasId; if (m_scriptCanvasId.IsValid()) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index ecc3d52e5f..fe2d451e75 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -1102,7 +1102,7 @@ namespace ScriptCanvasEditor { ScopedUndoBatch scopedUndoBatch("Modify Graph Canvas Scene"); UndoRequestBus::Event(scriptCanvasId, &UndoRequests::AddGraphItemChangeUndo, "Graph Change"); - MarkAssetModified(m_activeGraph); + UpdateFileState(m_activeGraph, Tracker::ScriptCanvasFileState::MODIFIED); } const bool forceTimer = true; @@ -1111,7 +1111,7 @@ namespace ScriptCanvasEditor void MainWindow::SignalSceneDirty(ScriptCanvasEditor::SourceHandle assetId) { - MarkAssetModified(assetId); + UpdateFileState(assetId, Tracker::ScriptCanvasFileState::MODIFIED); } void MainWindow::PushPreventUndoStateUpdate() @@ -1132,25 +1132,9 @@ namespace ScriptCanvasEditor m_preventUndoStateUpdateCount = 0; } - void MainWindow::MarkAssetModified(const ScriptCanvasEditor::SourceHandle& /*assetId*/) + void MainWindow::UpdateFileState(const ScriptCanvasEditor::SourceHandle& assetId, Tracker::ScriptCanvasFileState fileState) { -// #sc_editor_asset if (!assetId.IsValid()) -// { -// return; -// } -// -// ScriptCanvasMemoryAsset::pointer memoryAsset; -// AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); -// -// if (memoryAsset) -// { -// const auto& memoryAssetId = memoryAsset->GetId(); -// const Tracker::ScriptCanvasFileState& fileState = GetAssetFileState(memoryAssetId); -// if (fileState != Tracker::ScriptCanvasFileState::NEW) -// { -// AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::UpdateFileState, memoryAssetId, Tracker::ScriptCanvasFileState::MODIFIED); -// } -// } + m_tabBar->UpdateFileState(assetId, fileState); } void MainWindow::RefreshScriptCanvasAsset(const AZ::Data::Asset& /*asset*/) @@ -4392,13 +4376,10 @@ namespace ScriptCanvasEditor } } - ScriptCanvasEditor::Tracker::ScriptCanvasFileState MainWindow::GetAssetFileState(ScriptCanvasEditor::SourceHandle /*assetId*/) const + ScriptCanvasEditor::Tracker::ScriptCanvasFileState MainWindow::GetAssetFileState(ScriptCanvasEditor::SourceHandle assetId) const { - // #sc_editor_asset - return Tracker::ScriptCanvasFileState::INVALID; - // Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::INVALID; - // AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, assetId); - // return fileState; + auto dataOptional = m_tabBar->GetTabData(assetId); + return dataOptional ? dataOptional->m_fileState : Tracker::ScriptCanvasFileState::INVALID; } void MainWindow::AssignGraphToEntityImpl(const AZ::EntityId& entityId) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h index ee93308035..0a687e0011 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h @@ -548,7 +548,7 @@ namespace ScriptCanvasEditor //! \param asset asset to save void GetSuggestedFullFilenameToSaveAs(const ScriptCanvasEditor::SourceHandle& assetId, AZStd::string& filePath, AZStd::string& fileFilter); - void MarkAssetModified(const ScriptCanvasEditor::SourceHandle& assetId); + void UpdateFileState(const ScriptCanvasEditor::SourceHandle& assetId, Tracker::ScriptCanvasFileState fileState); // QMainWindow void closeEvent(QCloseEvent *event) override; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h index 1a81345054..ece7008b06 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h @@ -360,6 +360,7 @@ namespace ScriptCanvasEditor namespace ScriptCanvas { class ScriptCanvasData + : public AZStd::enable_shared_from_this { public: diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp index 9d848ff998..ee500514dc 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp @@ -1190,11 +1190,6 @@ namespace ScriptCanvas m_isObserved = isObserved; } - AZ::Data::AssetType Graph::GetAssetType() const - { - return m_assetType; - } - void Graph::VersioningRemoveSlot(ScriptCanvas::Node& scriptCanvasNode, const SlotId& slotId) { bool deletedSlot = true; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.h index 786e693a04..76fc3a6c7b 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.h @@ -187,8 +187,6 @@ namespace ScriptCanvas bool IsGraphObserved() const override; void SetIsGraphObserved(bool isObserved) override; - - AZ::Data::AssetType GetAssetType() const override; //// const AZStd::unordered_map& GetNodeMapping() const { return m_nodeMapping; } @@ -198,7 +196,7 @@ namespace ScriptCanvas GraphData m_graphData; AZ::Data::AssetType m_assetType; - + private: ScriptCanvasId m_scriptCanvasId; ExecutionMode m_executionMode = ExecutionMode::Interpreted; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/GraphBus.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/GraphBus.h index 6b7133d47e..53d1a95964 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/GraphBus.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/GraphBus.h @@ -147,9 +147,6 @@ namespace ScriptCanvas //! returns a pair of with the supplied id //! The variable datum pointer is non-null if the variable has been found virtual GraphVariable* FindVariableById(const VariableId& variableId) = 0; - - virtual AZ::Data::AssetType GetAssetType() const = 0; - }; using GraphRequestBus = AZ::EBus; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.cpp index 3d76883adc..8b8dfdc3fc 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.cpp @@ -493,14 +493,6 @@ namespace ScriptCanvas return m_sortPriority; } - bool GraphVariable::IsInFunction() const - { - AZ::Data::AssetType assetType = AZ::Data::AssetType::CreateNull(); - ScriptCanvas::GraphRequestBus::EventResult(assetType, m_scriptCanvasId, &ScriptCanvas::GraphRequests::GetAssetType); - - return assetType == azrtti_typeid(); - } - AZ::u32 GraphVariable::OnInitialValueSourceChanged() { VariableNotificationBus::Event(GetGraphScopedId(), &VariableNotifications::OnVariableInitialValueSourceChanged); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.h index dbc0a814c6..e7829ca6c1 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.h @@ -194,9 +194,7 @@ namespace ScriptCanvas choices.emplace_back(AZStd::make_pair(static_cast(VariableFlags::Scope::Function), s_ScopeNames[1])); return choices; } - - bool IsInFunction() const; - + void OnScopeTypedChanged(); AZ::u32 OnInitialValueSourceChanged(); void OnSortPriorityChanged(); From 837e9f6105d495eb04156e0cb1b143264b1d576d Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Mon, 8 Nov 2021 10:00:45 -0800 Subject: [PATCH 007/128] source save asset-free WIP Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Assets/ScriptCanvasAssetHandler.cpp | 1 + .../Assets/ScriptCanvasFileHandling.cpp | 60 +++++ .../Code/Editor/Components/EditorGraph.cpp | 5 + .../Assets/ScriptCanvasFileHandling.h | 6 +- .../ScriptCanvas/Components/EditorGraph.h | 2 + .../Code/Editor/View/Windows/MainWindow.cpp | 230 ++++++++---------- .../Code/Editor/View/Windows/MainWindow.h | 27 +- .../Windows/Tools/UpgradeTool/FileSaver.cpp | 86 ++++++- .../Windows/Tools/UpgradeTool/FileSaver.h | 2 + 9 files changed, 269 insertions(+), 150 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHandler.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHandler.cpp index bac1f770cb..896d285054 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHandler.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHandler.cpp @@ -186,6 +186,7 @@ namespace ScriptCanvasEditor , AZ::IO::GenericStream* stream , [[maybe_unused]] AZ::DataStream::StreamType streamType) { + // #sc_editor_asset delete usage of this, and route to ScriptCanvasEditor::SaveToStream namespace JSRU = AZ::JsonSerializationUtils; using namespace ScriptCanvas; diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp index 42dcf81a8d..9e385443f2 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp @@ -139,4 +139,64 @@ namespace ScriptCanvasEditor return AZ::Success(ScriptCanvasEditor::SourceHandle(scriptCanvasData, {}, path)); } + + AZ::Outcome SaveToStream(const SourceHandle& source, AZ::IO::GenericStream& stream) + { + namespace JSRU = AZ::JsonSerializationUtils; + + if (!source) + { + 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 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.get(), stream, nullptr, &settings); + if (!saveOutcome.IsSuccess()) + { + return AZ::Failure(AZStd::string("JSON serialization failed to save source: %s", saveOutcome.GetError().c_str())); + } + + return AZ::Success(); + } } diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp index 770d56860f..4f78c8e1b1 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp @@ -1067,6 +1067,11 @@ namespace ScriptCanvasEditor m_owner = &owner; } + ScriptCanvas::DataPtr Graph::GetOwnership() const + { + return ScriptCanvas::DataPtr(const_cast(this)->m_owner); + } + bool Graph::CreateConnection(const GraphCanvas::ConnectionId& connectionId, const GraphCanvas::Endpoint& sourcePoint, const GraphCanvas::Endpoint& targetPoint) { if (!sourcePoint.IsValid() || !targetPoint.IsValid()) diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h index 154ff5f2b0..c88a7df28b 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h @@ -26,10 +26,12 @@ namespace ScriptCanvas namespace ScriptCanvasEditor { - AZ::Outcome LoadFromFile(AZStd::string_view path); + AZ::Outcome LoadFromFile(AZStd::string_view path); AZ::Outcome LoadDataFromJson ( ScriptCanvas::ScriptCanvasData& dataTarget , AZStd::string_view source , AZ::SerializeContext& serializeContext); - } + + AZ::Outcome SaveToStream(const SourceHandle& source, AZ::IO::GenericStream& stream); +} diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h index 526c929664..05619caa30 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h @@ -309,6 +309,7 @@ namespace ScriptCanvasEditor const GraphStatisticsHelper& GetNodeUsageStatistics() const; void MarkOwnership(ScriptCanvas::ScriptCanvasData& owner); + ScriptCanvas::DataPtr GetOwnership() const; // Finds and returns all nodes within the graph that are of the specified type template @@ -393,6 +394,7 @@ namespace ScriptCanvasEditor bool m_saveFormatConverted = true; ScriptCanvasEditor::SourceHandle m_assetId; + // #sc_editor_asset temporary step in cleaning up the graph / asset class structure. This reference is deliberately weak. ScriptCanvas::ScriptCanvasData* m_owner; }; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index fe2d451e75..aede7ff9a1 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -1721,17 +1721,18 @@ namespace ScriptCanvasEditor // return AZ::Success(outTabIndex); } - bool MainWindow::OnFileSave(const Callbacks::OnSave& saveCB) + bool MainWindow::OnFileSave() { - return SaveAssetAsImpl(m_activeGraph, saveCB); + return SaveAssetImpl(m_activeGraph, Save::InPlace); } - bool MainWindow::OnFileSaveAs(const Callbacks::OnSave& saveCB) + bool MainWindow::OnFileSaveAs() { - return SaveAssetAsImpl(m_activeGraph, saveCB); + return SaveAssetImpl(m_activeGraph, Save::As); } - bool MainWindow::SaveAssetImpl(const ScriptCanvasEditor::SourceHandle& assetId, const Callbacks::OnSave& saveCB) + /* + bool MainWindow::SaveAssetImpl_OLD(const ScriptCanvasEditor::SourceHandle& assetId, const Callbacks::OnSave& saveCB) { if (!assetId.IsValid()) { @@ -1746,7 +1747,7 @@ namespace ScriptCanvasEditor if (fileState == Tracker::ScriptCanvasFileState::NEW) { - saveSuccessful = SaveAssetAsImpl(assetId, saveCB); + saveSuccessful = SaveAssetImpl(assetId, saveCB); } else if (fileState == Tracker::ScriptCanvasFileState::MODIFIED || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED) @@ -1757,8 +1758,16 @@ namespace ScriptCanvasEditor return saveSuccessful; } + */ - bool MainWindow::SaveAssetAsImpl(const ScriptCanvasEditor::SourceHandle& inMemoryAssetId, const Callbacks::OnSave& saveCB) + + // 1. SaveAssetImpl + // 2. SaveAs + // // 3. OnSaveCallback + // SaveAsEnd + // SaveAssetImpl end + + bool MainWindow::SaveAssetImpl(const ScriptCanvasEditor::SourceHandle& inMemoryAssetId, Save /*save*/) { if (!inMemoryAssetId.IsValid()) { @@ -1801,11 +1810,12 @@ namespace ScriptCanvasEditor AZ::IO::FileIOBase::GetInstance()->ResolvePath("@engroot@", assetRootChar.data(), assetRootChar.size()); assetRoot = assetRootChar.data(); - /* if (!AZ::StringFunc::StartsWith(filePath, assetRoot)) - { - QMessageBox::information(this, "Unable to Save", AZStd::string::format("You must select a path within the current project\n\n%s", assetRoot.c_str()).c_str()); - } - else*/ if (AzFramework::StringFunc::Path::GetFileName(filePath.c_str(), fileName)) +// if (!AZ::StringFunc::StartsWith(filePath, assetRoot)) +// { +// QMessageBox::information(this, "Unable to Save", AZStd::string::format("You must select a path within the current project\n\n%s", assetRoot.c_str()).c_str()); +// } +// else +if (AzFramework::StringFunc::Path::GetFileName(filePath.c_str(), fileName)) { isValidFileName = !(fileName.empty()); } @@ -1831,7 +1841,7 @@ namespace ScriptCanvasEditor return false; } - SaveAs(internalStringFile, inMemoryAssetId, saveCB); + SaveAs(internalStringFile, inMemoryAssetId); m_newlySavedFile = internalStringFile; @@ -1840,103 +1850,95 @@ namespace ScriptCanvasEditor return true; } - return false; } + - void MainWindow::OnSaveCallback(bool /*saveSuccess*/, AZ::Data::AssetPtr /*fileAsset*/, ScriptCanvasEditor::SourceHandle /*previousFileAssetId*/) + void MainWindow::OnSaveCallback(bool saveSuccess, ScriptCanvasEditor::SourceHandle memoryAsset) { - // #sc_editor_asset yikes...just save the thing...move to ::SaveAsset maybe - - /* - ScriptCanvasMemoryAsset::pointer memoryAsset; - AZStd::string tabName = m_tabBar->tabText(m_tabBar->currentIndex()).toUtf8().data(); - - int saveTabIndex = m_tabBar->currentIndex(); + int saveTabIndex = m_tabBar->FindTab(memoryAsset); + AZStd::string tabName = saveTabIndex >= 0 ? m_tabBar->tabText(saveTabIndex).toUtf8().data() : ""; if (saveSuccess) { - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, fileAsset->GetId()); - AZ_Assert(memoryAsset, "At this point we must have a MemoryAsset"); - + // #sc_editor_asset find a tab with the same path name and close non focused old ones with the same name // Update the editor with the new information about this asset. - const ScriptCanvasEditor::SourceHandle& fileAssetId = memoryAsset->GetFileAssetId(); - - saveTabIndex = m_tabBar->FindTab(fileAssetId); - + const ScriptCanvasEditor::SourceHandle& fileAssetId = memoryAsset; // We've saved as over a new graph, so we need to close the old one. if (saveTabIndex != m_tabBar->currentIndex()) { // Invalidate the file asset id so we don't delete trigger the asset flow. - m_tabBar->setTabData(saveTabIndex, QVariant::fromValue(GraphTabMetaData)); - + m_tabBar->setTabData(saveTabIndex, QVariant::fromValue(Widget::GraphTabMetadata())); m_tabBar->CloseTab(saveTabIndex); saveTabIndex = -1; } + // #sc_editor_asset clean up these actions as well, save and close, save as and close, just save, etc if (saveTabIndex < 0) { // This asset had not been saved yet, we will need to use the in memory asset Id to get the index. - saveTabIndex = m_tabBar->FindTab(memoryAsset->GetId()); + // saveTabIndex = m_tabBar->FindTab(memoryAsset->GetId()); if (saveTabIndex < 0) { // Finally, we may have Saved-As and we need the previous file asset Id to find the tab - saveTabIndex = m_tabBar->FindTab(previousFileAssetId); + //saveTabIndex = m_tabBar->FindTab(previousFileAssetId); } } - AzFramework::StringFunc::Path::GetFileName(memoryAsset->GetAbsolutePath().c_str(), tabName); + AzFramework::StringFunc::Path::GetFileName(memoryAsset.Path().c_str(), tabName); // Update the tab's assetId to the file asset Id (necessary when saving a new asset) - // used to be configure tab...sets the name and file state - m_tabBar->ConfigureTab(saveTabIndex, fileAssetId, tabName); + // #sc_editor_asset used to be configure tab...sets the name and file state + // m_tabBar->ConfigureTab(saveTabIndex, fileAssetId, tabName); - GeneralAssetNotificationBus::Event(memoryAsset->GetId(), &GeneralAssetNotifications::OnAssetVisualized); - - auto requestorIter = m_assetCreationRequests.find(fileAsset->GetId()); - - if (requestorIter != m_assetCreationRequests.end()) - { - auto editorComponents = AZ::EntityUtils::FindDerivedComponents(requestorIter->second.first); - - if (editorComponents.empty()) - { - auto firstRequestBus = EditorScriptCanvasComponentRequestBus::FindFirstHandler(requestorIter->second.first); - - if (firstRequestBus) - { - firstRequestBus->SetAssetId(fileAsset->GetId()); - } - } - else - { - for (auto editorComponent : editorComponents) - { - if (editorComponent->GetId() == requestorIter->second.second) - { - editorComponent->SetAssetId(fileAsset->GetId()); - break; - } - } - } - - m_assetCreationRequests.erase(requestorIter); - } +// GeneralAssetNotificationBus::Event(memoryAsset, &GeneralAssetNotifications::OnAssetVisualized); +// +// auto requestorIter = m_assetCreationRequests.find(fileAsset->GetId()); +// +// if (requestorIter != m_assetCreationRequests.end()) +// { +// auto editorComponents = AZ::EntityUtils::FindDerivedComponents(requestorIter->second.first); +// +// if (editorComponents.empty()) +// { +// auto firstRequestBus = EditorScriptCanvasComponentRequestBus::FindFirstHandler(requestorIter->second.first); +// +// if (firstRequestBus) +// { +// firstRequestBus->SetAssetId(fileAsset->GetId()); +// } +// } +// else +// { +// for (auto editorComponent : editorComponents) +// { +// if (editorComponent->GetId() == requestorIter->second.second) +// { +// editorComponent->SetAssetId(fileAsset->GetId()); +// break; +// } +// } +// } +// +// m_assetCreationRequests.erase(requestorIter); +// } // Soft switch the asset id here. We'll do a double scene switch down below to actually switch the active assetid m_activeGraph = fileAssetId; } else { + // #sc_editor_asset this seems to remove the unsaved indicator even on failure + // Use the previous memory asset to find what we had setup as our display - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeGraph); + // AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeGraph); // Drop off our file modifier status for our display name when we fail to save. - if (tabName.at(tabName.size() -1) == '*') - { - tabName = tabName.substr(0, tabName.size() - 2); - } +// if (tabName.at(tabName.size() -1) == '*') +// { +// tabName = tabName.substr(0, tabName.size() - 2); +// } } if (m_tabBar->currentIndex() != saveTabIndex) @@ -1959,7 +1961,7 @@ namespace ScriptCanvasEditor const bool displayAsNotification = true; RunGraphValidation(displayAsNotification); - // This is called during saving, so the is scaving flag is always true Need to update the state after this callback is complete. So schedule for next system tick. + // This is called during saving, so the is saving flag is always true Need to update the state after this callback is complete. So schedule for next system tick. AddSystemTickAction(SystemTickActionFlag::UpdateSaveMenuState); if (m_closeCurrentGraphAfterSave) @@ -1972,69 +1974,27 @@ namespace ScriptCanvasEditor EnableAssetView(memoryAsset); UnblockCloseRequests(); - */ } - bool MainWindow::ActivateAndSaveAsset(const ScriptCanvasEditor::SourceHandle& unsavedAssetId, const Callbacks::OnSave& saveCB) + bool MainWindow::ActivateAndSaveAsset(const ScriptCanvasEditor::SourceHandle& unsavedAssetId) { SetActiveAsset(unsavedAssetId); - return OnFileSave(saveCB); + return OnFileSave(); } - void MainWindow::SaveAs(AZStd::string_view /*path*/, ScriptCanvasEditor::SourceHandle /*inMemoryAssetId*/, const Callbacks::OnSave& /*onSave*/) + void MainWindow::SaveAs(AZStd::string_view path, ScriptCanvasEditor::SourceHandle inMemoryAssetId) { - /* - PrepareAssetForSave(inMemoryAssetId); + AZ_TracePrintf("ScriptCanvas", "Saving %s to %.*s", inMemoryAssetId.Path().c_str(), path.data()); + // #sc_editor_asset maybe delete this + + DisableAssetView(inMemoryAssetId); - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, inMemoryAssetId); + // use the file saver, make new version that works on source handle and not asset + // then...connect the failed and succeed versions + // to OnSaveCallBack - // Disable the current view if we are saving. - if (memoryAsset) - { - DisableAssetView(memoryAsset); - } - - auto onSaveCallback = [this, onSave](bool saveSuccess, AZ::Data::AssetPtr asset, ScriptCanvasEditor::SourceHandle previousAssetId) - { - OnSaveCallback(saveSuccess, asset, previousAssetId); - if (onSave) - { - AZStd::invoke(onSave, saveSuccess, asset, previousAssetId); - } - }; - - AZ::Data::AssetStreamInfo streamInfo; - streamInfo.m_streamFlags = AZ::IO::OpenMode::ModeWrite; - streamInfo.m_streamName = m_saveAsPath; - - if (!streamInfo.IsValid()) - { - return; - } - - bool sourceControlActive = false; - AzToolsFramework::SourceControlConnectionRequestBus::BroadcastResult(sourceControlActive, &AzToolsFramework::SourceControlConnectionRequests::IsActive); - // If Source Control is active then use it to check out the file before saving otherwise query the file info and save only if the file is not read-only - if (sourceControlActive) - { - AzToolsFramework::SourceControlCommandBus::Broadcast(&AzToolsFramework::SourceControlCommandBus::Events::RequestEdit, - streamInfo.m_streamName.c_str(), - true, - [this, streamInfo, onSaveCallback](bool success, AzToolsFramework::SourceControlFileInfo info) { FinalizeAssetSave(success, info, streamInfo, onSaveCallback); } - ); - } - else - { - AzToolsFramework::SourceControlCommandBus::Broadcast(&AzToolsFramework::SourceControlCommandBus::Events::GetFileInfo, - streamInfo.m_streamName.c_str(), - [this, streamInfo, onSaveCallback](bool success, AzToolsFramework::SourceControlFileInfo info) { FinalizeAssetSave(success, info, streamInfo, onSaveCallback); } - ); - } - - UpdateSaveState(); - BlockCloseRequests(); - */ + UpdateSaveState(); + BlockCloseRequests(); } void MainWindow::OnFileOpen() @@ -2800,7 +2760,7 @@ namespace ScriptCanvasEditor // // if (fileState == Tracker::ScriptCanvasFileState::NEW) // { -// SaveAssetAsImpl(fileAssetId, saveCB); +// SaveAssetImpl(fileAssetId, saveCB); // } // else // { @@ -2820,7 +2780,7 @@ namespace ScriptCanvasEditor if (tabdata.isValid()) { auto assetId = tabdata.value(); - SaveAssetAsImpl(assetId.m_assetId, nullptr); + SaveAssetImpl(assetId.m_assetId, Save::InPlace); } } @@ -4759,11 +4719,11 @@ namespace ScriptCanvasEditor //connect(m_unitTestDockWidget, &QDockWidget::visibilityChanged, this, &MainWindow::OnViewVisibilityChanged); } - void MainWindow::DisableAssetView(ScriptCanvasMemoryAsset::pointer memoryAsset) + void MainWindow::DisableAssetView(const ScriptCanvasEditor::SourceHandle& memoryAssetId) { - if (memoryAsset->GetView()) + if (auto view = m_tabBar->ModTabView(m_tabBar->FindTab(memoryAssetId))) { - memoryAsset->GetView()->DisableView(); + view->DisableView(); } m_tabBar->setEnabled(false); @@ -4783,11 +4743,11 @@ namespace ScriptCanvasEditor m_autoSaveTimer.stop(); } - void MainWindow::EnableAssetView(ScriptCanvasMemoryAsset::pointer memoryAsset) + void MainWindow::EnableAssetView(const ScriptCanvasEditor::SourceHandle& memoryAssetId) { - if (memoryAsset->GetView()) + if (auto view = m_tabBar->ModTabView(m_tabBar->FindTab(memoryAssetId))) { - memoryAsset->GetView()->EnableView(); + view->EnableView(); } m_tabBar->setEnabled(true); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h index 0a687e0011..0f126456c0 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h @@ -325,12 +325,17 @@ namespace ScriptCanvasEditor // File menu void OnFileNew(); - bool OnFileSave(const Callbacks::OnSave& saveCB); - bool OnFileSaveAs(const Callbacks::OnSave& saveCB); - bool OnFileSaveCaller(){return OnFileSave(nullptr);}; - bool OnFileSaveAsCaller(){return OnFileSaveAs(nullptr);}; - bool SaveAssetImpl(const ScriptCanvasEditor::SourceHandle& assetId, const Callbacks::OnSave& saveCB); - bool SaveAssetAsImpl(const ScriptCanvasEditor::SourceHandle& assetId, const Callbacks::OnSave& saveCB); + bool OnFileSave(); + bool OnFileSaveAs(); + bool OnFileSaveCaller(){return OnFileSave();}; + bool OnFileSaveAsCaller(){return OnFileSaveAs();}; + bool SaveAssetImpl_OLD(const ScriptCanvasEditor::SourceHandle& assetId, const Callbacks::OnSave& saveCB); + enum class Save + { + InPlace, + As + }; + bool SaveAssetImpl(const ScriptCanvasEditor::SourceHandle& assetId, Save save); void OnFileOpen(); // Edit menu @@ -554,9 +559,9 @@ namespace ScriptCanvasEditor void closeEvent(QCloseEvent *event) override; UnsavedChangesOptions ShowSaveDialog(const QString& filename); - bool ActivateAndSaveAsset(const ScriptCanvasEditor::SourceHandle& unsavedAssetId, const Callbacks::OnSave& onSave); + bool ActivateAndSaveAsset(const ScriptCanvasEditor::SourceHandle& unsavedAssetId); - void SaveAs(AZStd::string_view path, ScriptCanvasEditor::SourceHandle assetId, const Callbacks::OnSave& onSave); + void SaveAs(AZStd::string_view path, ScriptCanvasEditor::SourceHandle assetId); void OpenFile(const char* fullPath); void CreateMenus(); @@ -667,8 +672,8 @@ namespace ScriptCanvasEditor } } - void DisableAssetView(ScriptCanvasMemoryAsset::pointer memoryAsset); - void EnableAssetView(ScriptCanvasMemoryAsset::pointer memoryAsset); + void DisableAssetView(const ScriptCanvasEditor::SourceHandle& memoryAssetId); + void EnableAssetView(const ScriptCanvasEditor::SourceHandle& memoryAssetId); QWidget* m_host = nullptr; @@ -783,6 +788,6 @@ namespace ScriptCanvasEditor //! this object manages the Save/Restore operations Workspace* m_workspace; - void OnSaveCallback(bool saveSuccess, AZ::Data::AssetPtr, ScriptCanvasEditor::SourceHandle previousFileAssetId); + void OnSaveCallback(bool saveSuccess, ScriptCanvasEditor::SourceHandle previousFileAssetId); }; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp index f067feeca4..82a046b0fc 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp @@ -186,12 +186,73 @@ namespace ScriptCanvasEditor }); } + void FileSaver::OnSourceFileReleased(const SourceHandle& source) + { + AZStd::string tmpFileName; + // here we are saving the graph to a temp file instead of the original file and then copying the temp file to the original file. + // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. Temp files are ignored by AP. + if (!AZ::IO::CreateTempFileName(source.Path().c_str(), tmpFileName)) + { + FileSaveResult result; + result.fileSaveError = "Failure to create temporary file name"; + m_onComplete(result); + return; + } + + bool tempSavedSucceeded = false; + AZ::IO::FileIOStream fileStream(tmpFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); + if (fileStream.IsOpen()) + { + if (asset.GetType() == azrtti_typeid()) + { + ScriptCanvasEditor::ScriptCanvasAssetHandler handler; + tempSavedSucceeded = handler.SaveAssetData(asset, &fileStream); + } + + fileStream.Close(); + } + + if (!tempSavedSucceeded) + { + FileSaveResult result; + result.fileSaveError = "Save asset data to temporary file failed"; + m_onComplete(result); + return; + } + + AzToolsFramework::SourceControlCommandBus::Broadcast + ( &AzToolsFramework::SourceControlCommandBus::Events::RequestEdit + , fullPath.c_str() + , true + , [this, fullPath, tmpFileName]([[maybe_unused]] bool success, const AzToolsFramework::SourceControlFileInfo& info) + { + constexpr const size_t k_maxAttemps = 10; + + if (!info.IsReadOnly()) + { + PerformMove(tmpFileName, fullPath, k_maxAttemps); + } + else if (m_onReadOnlyFile && m_onReadOnlyFile()) + { + AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); + PerformMove(tmpFileName, fullPath, k_maxAttemps); + } + else + { + FileSaveResult result; + result.fileSaveError = "Source file was and remained read-only"; + result.tempFileRemovalError = RemoveTempFile(tmpFileName); + m_onComplete(result); + } + }); + } + AZStd::string FileSaver::RemoveTempFile(AZStd::string_view tempFile) { AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); if (!fileIO) { - return "GraphUpgradeComplete: No FileIO instance"; + return "No FileIO instance"; } if (fileIO->Exists(tempFile.data()) && !fileIO->Remove(tempFile.data())) @@ -202,13 +263,34 @@ namespace ScriptCanvasEditor return ""; } + void FileSaver::Save(const SourceHandle& source) + { + if (source.Path().empty()) + { + FileSaveResult result; + result.fileSaveError = "No save location specified"; + m_onComplete(result); + } + else + { + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(source.Path()); + streamer->SetRequestCompleteCallback(flushRequest, [this, source]([[maybe_unused]] AZ::IO::FileRequestHandle request) + { + this->OnSourceFileReleased(source); + }); + streamer->QueueRequest(flushRequest); + } + } + void FileSaver::Save(AZ::Data::Asset asset) { + // #sc_editor_asset fix this path from the version explorer AZStd::string relativePath, fullPath; AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); bool fullPathFound = false; AzToolsFramework::AssetSystemRequestBus::BroadcastResult - (fullPathFound + ( fullPathFound , &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath , relativePath, fullPath); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h index dd333927ed..6ec0daa2b7 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h @@ -30,11 +30,13 @@ namespace ScriptCanvasEditor , AZStd::function onComplete); void Save(AZ::Data::Asset asset); + void Save(const SourceHandle& source); private: AZStd::function m_onComplete; AZStd::function m_onReadOnlyFile; + void OnSourceFileReleased(const SourceHandle& source); void OnSourceFileReleased(AZ::Data::Asset asset); void PerformMove From a334ce09b41abca514a3da3169f45681f74d822b Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Mon, 8 Nov 2021 13:58:48 -0800 Subject: [PATCH 008/128] source save in place first pass Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Assets/ScriptCanvasFileHandling.cpp | 4 +- .../Code/Editor/Components/EditorGraph.cpp | 4 +- .../ScriptCanvas/Components/EditorGraph.h | 2 +- .../Code/Editor/View/Windows/MainWindow.cpp | 139 +++++++++--------- .../Code/Editor/View/Windows/MainWindow.h | 5 +- .../Windows/Tools/UpgradeTool/FileSaver.cpp | 31 ++-- .../Windows/Tools/UpgradeTool/FileSaver.h | 2 + .../Windows/Tools/UpgradeTool/Modifier.cpp | 2 +- .../Code/Include/ScriptCanvas/Core/Core.cpp | 1 - 9 files changed, 101 insertions(+), 89 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp index 9e385443f2..4af7ff247e 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp @@ -173,7 +173,7 @@ namespace ScriptCanvasEditor } auto saveTarget = graphData->ModGraph(); - if (saveTarget || !saveTarget->GetGraphData()) + if (!saveTarget || !saveTarget->GetGraphData()) { return AZ::Failure(AZStd::string("source save container failed to return graph data")); } @@ -191,7 +191,7 @@ namespace ScriptCanvasEditor listener->OnSerialize(); } - auto saveOutcome = JSRU::SaveObjectToStream(graphData.get(), stream, nullptr, &settings); + auto saveOutcome = JSRU::SaveObjectToStream(graphData, stream, nullptr, &settings); if (!saveOutcome.IsSuccess()) { return AZ::Failure(AZStd::string("JSON serialization failed to save source: %s", saveOutcome.GetError().c_str())); diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp index 4f78c8e1b1..2c9dbe0fd6 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp @@ -1067,9 +1067,9 @@ namespace ScriptCanvasEditor m_owner = &owner; } - ScriptCanvas::DataPtr Graph::GetOwnership() const + ScriptCanvas::ScriptCanvasData* Graph::GetOwnership() const { - return ScriptCanvas::DataPtr(const_cast(this)->m_owner); + return const_cast(this)->m_owner; } bool Graph::CreateConnection(const GraphCanvas::ConnectionId& connectionId, const GraphCanvas::Endpoint& sourcePoint, const GraphCanvas::Endpoint& targetPoint) diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h index 05619caa30..b5269cc45d 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h @@ -309,7 +309,7 @@ namespace ScriptCanvasEditor const GraphStatisticsHelper& GetNodeUsageStatistics() const; void MarkOwnership(ScriptCanvas::ScriptCanvasData& owner); - ScriptCanvas::DataPtr GetOwnership() const; + ScriptCanvas::ScriptCanvasData* GetOwnership() const; // Finds and returns all nodes within the graph that are of the specified type template diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index aede7ff9a1..deb75ff78c 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -1403,48 +1403,28 @@ namespace ScriptCanvasEditor void MainWindow::GetSuggestedFullFilenameToSaveAs(const ScriptCanvasEditor::SourceHandle& /*assetId*/, AZStd::string& /*filePath*/, AZStd::string& /*fileFilter*/) { // #sc_editor_asset - /* - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); - - AZStd::string assetPath; - if (memoryAsset) - { - assetPath = memoryAsset->GetAbsolutePath(); - - AZ::Data::AssetType assetType = memoryAsset->GetAsset().GetType(); - - ScriptCanvasAssetHandler* assetHandler; - AssetTrackerRequestBus::BroadcastResult(assetHandler, &AssetTrackerRequests::GetAssetHandlerForType, assetType); - AZ_Assert(assetHandler, "Asset type must have a valid asset handler"); - - AZ::EBusAggregateResults results; - AssetRegistryRequestBus::BroadcastResult(results, &AssetRegistryRequests::GetAssetDescription, assetType); - - ScriptCanvas::AssetDescription* description = nullptr; - for (auto item : results.values) - { - if (item->GetAssetType() == assetType) - { - description = item; - break; - } - } - - AZ_Assert(description, "Asset type must have a valid description"); - - fileFilter = description->GetFileFilterImpl(); - - AZStd::string tabName; - AssetTrackerRequestBus::BroadcastResult(tabName, &AssetTrackerRequests::GetTabName, assetId); - - assetPath = AZStd::string::format("%s/%s%s", description->GetSuggestedSavePathImpl(), tabName.c_str(), description->GetExtensionImpl()); - } - - AZStd::array resolvedPath; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(assetPath.data(), resolvedPath.data(), resolvedPath.size()); - filePath = resolvedPath.data(); - */ +// +// ScriptCanvasMemoryAsset::pointer memoryAsset; +// AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); +// +// AZStd::string assetPath; +// if (memoryAsset) +// { +// assetPath = memoryAsset->GetAbsolutePath(); +// fileFilter = ScriptCanvasAssetDescription().GetFileFilterImpl(); +// +// AZStd::string tabName; +// AssetTrackerRequestBus::BroadcastResult(tabName, &AssetTrackerRequests::GetTabName, assetId); +// +// assetPath = AZStd::string::format("%s/%s%s" +// , ScriptCanvasAssetDescription().GetSuggestedSavePathImpl() +// , tabName.c_str() +// , ScriptCanvasAssetDescription().GetExtensionImpl()); +// } +// +// AZStd::array resolvedPath; +// AZ::IO::FileIOBase::GetInstance()->ResolvePath(assetPath.data(), resolvedPath.data(), resolvedPath.size()); +// filePath = resolvedPath.data(); } void MainWindow::OpenFile(const char* fullPath) @@ -1767,7 +1747,7 @@ namespace ScriptCanvasEditor // SaveAsEnd // SaveAssetImpl end - bool MainWindow::SaveAssetImpl(const ScriptCanvasEditor::SourceHandle& inMemoryAssetId, Save /*save*/) + bool MainWindow::SaveAssetImpl(const ScriptCanvasEditor::SourceHandle& inMemoryAssetId, Save save) { if (!inMemoryAssetId.IsValid()) { @@ -1783,15 +1763,23 @@ namespace ScriptCanvasEditor AZStd::string suggestedFilename; AZStd::string suggestedFileFilter; - GetSuggestedFullFilenameToSaveAs(inMemoryAssetId, suggestedFilename, suggestedFileFilter); - - EnsureSaveDestinationDirectory(suggestedFilename); - - QString filter = suggestedFileFilter.c_str(); - QString selectedFile; - bool isValidFileName = false; + if (save == Save::InPlace) + { + isValidFileName = true; + suggestedFileFilter = ScriptCanvasAssetDescription().GetExtensionImpl(); + suggestedFilename = inMemoryAssetId.Path(); + } + else + { + GetSuggestedFullFilenameToSaveAs(inMemoryAssetId, suggestedFilename, suggestedFileFilter); + } + + EnsureSaveDestinationDirectory(suggestedFilename); + QString filter = suggestedFileFilter.c_str(); + QString selectedFile = suggestedFilename.c_str(); + while (!isValidFileName) { selectedFile = AzQtComponents::FileDialog::GetSaveFileName(this, tr("Save As..."), suggestedFilename.data(), filter); @@ -1815,7 +1803,7 @@ namespace ScriptCanvasEditor // QMessageBox::information(this, "Unable to Save", AZStd::string::format("You must select a path within the current project\n\n%s", assetRoot.c_str()).c_str()); // } // else -if (AzFramework::StringFunc::Path::GetFileName(filePath.c_str(), fileName)) + if (AzFramework::StringFunc::Path::GetFileName(filePath.c_str(), fileName)) { isValidFileName = !(fileName.empty()); } @@ -1823,7 +1811,6 @@ if (AzFramework::StringFunc::Path::GetFileName(filePath.c_str(), fileName)) { QMessageBox::information(this, "Unable to Save", "File name cannot be empty"); } - } else { @@ -1842,20 +1829,20 @@ if (AzFramework::StringFunc::Path::GetFileName(filePath.c_str(), fileName)) } SaveAs(internalStringFile, inMemoryAssetId); - m_newlySavedFile = internalStringFile; - // Forcing the file add here, since we are creating a new file AddRecentFile(m_newlySavedFile.c_str()); - return true; } + return false; } - void MainWindow::OnSaveCallback(bool saveSuccess, ScriptCanvasEditor::SourceHandle memoryAsset) + void MainWindow::OnSaveCallBack(const VersionExplorer::FileSaveResult& result) { + const bool saveSuccess = result.fileSaveError.empty(); + auto memoryAsset = m_fileSaver->GetSource(); int saveTabIndex = m_tabBar->FindTab(memoryAsset); AZStd::string tabName = saveTabIndex >= 0 ? m_tabBar->tabText(saveTabIndex).toUtf8().data() : ""; @@ -1864,8 +1851,9 @@ if (AzFramework::StringFunc::Path::GetFileName(filePath.c_str(), fileName)) // #sc_editor_asset find a tab with the same path name and close non focused old ones with the same name // Update the editor with the new information about this asset. const ScriptCanvasEditor::SourceHandle& fileAssetId = memoryAsset; + int currentTabIndex = m_tabBar->currentIndex(); // We've saved as over a new graph, so we need to close the old one. - if (saveTabIndex != m_tabBar->currentIndex()) + if (saveTabIndex != currentTabIndex) { // Invalidate the file asset id so we don't delete trigger the asset flow. m_tabBar->setTabData(saveTabIndex, QVariant::fromValue(Widget::GraphTabMetadata())); @@ -1926,6 +1914,14 @@ if (AzFramework::StringFunc::Path::GetFileName(filePath.c_str(), fileName)) // Soft switch the asset id here. We'll do a double scene switch down below to actually switch the active assetid m_activeGraph = fileAssetId; + + if (tabName.at(tabName.size() - 1) == '*') + { + tabName = tabName.substr(0, tabName.size() - 2); + } + + m_tabBar->UpdateFileState(fileAssetId, Tracker::ScriptCanvasFileState::UNMODIFIED); + m_tabBar->SetTabText(saveTabIndex, tabName.c_str()); } else { @@ -1947,11 +1943,11 @@ if (AzFramework::StringFunc::Path::GetFileName(filePath.c_str(), fileName)) } else { - // Something weird happens with our saving. Where we are relying on these scene changes being called. - ScriptCanvasEditor::SourceHandle previousAssetId = m_activeGraph; - - OnChangeActiveGraphTab(ScriptCanvasEditor::SourceHandle()); - OnChangeActiveGraphTab(previousAssetId); +// // Something weird happens with our saving. Where we are relying on these scene changes being called. +// ScriptCanvasEditor::SourceHandle previousAssetId = m_activeGraph; +// +// OnChangeActiveGraphTab(ScriptCanvasEditor::SourceHandle()); +// OnChangeActiveGraphTab(previousAssetId); } UpdateAssignToSelectionState(); @@ -1964,7 +1960,7 @@ if (AzFramework::StringFunc::Path::GetFileName(filePath.c_str(), fileName)) // This is called during saving, so the is saving flag is always true Need to update the state after this callback is complete. So schedule for next system tick. AddSystemTickAction(SystemTickActionFlag::UpdateSaveMenuState); - if (m_closeCurrentGraphAfterSave) + if (saveSuccess && m_closeCurrentGraphAfterSave) { AddSystemTickAction(SystemTickActionFlag::CloseCurrentGraph); } @@ -1974,6 +1970,7 @@ if (AzFramework::StringFunc::Path::GetFileName(filePath.c_str(), fileName)) EnableAssetView(memoryAsset); UnblockCloseRequests(); + m_fileSaver.reset(); } bool MainWindow::ActivateAndSaveAsset(const ScriptCanvasEditor::SourceHandle& unsavedAssetId) @@ -1984,17 +1981,17 @@ if (AzFramework::StringFunc::Path::GetFileName(filePath.c_str(), fileName)) void MainWindow::SaveAs(AZStd::string_view path, ScriptCanvasEditor::SourceHandle inMemoryAssetId) { - AZ_TracePrintf("ScriptCanvas", "Saving %s to %.*s", inMemoryAssetId.Path().c_str(), path.data()); - // #sc_editor_asset maybe delete this - DisableAssetView(inMemoryAssetId); - // use the file saver, make new version that works on source handle and not asset - // then...connect the failed and succeed versions - // to OnSaveCallBack + m_fileSaver = AZStd::make_unique + ( nullptr + , [this](const VersionExplorer::FileSaveResult& fileSaveResult) { OnSaveCallBack(fileSaveResult); }); - UpdateSaveState(); - BlockCloseRequests(); + ScriptCanvasEditor::SourceHandle newLocation(inMemoryAssetId, {}, path); + m_fileSaver->Save(newLocation); + + UpdateSaveState(); + BlockCloseRequests(); } void MainWindow::OnFileOpen() diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h index 0f126456c0..6704c10fda 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h @@ -53,6 +53,7 @@ #include #include +#include #if SCRIPTCANVAS_EDITOR #include @@ -788,6 +789,8 @@ namespace ScriptCanvasEditor //! this object manages the Save/Restore operations Workspace* m_workspace; - void OnSaveCallback(bool saveSuccess, ScriptCanvasEditor::SourceHandle previousFileAssetId); + AZStd::unique_ptr m_fileSaver; + VersionExplorer::FileSaveResult m_fileSaveResult; + void OnSaveCallBack(const VersionExplorer::FileSaveResult& result); }; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp index 82a046b0fc..f36f72234b 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp @@ -15,6 +15,7 @@ #include #include #include +#include namespace FileSaverCpp { @@ -58,6 +59,11 @@ namespace ScriptCanvasEditor , m_onComplete(onComplete) {} + const SourceHandle& FileSaver::GetSource() const + { + return m_source; + } + void FileSaver::PerformMove ( AZStd::string tmpFileName , AZStd::string target @@ -179,7 +185,7 @@ namespace ScriptCanvasEditor else { FileSaveResult result; - result.fileSaveError = "Source file was and remained read-only"; + result.fileSaveError = "Source file is read-only"; result.tempFileRemovalError = RemoveTempFile(tmpFileName); m_onComplete(result); } @@ -188,10 +194,12 @@ namespace ScriptCanvasEditor void FileSaver::OnSourceFileReleased(const SourceHandle& source) { + AZStd::string fullPath = source.Path(); AZStd::string tmpFileName; // here we are saving the graph to a temp file instead of the original file and then copying the temp file to the original file. - // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. Temp files are ignored by AP. - if (!AZ::IO::CreateTempFileName(source.Path().c_str(), tmpFileName)) + // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. + // Temp files are ignored by AP. + if (!AZ::IO::CreateTempFileName(fullPath.c_str(), tmpFileName)) { FileSaveResult result; result.fileSaveError = "Failure to create temporary file name"; @@ -199,23 +207,24 @@ namespace ScriptCanvasEditor return; } - bool tempSavedSucceeded = false; + AZStd::string saveError; + AZ::IO::FileIOStream fileStream(tmpFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); if (fileStream.IsOpen()) { - if (asset.GetType() == azrtti_typeid()) + auto saveOutcome = ScriptCanvasEditor::SaveToStream(source, fileStream); + if (!saveOutcome.IsSuccess()) { - ScriptCanvasEditor::ScriptCanvasAssetHandler handler; - tempSavedSucceeded = handler.SaveAssetData(asset, &fileStream); + saveError = saveOutcome.TakeError(); } fileStream.Close(); } - if (!tempSavedSucceeded) + if (!saveError.empty()) { FileSaveResult result; - result.fileSaveError = "Save asset data to temporary file failed"; + result.fileSaveError = AZStd::string::format("Save asset data to temporary file failed: %s", saveError.c_str()); m_onComplete(result); return; } @@ -265,6 +274,8 @@ namespace ScriptCanvasEditor void FileSaver::Save(const SourceHandle& source) { + m_source = source; + if (source.Path().empty()) { FileSaveResult result; @@ -285,7 +296,7 @@ namespace ScriptCanvasEditor void FileSaver::Save(AZ::Data::Asset asset) { - // #sc_editor_asset fix this path from the version explorer + // #sc_editor_asset fix/remove this path that is used by the version explorer AZStd::string relativePath, fullPath; AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); bool fullPathFound = false; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h index 6ec0daa2b7..439db2d260 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h @@ -29,10 +29,12 @@ namespace ScriptCanvasEditor ( AZStd::function onReadOnlyFile , AZStd::function onComplete); + const SourceHandle& GetSource() const; void Save(AZ::Data::Asset asset); void Save(const SourceHandle& source); private: + SourceHandle m_source; AZStd::function m_onComplete; AZStd::function m_onReadOnlyFile; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp index f3da1ba309..0e4190b18d 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp @@ -259,7 +259,7 @@ namespace ScriptCanvasEditor m_modifyState = ModifyState::Saving; m_fileSaver = AZStd::make_unique ( m_config.onReadOnlyFile - , [this](const FileSaveResult& result) { OnFileSaveComplete(result); }); + , [this](const FileSaveResult& fileSaveResult) { OnFileSaveComplete(fileSaveResult); }); m_fileSaver->Save(result.asset); } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp index 15e2192ee8..064029eb03 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp @@ -13,7 +13,6 @@ #include #include #include -// #include #include "Core.h" #include "Attributes.h" From 98ecef2fd23650885fc1a36b6cdaf88939b03a10 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Mon, 8 Nov 2021 14:39:20 -0800 Subject: [PATCH 009/128] source file save-as Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Editor/View/Windows/MainWindow.cpp | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index deb75ff78c..b20fcb7e7a 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -1764,7 +1764,7 @@ namespace ScriptCanvasEditor AZStd::string suggestedFilename; AZStd::string suggestedFileFilter; bool isValidFileName = false; - + if (save == Save::InPlace) { isValidFileName = true; @@ -1773,7 +1773,17 @@ namespace ScriptCanvasEditor } else { - GetSuggestedFullFilenameToSaveAs(inMemoryAssetId, suggestedFilename, suggestedFileFilter); + // replaces GetSuggestedFullFilenameToSaveAs + suggestedFileFilter = ScriptCanvasAssetDescription().GetExtensionImpl(); + + if (inMemoryAssetId.Path().empty()) + { + suggestedFilename = ScriptCanvasAssetDescription().GetSuggestedSavePathImpl(); + } + else + { + suggestedFilename = inMemoryAssetId.Path(); + } } EnsureSaveDestinationDirectory(suggestedFilename); @@ -1788,7 +1798,14 @@ namespace ScriptCanvasEditor // So we want to break out. if (!selectedFile.isEmpty()) { + ScriptCanvasAssetDescription assetDescription; AZStd::string filePath = selectedFile.toUtf8().data(); + + if (!AZ::StringFunc::EndsWith(filePath, assetDescription.GetExtensionImpl(), false)) + { + filePath += assetDescription.GetExtensionImpl(); + } + AZStd::string fileName; // Verify that the path is within the project From e9a57380bb82045e5ebe66ed11b65009ae53b4b0 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Wed, 10 Nov 2021 12:14:07 -0800 Subject: [PATCH 010/128] Generic DOM: Add DomBackend abstraction and JSON support This change adds a `DomBackend` interface and a `DomBackendRegistry` for backend discovery (currently not hooked up to anything) alongside a JSON backend implementation. The JSON backend comes with a small suite of unit and performance tests. The unit tests validate generic DOM conversion to and from serialized JSON and rapidjson::Document objects (the support for which lives in `JsonSerializationUtils.h`). The performance tests show a throughput decrease compared to directly using the rapidjson serializer when mirroring our current pattern of copying strings from the serialized JSON representation, but with the coming in-memory store we have the opportunity to keep the buffer in memory and deserialize in-situ using rapidjson's API, which is consistently at least 100MiB/s faster on my machine (Ryzen Threadripper 3970X). The first parameter is the nested object complexity (N*N, objects with N keys comprised of arrays with N values) and the second parameter is the base size of the strings within each entry of this object. ``` ---------------------------------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations UserCounters... ---------------------------------------------------------------------------------------------------------------------- DomJsonBenchmark/DomDeserializeToDocumentInPlace/10/5 0.050 ms 0.050 ms 10000 bytes_per_second=355.816M/s DomJsonBenchmark/DomDeserializeToDocumentInPlace/10/50 0.057 ms 0.057 ms 11200 bytes_per_second=386.064M/s DomJsonBenchmark/DomDeserializeToDocumentInPlace/100/5 4.77 ms 4.88 ms 112 bytes_per_second=364.046M/s DomJsonBenchmark/DomDeserializeToDocumentInPlace/100/500 11.6 ms 11.7 ms 64 bytes_per_second=554.518M/s DomJsonBenchmark/DomDeserializeToDocumentWithCopies/10/5 0.084 ms 0.084 ms 7467 bytes_per_second=212.55M/s DomJsonBenchmark/DomDeserializeToDocumentWithCopies/10/50 0.099 ms 0.100 ms 6400 bytes_per_second=220.608M/s DomJsonBenchmark/DomDeserializeToDocumentWithCopies/100/5 8.22 ms 8.16 ms 90 bytes_per_second=217.847M/s DomJsonBenchmark/DomDeserializeToDocumentWithCopies/100/500 23.2 ms 22.9 ms 30 bytes_per_second=283.56M/s DomJsonBenchmark/JsonUtilsDeserializeToDocument/10/5 0.070 ms 0.070 ms 11200 bytes_per_second=255.049M/s DomJsonBenchmark/JsonUtilsDeserializeToDocument/10/50 0.086 ms 0.087 ms 8960 bytes_per_second=253.258M/s DomJsonBenchmark/JsonUtilsDeserializeToDocument/100/5 6.86 ms 6.84 ms 112 bytes_per_second=260.033M/s DomJsonBenchmark/JsonUtilsDeserializeToDocument/100/500 22.8 ms 22.9 ms 32 bytes_per_second=283.158M/s ``` For `AZ::DOM::Document`, the current plan is to offer helper methods that can load from a file path or string using a given backend that can take advantage of in-place parsing by internally storing the serialized buffer. Signed-off-by: Nicholas Van Sickle --- .../AzCore/DOM/Backends/JSON/JsonBackend.cpp | 37 + .../AzCore/DOM/Backends/JSON/JsonBackend.h | 27 + .../Backends/JSON/JsonSerializationUtils.cpp | 675 ++++++++++++++++++ .../Backends/JSON/JsonSerializationUtils.h | 60 ++ .../AzCore/AzCore/DOM/DomBackend.cpp | 77 ++ Code/Framework/AzCore/AzCore/DOM/DomBackend.h | 54 ++ .../AzCore/AzCore/DOM/DomBackendRegistry.cpp | 68 ++ .../AzCore/AzCore/DOM/DomBackendRegistry.h | 44 ++ .../AzCore/DOM/DomBackendRegistryInterface.h | 54 ++ Code/Framework/AzCore/AzCore/DOM/DomVisitor.h | 29 +- .../AzCore/AzCore/azcore_files.cmake | 10 + .../AzCore/Tests/DOM/DomJsonBenchmarks.cpp | 184 +++++ .../AzCore/Tests/DOM/DomJsonTests.cpp | 288 ++++++++ .../AzCore/Tests/azcoretests_files.cmake | 2 + 14 files changed, 1599 insertions(+), 10 deletions(-) create mode 100644 Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.cpp create mode 100644 Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h create mode 100644 Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp create mode 100644 Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h create mode 100644 Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp create mode 100644 Code/Framework/AzCore/AzCore/DOM/DomBackend.h create mode 100644 Code/Framework/AzCore/AzCore/DOM/DomBackendRegistry.cpp create mode 100644 Code/Framework/AzCore/AzCore/DOM/DomBackendRegistry.h create mode 100644 Code/Framework/AzCore/AzCore/DOM/DomBackendRegistryInterface.h create mode 100644 Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp create mode 100644 Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.cpp b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.cpp new file mode 100644 index 0000000000..4abeeaf07e --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.cpp @@ -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 + * + */ + +#include + +#include + +namespace AZ::DOM +{ + Visitor::Result JsonBackend::ReadFromStringInPlace(AZStd::string& buffer, Visitor* visitor) + { + return Json::VisitSerializedJsonInPlace(buffer, visitor); + } + + Visitor::Result JsonBackend::ReadFromString(AZStd::string_view buffer, Lifetime lifetime, Visitor* visitor) + { + return Json::VisitSerializedJson(buffer, lifetime, visitor); + } + + AZStd::unique_ptr JsonBackend::CreateStreamWriter(AZ::IO::GenericStream* stream) + { + return Json::GetJsonStreamWriter(stream, Json::OutputFormatting::PrettyPrintedJson); + } + + void JsonBackend::Register() + { + if (auto backendRegistry = BackendRegistry::Get()) + { + backendRegistry->RegisterBackend(kName, {kExtension}); + } + } +} diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h new file mode 100644 index 0000000000..5e93ece1de --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h @@ -0,0 +1,27 @@ +/* + * 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 + +namespace AZ::DOM +{ + class JsonBackend final : public Backend + { + public: + Visitor::Result ReadFromStringInPlace(AZStd::string& buffer, Visitor* visitor) override; + Visitor::Result ReadFromString(AZStd::string_view buffer, Lifetime lifetime, Visitor* visitor) override; + AZStd::unique_ptr CreateStreamWriter(AZ::IO::GenericStream* stream) override; + + static constexpr const char* kName = "JSON"; + static constexpr const char* kExtension = ".json"; + static void Register(); + }; +} // namespace AZ::DOM diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp new file mode 100644 index 0000000000..302fd7bd63 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp @@ -0,0 +1,675 @@ +/* + * 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 + +namespace AZ::DOM::Json +{ + // + // class DocumentWriter + // + // Visitor that produces a rapidjson::Document + class DocumentWriter final : public Visitor + { + public: + VisitorFlags GetVisitorFlags() const override + { + return VisitorFlags::SupportsRawKeys | VisitorFlags::SupportsArrays | VisitorFlags::SupportsObjects; + } + + Result Null() override + { + CurrentValue().SetNull(); + return FinishWrite(); + } + + Result Bool(bool value) override + { + CurrentValue().SetBool(value); + return FinishWrite(); + } + + Result Int64(AZ::s64 value) override + { + CurrentValue().SetInt64(value); + return FinishWrite(); + } + + Result Uint64(AZ::u64 value) override + { + CurrentValue().SetUint64(value); + return FinishWrite(); + } + + Result Double(double value) override + { + CurrentValue().SetDouble(value); + return FinishWrite(); + } + + Result String(AZStd::string_view value, Lifetime lifetime) override + { + if (lifetime == Lifetime::Temporary) + { + CurrentValue().SetString(value.data(), static_cast(value.length()), m_result.GetAllocator()); + } + else + { + CurrentValue().SetString(value.data(), static_cast(value.size())); + } + return FinishWrite(); + } + + Result StartObject() override + { + CurrentValue().SetObject(); + + const bool isObject = true; + m_entryStack.emplace_front(isObject, CurrentValue()); + return VisitorSuccess(); + } + + Result EndObject(AZ::u64 attributeCount) override + { + if (m_entryStack.empty()) + { + return VisitorFailure(VisitorErrorCode::InternalError, "EndObject called without a matching BeginObject call"); + } + + if (!m_entryStack.front().m_isObject) + { + return VisitorFailure(VisitorErrorCode::InternalError, "Expected EndArray and received EndObject instead"); + } + + if (m_entryStack.front().m_entryCount != attributeCount) + { + return FormatVisitorFailure( + VisitorErrorCode::InternalError, "EndObject: Expected %lu attributes but received %lu attributes instead", + attributeCount, m_entryStack.front().m_entryCount); + } + + m_entryStack.pop_front(); + return FinishWrite(); + } + + Result Key(AZ::Name key) override + { + return RawKey(key.GetStringView(), Lifetime::Persistent); + } + + Result RawKey(AZStd::string_view key, Lifetime lifetime) override + { + AZ_Assert(!m_entryStack.empty(), "Attempmted to push a key with no object"); + AZ_Assert(m_entryStack.front().m_isObject, "Attempted to push a key to an array"); + if (lifetime == Lifetime::Persistent) + { + m_entryStack.front().m_key.SetString(key.data(), static_cast(key.size())); + } + else + { + m_entryStack.front().m_key.SetString(key.data(), static_cast(key.size()), m_result.GetAllocator()); + } + return VisitorSuccess(); + } + + Result StartArray() override + { + CurrentValue().SetArray(); + + const bool isObject = false; + m_entryStack.emplace_front(isObject, CurrentValue()); + return VisitorSuccess(); + } + + Result EndArray(AZ::u64 elementCount) override + { + if (m_entryStack.empty()) + { + return VisitorFailure(VisitorErrorCode::InternalError, "EndArray called without a matching BeginArray call"); + } + + if (m_entryStack.front().m_isObject) + { + return VisitorFailure(VisitorErrorCode::InternalError, "Expected EndObject and received EndArray instead"); + } + + if (m_entryStack.front().m_entryCount != elementCount) + { + return FormatVisitorFailure( + VisitorErrorCode::InternalError, "EndArray: Expected %lu elements but received %lu elements instead", elementCount, + m_entryStack.front().m_entryCount); + } + + m_entryStack.pop_front(); + return FinishWrite(); + } + + rapidjson::Document&& TakeDocument() + { + return AZStd::move(m_result); + } + + private: + Result FinishWrite() + { + if (m_entryStack.empty()) + { + return VisitorSuccess(); + } + + // Retrieve the top value of the stack and replace it with a null value + rapidjson::Value value; + m_entryStack.front().m_value.Swap(value); + ++m_entryStack.front().m_entryCount; + + if (m_entryStack.front().m_key.IsString()) + { + m_entryStack.front().m_container.AddMember(m_entryStack.front().m_key.Move(), AZStd::move(value), m_result.GetAllocator()); + m_entryStack.front().m_key.SetNull(); + } + else + { + m_entryStack.front().m_container.PushBack(AZStd::move(value), m_result.GetAllocator()); + } + + return VisitorSuccess(); + } + + rapidjson::Value& CurrentValue() + { + if (m_entryStack.empty()) + { + return m_result; + } + return m_entryStack.front().m_value; + } + + struct ValueInfo + { + ValueInfo(bool isObject, rapidjson::Value& container) + : m_isObject(isObject) + , m_container(container) + { + } + + bool m_isObject; + rapidjson::Value& m_container; + rapidjson::Value m_value; + AZ::u64 m_entryCount = 0; + rapidjson::Value m_key; + }; + + rapidjson::Document m_result; + AZStd::deque m_entryStack; + AZ::u64 m_entryCount = 0; + }; + + // + // class StreamWriter + // + // Visitor that writes to a rapidjson::Writer + template + class StreamWriter : public Visitor + { + public: + StreamWriter(AZ::IO::GenericStream* stream) + : m_streamWriter(stream) + , m_writer(TWriter(m_streamWriter)) + { + } + + VisitorFlags GetVisitorFlags() const override + { + return VisitorFlags::SupportsRawKeys | VisitorFlags::SupportsArrays | VisitorFlags::SupportsObjects; + } + + Result Null() override + { + return CheckWrite(m_writer.Null()); + } + + Result Bool(bool value) override + { + return CheckWrite(m_writer.Bool(value)); + } + + Result Int64(AZ::s64 value) override + { + return CheckWrite(m_writer.Int64(value)); + } + + Result Uint64(AZ::u64 value) override + { + return CheckWrite(m_writer.Uint64(value)); + } + + Result Double(double value) override + { + return CheckWrite(m_writer.Double(value)); + } + + Result String(AZStd::string_view value, Lifetime lifetime) override + { + const bool shouldCopy = lifetime == Lifetime::Temporary; + return CheckWrite(m_writer.String(value.data(), static_cast(value.size()), shouldCopy)); + } + + Result StartObject() override + { + return CheckWrite(m_writer.StartObject()); + } + + Result EndObject(AZ::u64 attributeCount) override + { + return CheckWrite(m_writer.EndObject(static_cast(attributeCount))); + } + + Result Key(AZ::Name key) override + { + return RawKey(key.GetStringView(), Lifetime::Persistent); + } + + Result RawKey(AZStd::string_view key, Lifetime lifetime) override + { + const bool shouldCopy = lifetime == Lifetime::Temporary; + return CheckWrite(m_writer.Key(key.data(), static_cast(key.size()), shouldCopy)); + } + + Result StartArray() override + { + return CheckWrite(m_writer.StartArray()); + } + + Result EndArray(AZ::u64 elementCount) override + { + return CheckWrite(m_writer.EndArray(static_cast(elementCount))); + } + + private: + Result CheckWrite(bool writeSucceeded) + { + if (!writeSucceeded) + { + return VisitorFailure(VisitorErrorCode::InternalError, "Failed to write JSON"); + } + return VisitorSuccess(); + } + + AZ::IO::RapidJSONStreamWriter m_streamWriter; + TWriter m_writer; + }; + + // + // struct JsonReadHandler + // + // Handler for a rapidjson::Reader that translates reads into an AZ::DOM::Visitor + struct JsonReadHandler : public rapidjson::BaseReaderHandler, JsonReadHandler> + { + public: + JsonReadHandler(Visitor* visitor, Lifetime stringLifetime) + : m_visitor(visitor) + , m_stringLifetime(stringLifetime) + , m_outcome(AZ::Success()) + { + } + + bool Null() + { + return CheckResult(m_visitor->Null()); + } + + bool Bool(bool b) + { + return CheckResult(m_visitor->Bool(b)); + } + + bool Int(int i) + { + return CheckResult(m_visitor->Int64(static_cast(i))); + } + + bool Uint(unsigned i) + { + return CheckResult(m_visitor->Uint64(static_cast(i))); + } + + bool Int64(int64_t i) + { + return CheckResult(m_visitor->Int64(i)); + } + + bool Uint64(uint64_t i) + { + return CheckResult(m_visitor->Uint64(i)); + } + + bool Double(double d) + { + return CheckResult(m_visitor->Double(d)); + } + + bool RawNumber([[maybe_unused]] const Ch* str, [[maybe_unused]] rapidjson::SizeType length, [[maybe_unused]] bool copy) + { + AZ_Assert(false, "Raw numbers are unsupported"); + return false; + } + + bool String(const Ch* str, rapidjson::SizeType length, bool copy) + { + Lifetime lifetime = m_stringLifetime; + if (!copy) + { + lifetime = Lifetime::Temporary; + } + return CheckResult(m_visitor->String(AZStd::string_view(str, length), lifetime)); + } + + bool StartObject() + { + return CheckResult(m_visitor->StartObject()); + } + + bool Key(const Ch* str, rapidjson::SizeType length, [[maybe_unused]] bool copy) + { + AZStd::string_view key = AZStd::string_view(str, length); + if (!m_visitor->SupportsRawKeys()) + { + m_visitor->Key(AZ::Name(key)); + } + Lifetime lifetime = m_stringLifetime; + if (!copy) + { + lifetime = Lifetime::Temporary; + } + return CheckResult(m_visitor->RawKey(key, lifetime)); + } + + bool EndObject([[maybe_unused]] rapidjson::SizeType memberCount) + { + return CheckResult(m_visitor->EndObject(memberCount)); + } + + bool StartArray() + { + return CheckResult(m_visitor->StartArray()); + } + + bool EndArray([[maybe_unused]] rapidjson::SizeType elementCount) + { + return CheckResult(m_visitor->EndArray(elementCount)); + } + + Visitor::Result&& TakeOutcome() + { + return AZStd::move(m_outcome); + } + + private: + bool CheckResult(Visitor::Result result) + { + if (!result.IsSuccess()) + { + m_outcome = AZStd::move(result); + return false; + } + return true; + } + + Visitor::Result m_outcome; + Visitor* m_visitor; + Lifetime m_stringLifetime; + }; + + // + // struct AzStringStream + // + // rapidjson stream wrapper for AZStd::string suitable for in-situ parsing + struct AzStringStream + { + using Ch = char; + + AzStringStream(AZStd::string& buffer) + { + m_cursor = buffer.data(); + m_begin = m_cursor; + } + + char Peek() const + { + return *m_cursor; + } + + char Take() + { + return *m_cursor++; + } + + size_t Tell() const + { + return static_cast(m_cursor - m_begin); + } + + char* PutBegin() + { + m_write = m_cursor; + return m_cursor; + } + + void Put(char c) + { + (*m_write++) = c; + } + + void Flush() + { + } + + size_t PutEnd(char* begin) + { + return m_write - begin; + } + + const char* Peek4() const + { + AZ_Assert(false, "Not implemented, encoding is hard-coded to UTF-8"); + } + + char* m_cursor; //!< Current read position. + char* m_write; //!< Current write position. + const char* m_begin; //!< Head of string. + }; + + // + // Serialized JSON util functions + // + AZStd::unique_ptr GetJsonStreamWriter(AZ::IO::GenericStream* stream, OutputFormatting format) + { + if (format == OutputFormatting::MinifiedJson) + { + using WriterType = rapidjson::Writer; + return AZStd::make_unique>(stream); + } + else + { + using WriterType = rapidjson::PrettyWriter; + return AZStd::make_unique>(stream); + } + } + + Visitor::Result VisitSerializedJson(AZStd::string_view buffer, Lifetime lifetime, Visitor* visitor) + { + rapidjson::Reader reader; + rapidjson::MemoryStream stream(buffer.data(), buffer.size()); + JsonReadHandler handler(visitor, lifetime); + + constexpr int flags = rapidjson::kParseCommentsFlag; + reader.Parse(stream, handler); + return handler.TakeOutcome(); + } + + Visitor::Result VisitSerializedJsonInPlace(AZStd::string& buffer, Visitor* visitor) + { + rapidjson::Reader reader; + AzStringStream stream(buffer); + JsonReadHandler handler(visitor, Lifetime::Persistent); + + constexpr int flags = rapidjson::kParseCommentsFlag | rapidjson::kParseInsituFlag; + reader.Parse(stream, handler); + return handler.TakeOutcome(); + } + + // + // In-memory rapidjson util functions + // + AZ::Outcome WriteToRapidJsonDocument(Backend::WriteCallback writeCallback) + { + DocumentWriter writer; + auto result = writeCallback(&writer); + if (!result.IsSuccess()) + { + return AZ::Failure(result.TakeError().FormatVisitorErrorMessage()); + } + return AZ::Success(writer.TakeDocument()); + } + + Visitor::Result VisitRapidJsonValue(const rapidjson::Value& value, Visitor* visitor, Lifetime lifetime) + { + enum class EndMarker + { + EndArray, + EndObject + }; + + // Processing stack consists of values comprised of one of a: + // - rapidjson::Value to process + // - EndMarker denoting the end of an array or object + // - string denoting a key at the beginning of a key/value pair + using Entry = AZStd::variant; + AZStd::stack entryStack; + AZStd::stack entryCountStack; + entryStack.push(&value); + + while (!entryStack.empty()) + { + const auto currentEntry = entryStack.top(); + entryStack.pop(); + + if (AZStd::holds_alternative(currentEntry)) + { + EndMarker marker = AZStd::get(currentEntry); + if (marker == EndMarker::EndArray) + { + visitor->EndArray(entryCountStack.top()); + } + else + { + visitor->EndObject(entryCountStack.top()); + } + entryCountStack.pop(); + continue; + } + + if (AZStd::holds_alternative(currentEntry)) + { + AZStd::string_view key = AZStd::get(currentEntry); + if (visitor->SupportsRawKeys()) + { + visitor->RawKey(key, lifetime); + } + else + { + visitor->Key(AZ::Name(key)); + } + continue; + } + + const rapidjson::Value& currentValue = *AZStd::get(currentEntry); + if (!entryCountStack.empty()) + { + ++entryCountStack.top(); + } + + Visitor::Result result = AZ::Success(); + + switch (currentValue.GetType()) + { + case rapidjson::kNullType: + result = visitor->Null(); + break; + case rapidjson::kFalseType: + result = visitor->Bool(false); + break; + case rapidjson::kTrueType: + result = visitor->Bool(true); + break; + case rapidjson::kObjectType: + entryStack.push(EndMarker::EndObject); + entryCountStack.push(0); + result = visitor->StartObject(); + for (auto it = currentValue.MemberEnd(); it != currentValue.MemberBegin(); --it) + { + auto entry = (it - 1); + const AZStd::string_view key(entry->name.GetString(), static_cast(entry->name.GetStringLength())); + entryStack.push(&entry->value); + entryStack.push(key); + } + break; + case rapidjson::kArrayType: + entryStack.push(EndMarker::EndArray); + entryCountStack.push(0); + result = visitor->StartArray(); + for (auto it = currentValue.End(); it != currentValue.Begin(); --it) + { + auto entry = (it - 1); + entryStack.push(entry); + } + break; + case rapidjson::kStringType: + result = visitor->String( + AZStd::string_view(currentValue.GetString(), static_cast(currentValue.GetStringLength())), lifetime); + break; + case rapidjson::kNumberType: + if (currentValue.IsFloat() || currentValue.IsDouble()) + { + result = visitor->Double(currentValue.GetDouble()); + } + else if (currentValue.IsInt64() || currentValue.IsInt()) + { + result = visitor->Int64(currentValue.GetInt64()); + } + else + { + result = visitor->Uint64(currentValue.GetUint64()); + } + break; + default: + return AZ::Failure(VisitorError(VisitorErrorCode::InvalidData, "Value with invalid type specified")); + } + + if (!result.IsSuccess()) + { + return result; + } + } + + return AZ::Success(); + } +} // namespace AZ::DOM::Json diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h new file mode 100644 index 0000000000..323e0b880c --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h @@ -0,0 +1,60 @@ +/* + * 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 +#include +#include +#include +#include + +namespace AZ::DOM::Json +{ + //! Specifies how JSON should be formatted when serialized. + enum class OutputFormatting + { + MinifiedJson, //!< Formats JSON in compact minified form, focusing on minimizing output size. + PrettyPrintedJson, //!< Formats JSON in a pretty printed form, focusing on legibility to readers. + }; + + //! Creates a Visitor that will write serialized JSON to the specified stream. + //! \param stream The stream the visitor will write to. + //! \param format The format to write in. + //! \return A Visitor that will write to stream when visited. + AZStd::unique_ptr GetJsonStreamWriter( + AZ::IO::GenericStream* stream, OutputFormatting format = OutputFormatting::PrettyPrintedJson); + //! Reads serialized JSON from a string and applies it to a visitor. + //! \param buffer The UTF-8 serialized JSON to read. + //! \param lifetime Specifies the lifetime of the specified buffer. If the string specified by buffer might be deallocated, + //! ensure specify Lifetime::Temporary is specified. + //! \param visitor The visitor to visit with the JSON buffer's contents. + //! \return The aggregate result specifying whether the visitor operations were successful. + Visitor::Result VisitSerializedJson(AZStd::string_view buffer, Lifetime lifetime, Visitor* visitor); + //! Reads serialized JSON from a string in-place and applies it to a visitor. + //! \param buffer The UTF-8 serialized JSON to read. This buffer will be modified as part of the deserialization process to + //! apply null terminators. + //! \param visitor The visitor to visit with the JSON buffer's contents. The strings provided to the visitor will only + //! be valid for the lifetime of buffer. + //! \return The aggregate result specifying whether the visitor operations were successful. + Visitor::Result VisitSerializedJsonInPlace(AZStd::string& buffer, Visitor* visitor); + + //! Takes a visitor specified by a callback and produces a rapidjson::Document. + //! \param writeCallback A callback specifying a visitor to accept to build the resulting document. + //! \return An outcome with either the rapidjson::Document or an error message. + AZ::Outcome WriteToRapidJsonDocument(Backend::WriteCallback writeCallback); + //! Accepts a visitor with the contents of a rapidjson::Value. + //! \param value The rapidjson::Value to apply to visitor. + //! \param visitor The visitor to receive the contents of value. + //! \param lifetime The lifetime to specify for visiting strings. If the rapidjson::Value might be destroyed or changed + //! before the visitor is finished using these values, Lifetime::Temporary should be specified. + //! \return The aggregate result specifying whether the visitor operations were successful. + Visitor::Result VisitRapidJsonValue(const rapidjson::Value& value, Visitor* visitor, Lifetime lifetime); +} // namespace AZ::DOM::Json diff --git a/Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp b/Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp new file mode 100644 index 0000000000..f26e34acdf --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp @@ -0,0 +1,77 @@ +/* + * 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 "DomBackend.h" + +namespace AZ::DOM +{ + Visitor::Result Backend::ReadFromPath(AZ::IO::PathView pathName, Visitor* visitor, size_t maxFileSize) + { + auto readResult = AZ::Utils::ReadFile(pathName.Native(), maxFileSize); + if (!readResult.IsSuccess()) + { + return AZ::Failure(VisitorError(VisitorErrorCode::InternalError, readResult.TakeError())); + } + + AZStd::string fileContents = readResult.TakeValue(); + return ReadFromString(fileContents, Lifetime::Temporary, visitor); + } + + Visitor::Result Backend::ReadFromStream(AZ::IO::GenericStream* stream, Visitor* visitor, size_t maxSize) + { + size_t length = stream->GetLength(); + if (length > maxSize) + { + return AZ::Failure(VisitorError(VisitorErrorCode::InternalError, "Stream is too large.")); + } + AZStd::string buffer; + buffer.resize(maxSize); + stream->Read(length, buffer.data()); + return ReadFromString(buffer, Lifetime::Temporary, visitor); + } + + Visitor::Result Backend::ReadFromStringInPlace(AZStd::string& buffer, Visitor* visitor) + { + return ReadFromString(buffer, Lifetime::Persistent, visitor); + } + + Visitor::Result Backend::WriteToStream(AZ::IO::GenericStream* stream, WriteCallback callback) + { + AZStd::unique_ptr writer = CreateStreamWriter(stream); + return callback(writer.get()); + } + + Visitor::Result Backend::WriteToPath(AZ::IO::PathView pathName, WriteCallback callback) + { + AZStd::string buffer; + auto serializeResult = WriteToString(buffer, callback); + if (!serializeResult.IsSuccess()) + { + return serializeResult; + } + + auto writeResult = AZ::Utils::WriteFile(buffer, pathName.Native()); + if (!writeResult.IsSuccess()) + { + return AZ::Failure(VisitorError(VisitorErrorCode::InternalError, writeResult.TakeError())); + } + + return AZ::Success(); + } + + Visitor::Result Backend::WriteToString(AZStd::string& buffer, WriteCallback callback) + { + AZ::IO::ByteContainerStream stream{&buffer}; + AZStd::unique_ptr writer = CreateStreamWriter(&stream); + return callback(writer.get()); + } +} diff --git a/Code/Framework/AzCore/AzCore/DOM/DomBackend.h b/Code/Framework/AzCore/AzCore/DOM/DomBackend.h new file mode 100644 index 0000000000..bb5c9e40fe --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/DomBackend.h @@ -0,0 +1,54 @@ +/* + * 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 +#include +#include + +namespace AZ::DOM +{ + //! Backends are registered centrally and used to transition DOM formats to and from a textual format. + class Backend + { + public: + virtual ~Backend() = default; + + //! Attempt to read this format from the given file into the target Visitor. + Visitor::Result ReadFromPath( + AZ::IO::PathView pathName, Visitor* visitor, size_t maxFileSize = AZStd::numeric_limits::max()); + //! Attempt to read this format from the given stream into the target Visitor. + //! The base implementation reads the stream into memory and calls ReadFromString. + virtual Visitor::Result ReadFromStream( + AZ::IO::GenericStream* stream, Visitor* visitor, size_t maxSize = AZStd::numeric_limits::max()); + //! Attempt to read this format from a mutable string into the target Visitor. This enables some backends to + //! parse without making additional string allocations. + //! This string may be modified and read in place without being copied, so when calling this please ensure that: + //! - The string won't be deallocated until the visitor no longer needs the values and + //! - The string is safe to modify in place. + //! The base implementation simply calls ReadFromString. + virtual Visitor::Result ReadFromStringInPlace(AZStd::string& buffer, Visitor* visitor); + //! Attempt to read this format from an immutable buffer in memory into the target Visitor. + virtual Visitor::Result ReadFromString(AZStd::string_view buffer, Lifetime lifetime, Visitor* visitor) = 0; + + //! Acquire a visitor interface for writing to the target output file. + virtual AZStd::unique_ptr CreateStreamWriter(AZ::IO::GenericStream* stream) = 0; + //! A callback that accepts a Visitor, making DOM calls to inform the serializer, and returns an + //! aggregate error code to indicate whether or not the operation succeeded. + using WriteCallback = AZStd::function; + //! Attempt to write a value to a stream using a write callback. + Visitor::Result WriteToStream(AZ::IO::GenericStream* stream, WriteCallback callback); + //! Attempt to write a value to a file using a write callback. + Visitor::Result WriteToPath(AZ::IO::PathView pathName, WriteCallback callback); + //! Attempt to write a value to a string using a write callback. + Visitor::Result WriteToString(AZStd::string& buffer, WriteCallback callback); + }; +} // namespace AZ::DOM diff --git a/Code/Framework/AzCore/AzCore/DOM/DomBackendRegistry.cpp b/Code/Framework/AzCore/AzCore/DOM/DomBackendRegistry.cpp new file mode 100644 index 0000000000..c8f4050602 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/DomBackendRegistry.cpp @@ -0,0 +1,68 @@ +/* + * 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 + +namespace AZ::DOM +{ + BackendRegistry* BackendRegistry::s_instance = nullptr; + + BackendRegistryInterface* BackendRegistry::Get() + { + return AZ::Interface::Get(); + } + + void BackendRegistry::Create() + { + AZ_Assert(!s_instance, "Attempted to register BackendRegistry when it's already registered"); + s_instance = aznew BackendRegistry; + AZ::Interface::Register(s_instance); + } + + void BackendRegistry::Destroy() + { + AZ_Assert(s_instance, "Attempted to unregister a non-existent BackendRegistry"); + AZ::Interface::Unregister(s_instance); + delete s_instance; + s_instance = nullptr; + } + + AZStd::unique_ptr BackendRegistry::GetBackendByName(AZStd::string_view name) + { + auto backendIterator = m_nameToBackend.find(name); + if (backendIterator != m_nameToBackend.end()) + { + return backendIterator->second(); + } + return nullptr; + } + + AZStd::unique_ptr BackendRegistry::GetBackendForExtension(AZStd::string_view extension) + { + auto extensionIterator = m_extensionToName.find(extension); + if (extensionIterator != m_extensionToName.end()) + { + return GetBackendByName(extensionIterator->second); + } + return nullptr; + } + + void BackendRegistry::RegisterBackendInternal( + BackendRegistryInterface::BackendFactory factory, AZStd::string name, AZStd::vector extensions) + { + AZ_Assert(m_nameToBackend.find(name) == m_nameToBackend.end(), "DOM Backend %s already registered", name.c_str()); + m_nameToBackend.insert({name, factory}); + for (AZStd::string& extension : extensions) + { + AZ_Assert(m_extensionToName.find(extension) == m_extensionToName.end(), "DOM Extensions already registered", extension.c_str()); + m_extensionToName.insert({AZStd::move(extension), name}); + } + } +} diff --git a/Code/Framework/AzCore/AzCore/DOM/DomBackendRegistry.h b/Code/Framework/AzCore/AzCore/DOM/DomBackendRegistry.h new file mode 100644 index 0000000000..c71e6798fc --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/DomBackendRegistry.h @@ -0,0 +1,44 @@ +/* + * 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 + +namespace AZ::DOM +{ + //! DOM backend registry implementation. + //! \see BackendRegistryInterface + class BackendRegistry final : public BackendRegistryInterface + { + public: + AZ_RTTI(BackendRegistry, "{95533861-6201-4E45-BD03-097A20850C48}", BackendRegistryInterface); + AZ_CLASS_ALLOCATOR(BackendRegistry, AZ::SystemAllocator, 0); + + AZStd::unique_ptr GetBackendByName(AZStd::string_view name) override; + AZStd::unique_ptr GetBackendForExtension(AZStd::string_view extension) override; + + //! Convenience method, gets the current instance of the BackendRegistry via AZ::Interface. + static BackendRegistryInterface* Get(); + //! Creates a singleton BackendRegistry and registers it via AZ::Interface. + static void Create(); + //! Destroys the singleton BackendRegistry created by Create and unregisters it from AZ::Interface. + static void Destroy(); + + protected: + void RegisterBackendInternal(BackendFactory factory, AZStd::string name, AZStd::vector extensions) override; + + private: + using BackendFactory = AZStd::function()>; + AZStd::unordered_map m_nameToBackend; + AZStd::unordered_map m_extensionToName; + + static BackendRegistry* s_instance; + }; +} // namespace AZ::DOM diff --git a/Code/Framework/AzCore/AzCore/DOM/DomBackendRegistryInterface.h b/Code/Framework/AzCore/AzCore/DOM/DomBackendRegistryInterface.h new file mode 100644 index 0000000000..4651f35961 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/DomBackendRegistryInterface.h @@ -0,0 +1,54 @@ +/* + * 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 + +namespace AZ::DOM +{ + //! Central interface for registering and looking up backend types by file extension. + class BackendRegistryInterface + { + public: + AZ_RTTI(BackendRegistryInterface, "{B72A88AC-DF15-4F92-9489-ABCDEA3D94E6}") + using BackendFactory = AZStd::function()>; + + virtual ~BackendRegistryInterface() = default; + + //! Registers a factory for a given backend. + //! \param name A unique name to identify this backend. + //! \param extensions A set of file extensions this backend supports. + //! Extensions should by the entire file suffix including any dots (.), for example: + //! ".json" or ".tar.gz" + template + void RegisterBackend(AZStd::string name, AZStd::vector extensions); + + //! Looks up a DOM backend based on its name. + virtual AZStd::unique_ptr GetBackendByName(AZStd::string_view name) = 0; + + //! Looks up a DOM backend based on a file extension. + virtual AZStd::unique_ptr GetBackendForExtension(AZStd::string_view extension) = 0; + + protected: + //! Registers a factory for a given backend, called by RegisterBackend. + //! \param factory The factory function to create new backend instances. + //! \param name The unique name to identify this backend. + //! \param extensions A set of file extensions this backend supports. + //! \see RegisterBackend + virtual void RegisterBackendInternal(BackendFactory factory, AZStd::string name, AZStd::vector extensions) = 0; + }; + + template + void BackendRegistryInterface::RegisterBackend(AZStd::string name, AZStd::vector extensions) + { + RegisterBackendInternal([](){ + return AZStd::make_unique(); + }, AZStd::move(name), AZStd::move(extensions)); + } +} // namespace AZ::DOM diff --git a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h index 584cfce4ed..eb6f20ae1b 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h +++ b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h @@ -17,7 +17,7 @@ namespace AZ::DOM { // // Lifetime enum - // + // //! Specifies the period in which a reference value will still be alive and safe to read. enum class Lifetime { @@ -30,7 +30,7 @@ namespace AZ::DOM // // VisitorErrorCode enum - // + // //! Error code specifying the reason a Visitor operation failed. enum class VisitorErrorCode { @@ -75,7 +75,7 @@ namespace AZ::DOM }; //! A type alias for opaque DOM types that aren't meant to be serializable. - //! /see VisitorInterface::OpaqueValue + //! \see VisitorInterface::OpaqueValue using OpaqueType = AZStd::any; // @@ -116,7 +116,7 @@ namespace AZ::DOM //! - \ref Double: 64 bit double precision float //! - \ref Null: sentinel "empty" type with no value representation //! - \ref String: UTF8 encoded string - //! - \ref Object: an ordered container of key/value pairs where keys are AZ::Names and values may be any DOM type + //! - \ref Object: an ordered container of key/value pairs where keys are \ref AZ::Name and values may be any DOM type //! (including Object) //! - \ref Array: an ordered container of values, in which values are any DOM value type (including Array) //! - \ref Node: a container @@ -144,17 +144,17 @@ namespace AZ::DOM //! Raw (\see VisitorFlags::SupportsRawValues) and opaque values (\see VisitorFlags::SupportsOpaqueValues) //! are disallowed by default, as their handling is intended to be implementation-specific. virtual VisitorFlags GetVisitorFlags() const; - //! /see VisitorFlags::SupportsRawValues + //! \see VisitorFlags::SupportsRawValues bool SupportsRawValues() const; - //! /see VisitorFlags::SupportsRawKeys + //! \see VisitorFlags::SupportsRawKeys bool SupportsRawKeys() const; - //! /see VisitorFlags::SupportsObjects + //! \see VisitorFlags::SupportsObjects bool SupportsObjects() const; - //! /see VisitorFlags::SupportsArrays + //! \see VisitorFlags::SupportsArrays bool SupportsArrays() const; - //! /see VisitorFlags::SupportsNodes + //! \see VisitorFlags::SupportsNodes bool SupportsNodes() const; - //! /see VisitorFlags::SupportsOpaqueValues + //! \see VisitorFlags::SupportsOpaqueValues bool SupportsOpaqueValues() const; //! Operates on an empty null value. @@ -231,6 +231,15 @@ namespace AZ::DOM static Result VisitorFailure(VisitorErrorCode code, AZStd::string additionalInfo); //! Helper method, constructs a failure \ref Result with the specified error. static Result VisitorFailure(VisitorError error); + + //! Helper method, constructs a failure \ref Result with the specified code and supplemental info specified by a format string + //! and its arguments. + template + static Result FormatVisitorFailure(VisitorErrorCode code, TArgs... formatArgs) + { + return VisitorFailure(code, AZStd::string::format(formatArgs...)); + } + //! Helper method, constructs a success \ref Result. static Result VisitorSuccess(); }; diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index a5cc3fdcd4..54f2c9ecca 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -125,8 +125,18 @@ set(FILES Debug/TraceMessagesDrillerBus.h Debug/TraceReflection.cpp Debug/TraceReflection.h + DOM/DomAdapter.h + DOM/DomBackend.cpp + DOM/DomBackend.h + DOM/DomBackendRegistry.cpp + DOM/DomBackendRegistry.h + DOM/DomBackendRegistryInterface.h DOM/DomVisitor.cpp DOM/DomVisitor.h + DOM/Backends/JSON/JsonBackend.cpp + DOM/Backends/JSON/JsonBackend.h + DOM/Backends/JSON/JsonSerializationUtils.cpp + DOM/Backends/JSON/JsonSerializationUtils.h Driller/DefaultStringPool.h Driller/Driller.cpp Driller/Driller.h diff --git a/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp b/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp new file mode 100644 index 0000000000..238802a35f --- /dev/null +++ b/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp @@ -0,0 +1,184 @@ +/* + * 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 + * + */ + +#if defined(HAVE_BENCHMARK) + +#include +#include +#include +#include +#include +#include + +namespace Benchmark +{ + class DomJsonBenchmark : public UnitTest::AllocatorsBenchmarkFixture + { + public: + void SetUp([[maybe_unused]] const ::benchmark::State& st) override + { + UnitTest::AllocatorsBenchmarkFixture::SetUp(st); + AZ::NameDictionary::Create(); + } + + void SetUp([[maybe_unused]] ::benchmark::State& st) override + { + UnitTest::AllocatorsBenchmarkFixture::SetUp(st); + AZ::NameDictionary::Create(); + } + + void TearDown([[maybe_unused]] ::benchmark::State& st) override + { + AZ::NameDictionary::Destroy(); + UnitTest::AllocatorsBenchmarkFixture::TearDown(st); + } + + void TearDown([[maybe_unused]] const ::benchmark::State& st) override + { + AZ::NameDictionary::Destroy(); + UnitTest::AllocatorsBenchmarkFixture::TearDown(st); + } + + AZStd::string GenerateDomJsonBenchmarkPayload(int64_t entryCount = 100, int64_t stringTemplateLength = 5) + { + rapidjson::Document document; + document.SetObject(); + + AZStd::string entryTemplate; + while (entryTemplate.size() < static_cast(stringTemplateLength)) + { + entryTemplate += "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor "; + } + entryTemplate.resize(stringTemplateLength); + AZStd::string buffer; + + auto createString = [&](int n) -> rapidjson::Value + { + buffer = AZStd::string::format("#%i %s", n, entryTemplate.c_str()); + return rapidjson::Value(buffer.data(), static_cast(buffer.size()), document.GetAllocator()); + }; + + auto createEntry = [&](int n) -> rapidjson::Value + { + rapidjson::Value entry(rapidjson::kObjectType); + entry.AddMember("string", createString(n), document.GetAllocator()); + entry.AddMember("int", rapidjson::Value(n), document.GetAllocator()); + entry.AddMember("double", rapidjson::Value(static_cast(n) * 0.5), document.GetAllocator()); + entry.AddMember("bool", rapidjson::Value(n % 2 == 0), document.GetAllocator()); + entry.AddMember("null", rapidjson::Value(rapidjson::kNullType), document.GetAllocator()); + return entry; + }; + + auto createArray = [&]() -> rapidjson::Value + { + rapidjson::Value array; + array.SetArray(); + for (int i = 0; i < entryCount; ++i) + { + array.PushBack(createEntry(i), document.GetAllocator()); + } + return array; + }; + + auto createObject = [&]() -> rapidjson::Value + { + rapidjson::Value object; + object.SetObject(); + for (int i = 0; i < entryCount; ++i) + { + buffer = AZStd::string::format("Key%i", i); + rapidjson::Value key; + key.SetString(buffer.data(), static_cast(buffer.length()), document.GetAllocator()); + object.AddMember(key.Move(), createArray(), document.GetAllocator()); + } + return object; + }; + + document.SetObject(); + document.AddMember("entries", createObject(), document.GetAllocator()); + + AZStd::string serializedJson; + auto result = AZ::JsonSerializationUtils::WriteJsonString(document, serializedJson); + AZ_Assert(result.IsSuccess(), "Failed to serialize generated JSON"); + return serializedJson; + } + }; + +// Helper macro for registering JSON benchmarks +#define BENCHMARK_REGISTER_JSON(BaseClass, Method) \ + BENCHMARK_REGISTER_F(BaseClass, Method) \ + ->Args({ 10, 5 }) \ + ->Args({ 10, 500 }) \ + ->Args({ 100, 5 }) \ + ->Args({ 100, 500 }) \ + ->Unit(benchmark::kMillisecond); + + BENCHMARK_DEFINE_F(DomJsonBenchmark, DomDeserializeToDocumentInPlace)(benchmark::State& state) + { + AZ::DOM::JsonBackend backend; + AZStd::string serializedPayload = GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1)); + + for (auto _ : state) + { + state.PauseTiming(); + AZStd::string payloadCopy = serializedPayload; + state.ResumeTiming(); + + auto result = AZ::DOM::Json::WriteToRapidJsonDocument( + [&](AZ::DOM::Visitor* visitor) + { + return backend.ReadFromStringInPlace(payloadCopy, visitor); + }); + + benchmark::DoNotOptimize(result.GetValue()); + } + + state.SetBytesProcessed(serializedPayload.size() * state.iterations()); + } + BENCHMARK_REGISTER_JSON(DomJsonBenchmark, DomDeserializeToDocumentInPlace) + + BENCHMARK_DEFINE_F(DomJsonBenchmark, DomDeserializeToDocument)(benchmark::State& state) + { + AZ::DOM::JsonBackend backend; + AZStd::string serializedPayload = GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1)); + + for (auto _ : state) + { + auto result = AZ::DOM::Json::WriteToRapidJsonDocument( + [&](AZ::DOM::Visitor* visitor) + { + return backend.ReadFromString(serializedPayload, AZ::DOM::Lifetime::Temporary, visitor); + }); + + benchmark::DoNotOptimize(result.GetValue()); + } + + state.SetBytesProcessed(serializedPayload.size() * state.iterations()); + } + BENCHMARK_REGISTER_JSON(DomJsonBenchmark, DomDeserializeToDocument) + + BENCHMARK_DEFINE_F(DomJsonBenchmark, JsonUtilsDeserializeToDocument)(benchmark::State& state) + { + AZ::DOM::JsonBackend backend; + AZStd::string serializedPayload = GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1)); + + for (auto _ : state) + { + auto result = AZ::JsonSerializationUtils::ReadJsonString(serializedPayload); + + benchmark::DoNotOptimize(result.GetValue()); + } + + state.SetBytesProcessed(serializedPayload.size() * state.iterations()); + } + BENCHMARK_REGISTER_JSON(DomJsonBenchmark, JsonUtilsDeserializeToDocument) + +#undef BENCHMARK_REGISTER_JSON +} // namespace Benchmark + +#endif // defined(HAVE_BENCHMARK) diff --git a/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp b/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp new file mode 100644 index 0000000000..e778a449d5 --- /dev/null +++ b/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp @@ -0,0 +1,288 @@ +/* + * 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 + +namespace AZ::DOM::Tests +{ + class DomJsonTests : public UnitTest::AllocatorsFixture + { + public: + void SetUp() override + { + UnitTest::AllocatorsFixture::SetUp(); + NameDictionary::Create(); + m_document = AZStd::make_unique(); + } + + void TearDown() override + { + m_document.reset(); + NameDictionary::Destroy(); + UnitTest::AllocatorsFixture::TearDown(); + } + + static bool DeepCompare(const rapidjson::Value& lhs, const rapidjson::Value& rhs) + { + if (lhs.GetType() != rhs.GetType()) + { + return false; + } + + switch (lhs.GetType()) + { + case rapidjson::kNullType: + return true; + case rapidjson::kFalseType: + return true; + case rapidjson::kTrueType: + return true; + case rapidjson::kObjectType: + { + if (lhs.MemberCount() != rhs.MemberCount()) + { + return false; + } + + auto lhsIt = lhs.MemberBegin(); + auto rhsIt = rhs.MemberBegin(); + while (lhsIt != lhs.MemberEnd()) + { + if (lhsIt->name != rhsIt->name) + { + return false; + } + + if (!DeepCompare(lhsIt->value, rhsIt->value)) + { + return false; + } + + ++lhsIt; + ++rhsIt; + } + return true; + } + case rapidjson::kArrayType: + { + if (lhs.Size() != rhs.Size()) + { + return false; + } + + auto lhsIt = lhs.Begin(); + auto rhsIt = rhs.Begin(); + while (lhsIt != lhs.End()) + { + if (!DeepCompare(*lhsIt, *rhsIt)) + { + return false; + } + + ++lhsIt; + ++rhsIt; + } + return true; + } + case rapidjson::kStringType: + return lhs == rhs; + case rapidjson::kNumberType: + return lhs == rhs; + } + + AZ_Assert(false, "Unexpected JSON value type"); + return false; + } + + rapidjson::Value CreateString(const AZStd::string& text) + { + rapidjson::Value key; + key.SetString(text.c_str(), static_cast(text.length()), m_document->GetAllocator()); + return key; + } + + template + void AddValue(const AZStd::string& key, T value) + { + m_document->AddMember(CreateString(key), rapidjson::Value(value), m_document->GetAllocator()); + } + + // Validate round-trip serialization to and from rapidjson::Document and a UTF-8 encoded string + void PerformSerializationChecks() + { + // Generate a canonical serializaed representation of this document using rapidjson + // This will be pretty-printed using the same rapidjson pretty printer we use, so should be binary identical + // to any output generated by the visitor API + AZStd::string canonicalSerializedDocument; + AZ::JsonSerializationUtils::WriteJsonString(*m_document, canonicalSerializedDocument); + + auto visitDocumentFn = [this](AZ::DOM::Visitor* visitor) + { + return Json::VisitRapidJsonValue(*m_document, visitor, Lifetime::Persistent); + }; + + // Document -> Document + { + auto result = Json::WriteToRapidJsonDocument(visitDocumentFn); + EXPECT_TRUE(result.IsSuccess()); + EXPECT_TRUE(DeepCompare(*m_document, result.GetValue())); + } + + // Document -> string + { + AZStd::string serializedDocument; + JsonBackend backend; + auto result = backend.WriteToString(serializedDocument, visitDocumentFn); + EXPECT_TRUE(result.IsSuccess()); + EXPECT_EQ(canonicalSerializedDocument, serializedDocument); + } + + // string -> Document + { + auto result = Json::WriteToRapidJsonDocument( + [&canonicalSerializedDocument](AZ::DOM::Visitor* visitor) + { + JsonBackend backend; + return backend.ReadFromString(canonicalSerializedDocument, AZ::DOM::Lifetime::Temporary, visitor); + }); + EXPECT_TRUE(result.IsSuccess()); + EXPECT_TRUE(DeepCompare(*m_document, result.GetValue())); + } + + // string -> string + { + AZStd::string serializedDocument; + JsonBackend backend; + auto result = backend.WriteToString( + serializedDocument, + [&backend, &canonicalSerializedDocument](AZ::DOM::Visitor* visitor) + { + return backend.ReadFromString(canonicalSerializedDocument, AZ::DOM::Lifetime::Temporary, visitor); + }); + EXPECT_TRUE(result.IsSuccess()); + EXPECT_EQ(canonicalSerializedDocument, serializedDocument); + } + } + + AZStd::unique_ptr m_document; + }; + + TEST_F(DomJsonTests, EmptyArray) + { + m_document->SetArray(); + PerformSerializationChecks(); + } + + TEST_F(DomJsonTests, SimpleArray) + { + m_document->SetArray(); + for (int i = 0; i < 5; ++i) + { + m_document->PushBack(i, m_document->GetAllocator()); + } + PerformSerializationChecks(); + } + + TEST_F(DomJsonTests, NestedArrays) + { + m_document->SetArray(); + for (int j = 0; j < 7; ++j) + { + rapidjson::Value nestedArray(rapidjson::kArrayType); + for (int i = 0; i < 5; ++i) + { + nestedArray.PushBack(i, m_document->GetAllocator()); + } + m_document->PushBack(nestedArray.Move(), m_document->GetAllocator()); + } + PerformSerializationChecks(); + } + + TEST_F(DomJsonTests, EmptyObject) + { + m_document->SetObject(); + PerformSerializationChecks(); + } + + TEST_F(DomJsonTests, SimpleObject) + { + m_document->SetObject(); + for (int i = 0; i < 5; ++i) + { + m_document->AddMember(CreateString(AZStd::string::format("Key%i", i)), rapidjson::Value(i), m_document->GetAllocator()); + } + PerformSerializationChecks(); + } + + TEST_F(DomJsonTests, NestedObjects) + { + m_document->SetObject(); + for (int j = 0; j < 7; ++j) + { + rapidjson::Value nestedObject(rapidjson::kObjectType); + for (int i = 0; i < 5; ++i) + { + nestedObject.AddMember(CreateString(AZStd::string::format("Key%i", i)), rapidjson::Value(i), m_document->GetAllocator()); + } + m_document->AddMember(CreateString(AZStd::string::format("Obj%i", j)), nestedObject.Move(), m_document->GetAllocator()); + } + PerformSerializationChecks(); + } + + TEST_F(DomJsonTests, Int64) + { + m_document->SetObject(); + AddValue("int64_min", AZStd::numeric_limits::min()); + AddValue("int64_max", AZStd::numeric_limits::max()); + PerformSerializationChecks(); + } + + TEST_F(DomJsonTests, Uint64) + { + m_document->SetObject(); + AddValue("uint64_min", AZStd::numeric_limits::min()); + AddValue("uint64_max", AZStd::numeric_limits::max()); + PerformSerializationChecks(); + } + + TEST_F(DomJsonTests, Double) + { + m_document->SetObject(); + AddValue("double_min", AZStd::numeric_limits::min()); + AddValue("double_max", AZStd::numeric_limits::max()); + PerformSerializationChecks(); + } + + TEST_F(DomJsonTests, Null) + { + m_document->SetObject(); + m_document->AddMember(CreateString("null_value"), rapidjson::Value(rapidjson::kNullType), m_document->GetAllocator()); + PerformSerializationChecks(); + } + + TEST_F(DomJsonTests, Bool) + { + m_document->SetObject(); + AddValue("true_value", true); + AddValue("false_value", false); + PerformSerializationChecks(); + } + + TEST_F(DomJsonTests, String) + { + m_document->SetObject(); + m_document->AddMember(CreateString("empty_string"), CreateString(""), m_document->GetAllocator()); + m_document->AddMember(CreateString("short_string"), CreateString("test"), m_document->GetAllocator()); + m_document->AddMember(CreateString("long_string"), CreateString("abcdefghijklmnopqrstuvwxyz0123456789"), m_document->GetAllocator()); + PerformSerializationChecks(); + } +} // namespace AZ::DOM::Tests diff --git a/Code/Framework/AzCore/Tests/azcoretests_files.cmake b/Code/Framework/AzCore/Tests/azcoretests_files.cmake index d39595c45e..0fca75e2a8 100644 --- a/Code/Framework/AzCore/Tests/azcoretests_files.cmake +++ b/Code/Framework/AzCore/Tests/azcoretests_files.cmake @@ -213,6 +213,8 @@ set(FILES AZStd/Variant.cpp AZStd/VariantSerialization.cpp AZStd/VectorAndArray.cpp + DOM/DomJsonTests.cpp + DOM/DomJsonBenchmarks.cpp ) # Prevent the following files from being grouped in UNITY builds From 609469d5e44fc8707e8d477492bab55f8e32f6c4 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Wed, 10 Nov 2021 14:08:59 -0800 Subject: [PATCH 011/128] Fix a couple build issues Signed-off-by: Nicholas Van Sickle --- .../AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp | 2 +- Code/Framework/AzCore/AzCore/azcore_files.cmake | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp index 302fd7bd63..aa0b24a5ad 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp @@ -219,7 +219,6 @@ namespace AZ::DOM::Json rapidjson::Document m_result; AZStd::deque m_entryStack; - AZ::u64 m_entryCount = 0; }; // @@ -490,6 +489,7 @@ namespace AZ::DOM::Json const char* Peek4() const { AZ_Assert(false, "Not implemented, encoding is hard-coded to UTF-8"); + return m_cursor; } char* m_cursor; //!< Current read position. diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index 54f2c9ecca..abb16d61a0 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -125,7 +125,6 @@ set(FILES Debug/TraceMessagesDrillerBus.h Debug/TraceReflection.cpp Debug/TraceReflection.h - DOM/DomAdapter.h DOM/DomBackend.cpp DOM/DomBackend.h DOM/DomBackendRegistry.cpp From 0fa56ba5f8b8a3c397bb9aaef12fcffe6b84b051 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 10 Nov 2021 15:39:17 -0800 Subject: [PATCH 012/128] new source file button works Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../ScriptCanvasAssetTrackerDefinitions.h | 1 + .../Code/Editor/Components/EditorGraph.cpp | 4 +- .../Code/Editor/View/Windows/MainWindow.cpp | 229 +++++++----------- .../Code/Editor/View/Windows/MainWindow.h | 29 +-- .../Code/Include/ScriptCanvas/Core/Core.cpp | 9 + .../Code/Include/ScriptCanvas/Core/Core.h | 2 + 6 files changed, 109 insertions(+), 165 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerDefinitions.h b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerDefinitions.h index 2aebf29b24..29f88b33c8 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerDefinitions.h +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerDefinitions.h @@ -31,6 +31,7 @@ namespace ScriptCanvasEditor NEW, MODIFIED, UNMODIFIED, + // #sc_editor_asset restore this SOURCE_REMOVED, INVALID = -1 }; diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp index 2c9dbe0fd6..baa7139aae 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp @@ -1055,6 +1055,8 @@ namespace ScriptCanvasEditor { data->m_scriptCanvasEntity.reset(entity); graph->MarkOwnership(*data); + entity->Init(); + entity->Activate(); return data; } } @@ -1352,7 +1354,7 @@ namespace ScriptCanvasEditor void Graph::SignalDirty() { - SourceHandle handle(ScriptCanvas::DataPtr(m_owner), {}, {}); + SourceHandle handle(m_owner->shared_from_this(), {}, {}); GeneralRequestBus::Broadcast(&GeneralRequests::SignalSceneDirty, handle); } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index b20fcb7e7a..5f1b59a23c 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -1146,28 +1146,7 @@ namespace ScriptCanvasEditor if (memoryAsset && asset.IsReady()) { - AZ::EntityId scGraphId = memoryAsset->GetScriptCanvasId(); - GraphCanvas::SceneNotificationBus::MultiHandler::BusDisconnect(scGraphId); - AZ::EntityId graphCanvasId = GetGraphCanvasGraphId(scGraphId); - - GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId, &GraphCanvas::AssetEditorNotifications::OnGraphRefreshed, graphCanvasId, graphCanvasId); - - int tabIndex = -1; - if (IsTabOpen(asset.GetId(), tabIndex)) - { - const AZStd::string& assetPath = memoryAsset->GetAbsolutePath(); - m_tabBar->setTabToolTip(tabIndex, assetPath.c_str()); - m_tabBar->SetTabText(tabIndex, memoryAsset->GetTabName().c_str(), memoryAsset->GetFileState()); - } - - if (graphCanvasId.IsValid()) - { - GraphCanvas::SceneNotificationBus::MultiHandler::BusConnect(graphCanvasId); - GraphCanvas::SceneMimeDelegateRequestBus::Event(graphCanvasId, &GraphCanvas::SceneMimeDelegateRequests::AddDelegate, m_entityMimeDelegateId); - - GraphCanvas::SceneRequestBus::Event(graphCanvasId, &GraphCanvas::SceneRequests::SetMimeType, Widget::NodePaletteDockWidget::GetMimeType()); - GraphCanvas::SceneMemberNotificationBus::Event(graphCanvasId, &GraphCanvas::SceneMemberNotifications::OnSceneReady); - } + } */ } @@ -1285,31 +1264,6 @@ namespace ScriptCanvasEditor return m_tabBar->InsertGraphTab(tabIndex, assetId); } - AZ::Outcome MainWindow::UpdateScriptCanvasAsset(const AZ::Data::Asset& /*scriptCanvasAsset*/) - { - // #sc_editor_asset - return AZ::Failure(AZStd::string("rewrite MainWindow::UpdateScriptCanvasAsset")); - - /* - int outTabIndex = -1; - - PushPreventUndoStateUpdate(); - RefreshScriptCanvasAsset(scriptCanvasAsset); - if (IsTabOpen(scriptCanvasAsset.GetId(), outTabIndex)) - { - RefreshActiveAsset(); - } - PopPreventUndoStateUpdate(); - - if (outTabIndex == -1) - { - return AZ::Failure(AZStd::string::format("Script Canvas Asset %s is not open in a tab", scriptCanvasAsset.ToString().c_str())); - } - - return AZ::Success(outTabIndex); - */ - } - void MainWindow::RemoveScriptCanvasAsset(const ScriptCanvasEditor::SourceHandle& /*assetId*/) { // #sc_editor_asset move what is necessary to the widget @@ -1638,7 +1592,30 @@ namespace ScriptCanvasEditor void MainWindow::OnFileNew() { - MakeNewFile(); + static int scriptCanvasEditorDefaultNewNameCount = 0; + + ScriptCanvasAssetDescription description; + + AZStd::string newAssetName = AZStd::string::format(description.GetAssetNamePatternImpl(), ++scriptCanvasEditorDefaultNewNameCount); + + AZStd::array assetRootArray; + if (!AZ::IO::FileIOBase::GetInstance()->ResolvePath(description.GetSuggestedSavePathImpl() + , assetRootArray.data(), assetRootArray.size())) + { + AZ_ErrorOnce("Script Canvas", false, "Unable to resolve @projectroot@ path"); + } + + AZStd::string assetPath; + AzFramework::StringFunc::Path::Join(assetRootArray.data(), (newAssetName + description.GetExtensionImpl()).data(), assetPath); + + auto createOutcome = CreateScriptCanvasAsset(assetPath); + if (createOutcome) + { + } + else + { + AZ_Warning("Script Canvas", createOutcome, "%s", createOutcome.GetError().data()); + } } int MainWindow::InsertTabForAsset(AZStd::string_view assetPath, ScriptCanvasEditor::SourceHandle assetId, int tabIndex) @@ -1673,32 +1650,64 @@ namespace ScriptCanvasEditor } } - AZ::Outcome MainWindow::CreateScriptCanvasAsset(AZStd::string_view /*assetPath*/, AZ::Data::AssetType /*assetType*/, int /*tabIndex*/) + AZ::Outcome MainWindow::CreateScriptCanvasAsset(AZStd::string_view assetPath, int tabIndex) { - return AZ::Failure(AZStd::string("MainWindow::CreateScriptCanvasAsset just make a new thing with the project root + untitled...")); -// int outTabIndex = -1; -// -// ScriptCanvasEditor::SourceHandle newAssetId; -// auto onAssetCreated = [this, assetPath, tabIndex, &outTabIndex](ScriptCanvasMemoryAsset& asset) -// { -// const ScriptCanvasEditor::SourceHandle& assetId = asset.GetId(); -// -// outTabIndex = InsertTabForAsset(assetPath, assetId, tabIndex); -// -// SetActiveAsset(assetId); -// -// UpdateScriptCanvasAsset(asset.GetAsset()); -// -// AZ::EntityId scriptCanvasEntityId; -// AssetTrackerRequestBus::BroadcastResult(scriptCanvasEntityId, &AssetTrackerRequests::GetScriptCanvasId, assetId); -// -// GraphCanvas::GraphId graphCanvasGraphId = GetGraphCanvasGraphId(scriptCanvasEntityId); -// GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId, &GraphCanvas::AssetEditorNotifications::OnGraphLoaded, graphCanvasGraphId); -// -// }; -// AssetTrackerRequestBus::BroadcastResult(newAssetId, &AssetTrackerRequests::Create, assetPath, assetType, onAssetCreated); + int outTabIndex = -1; - // return AZ::Success(outTabIndex); + ScriptCanvas::DataPtr graph = Graph::Create(); + AZ::Uuid assetId = AZ::Uuid::CreateRandom(); + ScriptCanvasEditor::SourceHandle handle = ScriptCanvasEditor::SourceHandle(graph, assetId, assetPath); + + outTabIndex = InsertTabForAsset(assetPath, handle, tabIndex); + m_tabBar->UpdateFileState(handle, Tracker::ScriptCanvasFileState::NEW); + + if (outTabIndex == -1) + { + return AZ::Failure(AZStd::string::format("Script Canvas Asset %.*s is not open in a tab", assetPath.data())); + } + + SetActiveAsset(handle); + + // #sc_editor_asset delete candidate + + PushPreventUndoStateUpdate(); + + AZ::EntityId scriptCanvasEntityId = graph->GetGraph()->GetScriptCanvasId(); + GraphCanvas::SceneNotificationBus::MultiHandler::BusDisconnect(scriptCanvasEntityId); + AZ::EntityId graphCanvasGraphId = GetGraphCanvasGraphId(scriptCanvasEntityId); + + GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId + , &GraphCanvas::AssetEditorNotifications::OnGraphRefreshed, graphCanvasGraphId, graphCanvasGraphId); + + if (IsTabOpen(handle, tabIndex)) + { + AZStd::string tabName; + AzFramework::StringFunc::Path::GetFileName(assetPath.data(), tabName); + m_tabBar->setTabToolTip(tabIndex, assetPath.data()); + m_tabBar->SetTabText(tabIndex, tabName.c_str(), Tracker::ScriptCanvasFileState::NEW); + } + + if (graphCanvasGraphId.IsValid()) + { + GraphCanvas::SceneNotificationBus::MultiHandler::BusConnect(graphCanvasGraphId); + GraphCanvas::SceneMimeDelegateRequestBus::Event(graphCanvasGraphId, &GraphCanvas::SceneMimeDelegateRequests::AddDelegate, m_entityMimeDelegateId); + + GraphCanvas::SceneRequestBus::Event(graphCanvasGraphId, &GraphCanvas::SceneRequests::SetMimeType, Widget::NodePaletteDockWidget::GetMimeType()); + GraphCanvas::SceneMemberNotificationBus::Event(graphCanvasGraphId, &GraphCanvas::SceneMemberNotifications::OnSceneReady); + } + + if (IsTabOpen(handle, outTabIndex)) + { + RefreshActiveAsset(); + } + + PopPreventUndoStateUpdate(); + + + GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId + , &GraphCanvas::AssetEditorNotifications::OnGraphLoaded, graphCanvasGraphId); + + return AZ::Success(outTabIndex); } bool MainWindow::OnFileSave() @@ -1942,16 +1951,8 @@ namespace ScriptCanvasEditor } else { - // #sc_editor_asset this seems to remove the unsaved indicator even on failure - - // Use the previous memory asset to find what we had setup as our display - // AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeGraph); - - // Drop off our file modifier status for our display name when we fail to save. -// if (tabName.at(tabName.size() -1) == '*') -// { -// tabName = tabName.substr(0, tabName.size() - 2); -// } + const auto failureMessage = AZStd::string::format("Failed to save %s: %s", tabName.c_str(), result.fileSaveError.c_str()); + QMessageBox::critical(this, QString(), QObject::tr(failureMessage.data())); } if (m_tabBar->currentIndex() != saveTabIndex) @@ -2717,69 +2718,25 @@ namespace ScriptCanvasEditor void MainWindow::OnTabCloseButtonPressed(int index) { - QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) { - auto fileAssetId = tabdata.value(); - - Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::NEW; - bool isSaving = false; - - // #sc_editor_asset Get from widgets - /* - AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, fileAssetId); - AssetTrackerRequestBus::BroadcastResult(isSaving, &AssetTrackerRequests::IsSaving, fileAssetId); - */ - if (isSaving) - { - m_closeCurrentGraphAfterSave = true; - return; - } - + Widget::GraphTabMetadata tabMetadata = tabdata.value(); + Tracker::ScriptCanvasFileState fileState = tabMetadata.m_fileState; UnsavedChangesOptions saveDialogResults = UnsavedChangesOptions::CONTINUE_WITHOUT_SAVING; - if (!isSaving && (fileState == Tracker::ScriptCanvasFileState::NEW || fileState == Tracker::ScriptCanvasFileState::MODIFIED || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED)) + + if (fileState == Tracker::ScriptCanvasFileState::NEW + || fileState == Tracker::ScriptCanvasFileState::MODIFIED + || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED) { - SetActiveAsset(fileAssetId.m_assetId); - - // #sc_editor_asset - AZStd::string tabName = "Get from widget"; - // AssetTrackerRequestBus::BroadcastResult(tabName, &AssetTrackerRequests::GetTabName, fileAssetId); - - saveDialogResults = ShowSaveDialog(tabName.c_str()); + SetActiveAsset(tabMetadata.m_assetId); + saveDialogResults = ShowSaveDialog(m_tabBar->tabText(index).toUtf8().constData()); } if (saveDialogResults == UnsavedChangesOptions::SAVE) { - // #sc_editor_asset -// auto saveCB = [this](bool isSuccessful, AZ::Data::AssetPtr asset, ScriptCanvasEditor::SourceHandle) -// { -// if (isSuccessful) -// { -// ScriptCanvasMemoryAsset::pointer memoryAsset; -// AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, asset->GetId()); -// AZ_Assert(memoryAsset, "At this point we must have a MemoryAsset"); -// -// int tabIndex = -1; -// if (IsTabOpen(memoryAsset->GetFileAssetId(), tabIndex)) -// { -// OnTabCloseRequest(tabIndex); -// } -// } -// else -// { -// QMessageBox::critical(this, QString(), QObject::tr("Failed to save.")); -// } -// }; -// -// if (fileState == Tracker::ScriptCanvasFileState::NEW) -// { -// SaveAssetImpl(fileAssetId, saveCB); -// } -// else -// { -// SaveAsset(fileAssetId, saveCB); -// } + m_closeCurrentGraphAfterSave = true; + SaveAssetImpl(tabMetadata.m_assetId, fileState == Tracker::ScriptCanvasFileState::NEW ? Save::As : Save::InPlace); } else if (saveDialogResults == UnsavedChangesOptions::CONTINUE_WITHOUT_SAVING) { diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h index 6704c10fda..7c527a5449 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h @@ -437,9 +437,7 @@ namespace ScriptCanvasEditor const NodePaletteModelInformation* FindNodePaletteModelInformation(const ScriptCanvas::NodeTypeIdentifier& nodeType) const override; //// - AZ::Outcome CreateScriptCanvasAsset(AZStd::string_view assetPath, AZ::Data::AssetType assetType, int tabIndex = -1); - AZ::Outcome UpdateScriptCanvasAsset(const AZ::Data::Asset& scriptCanvasAsset); - + AZ::Outcome CreateScriptCanvasAsset(AZStd::string_view assetPath, int tabIndex = -1); void RefreshScriptCanvasAsset(const AZ::Data::Asset& scriptCanvasAsset); //! Removes the assetId -> ScriptCanvasAsset mapping and disconnects from the asset tracker @@ -647,31 +645,6 @@ namespace ScriptCanvasEditor void OpenNextFile(); - template - void MakeNewFile() - { - static int scriptCanvasEditorDefaultNewNameCount = 0; - - AZStd::string newAssetName = AZStd::string::format(ScriptCanvas::AssetDescription::GetAssetNamePattern(), ++scriptCanvasEditorDefaultNewNameCount); - - AZStd::array assetRootArray; - if (!AZ::IO::FileIOBase::GetInstance()->ResolvePath(ScriptCanvas::AssetDescription::GetSuggestedSavePath(), assetRootArray.data(), assetRootArray.size())) - { - AZ_ErrorOnce("Script Canvas", false, "Unable to resolve @projectroot@ path"); - } - - AZStd::string assetPath; - AzFramework::StringFunc::Path::Join(assetRootArray.data(), (newAssetName + ScriptCanvas::AssetDescription::GetExtension()).data(), assetPath); - - auto createOutcome = CreateScriptCanvasAsset(assetPath, azrtti_typeid()); - if (createOutcome) - { - } - else - { - AZ_Warning("Script Canvas", createOutcome, "%s", createOutcome.GetError().data()); - } - } void DisableAssetView(const ScriptCanvasEditor::SourceHandle& memoryAssetId); void EnableAssetView(const ScriptCanvasEditor::SourceHandle& memoryAssetId); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp index 064029eb03..761f30f88b 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp @@ -203,6 +203,15 @@ namespace ScriptCanvasEditor , m_path(path) {} + SourceHandle::~SourceHandle() + { + AZ_TracePrintf("ScriptCanvas", "Destroy Handle: %p, count %d", m_data.get(), m_data.use_count()); + if (m_data.use_count() <= 1) + { + AZ_TracePrintf("ScriptCanvas", "BOOM Handle: %p, count %d", m_data.get(), m_data.use_count()); + } + } + bool SourceHandle::AnyEquals(const SourceHandle& other) const { return m_data == other.m_data diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h index ece7008b06..53a0ecdeb3 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h @@ -330,6 +330,8 @@ namespace ScriptCanvasEditor SourceHandle(ScriptCanvas::DataPtr graph, const AZ::Uuid& id, AZStd::string_view path); + ~SourceHandle(); + bool AnyEquals(const SourceHandle& other) const; void Clear(); From eefc3f9a9182e1032bd6b16cf1f1e18631ffa835 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 10 Nov 2021 16:40:33 -0800 Subject: [PATCH 013/128] new source file close button works, but not on multiple tabs Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Editor/View/Windows/MainWindow.cpp | 54 +++++++++---------- .../Code/Include/ScriptCanvas/Core/Core.cpp | 9 ---- .../Code/Include/ScriptCanvas/Core/Core.h | 2 +- 3 files changed, 25 insertions(+), 40 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index 5f1b59a23c..0e4945483e 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -1264,38 +1264,27 @@ namespace ScriptCanvasEditor return m_tabBar->InsertGraphTab(tabIndex, assetId); } - void MainWindow::RemoveScriptCanvasAsset(const ScriptCanvasEditor::SourceHandle& /*assetId*/) + void MainWindow::RemoveScriptCanvasAsset(const ScriptCanvasEditor::SourceHandle& assetId) { - // #sc_editor_asset move what is necessary to the widget - /* - AssetHelpers::PrintInfo("RemoveScriptCanvasAsset : %s", AssetHelpers::AssetIdToString(assetId).c_str()); - + AssetHelpers::PrintInfo("RemoveScriptCanvasAsset : %s", assetId.ToString().c_str()); m_assetCreationRequests.erase(assetId); - GeneralAssetNotificationBus::Event(assetId, &GeneralAssetNotifications::OnAssetUnloaded); - AssetTrackerNotificationBus::MultiHandler::BusDisconnect(assetId); - - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); - - if (memoryAsset) + if (assetId) { // Disconnect scene and asset editor buses - GraphCanvas::SceneNotificationBus::MultiHandler::BusDisconnect(memoryAsset->GetScriptCanvasId()); - GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId, &GraphCanvas::AssetEditorNotifications::OnGraphUnloaded, memoryAsset->GetGraphId()); + GraphCanvas::SceneNotificationBus::MultiHandler::BusDisconnect(assetId.Get()->GetScriptCanvasId()); + GraphCanvas::AssetEditorNotificationBus::Event(ScriptCanvasEditor::AssetEditorId + , &GraphCanvas::AssetEditorNotifications::OnGraphUnloaded, assetId.Get()->GetGraphCanvasGraphId()); } - AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::Close, assetId); - int tabIndex = m_tabBar->FindTab(assetId); QVariant tabdata = m_tabBar->tabData(tabIndex); if (tabdata.isValid()) { auto tabAssetId = tabdata.value(); - SetActiveAsset(tabAssetId); + SetActiveAsset(tabAssetId.m_assetId); } - */ } int MainWindow::CloseScriptCanvasAsset(const ScriptCanvasEditor::SourceHandle& assetId) @@ -1769,6 +1758,7 @@ namespace ScriptCanvasEditor } PrepareAssetForSave(inMemoryAssetId); + ScriptCanvasAssetDescription assetDescription; AZStd::string suggestedFilename; AZStd::string suggestedFileFilter; @@ -1807,7 +1797,6 @@ namespace ScriptCanvasEditor // So we want to break out. if (!selectedFile.isEmpty()) { - ScriptCanvasAssetDescription assetDescription; AZStd::string filePath = selectedFile.toUtf8().data(); if (!AZ::StringFunc::EndsWith(filePath, assetDescription.GetExtensionImpl(), false)) @@ -1848,6 +1837,12 @@ namespace ScriptCanvasEditor { AZStd::string internalStringFile = selectedFile.toUtf8().data(); + + if (!AZ::StringFunc::EndsWith(internalStringFile, assetDescription.GetExtensionImpl(), false)) + { + internalStringFile += assetDescription.GetExtensionImpl(); + } + if (!AssetHelpers::IsValidSourceFile(internalStringFile, GetActiveScriptCanvasId())) { QMessageBox::warning(this, "Unable to Save", QString("File\n'%1'\n\nDoes not match the asset type of the current Graph.").arg(selectedFile)); @@ -2843,32 +2838,32 @@ namespace ScriptCanvasEditor } } - void MainWindow::OnTabCloseRequest(int /*index*/) + void MainWindow::OnTabCloseRequest(int index) { - /* QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) { auto tabAssetId = tabdata.value(); - if (tabAssetId == m_activeGraph) + + if (tabAssetId.m_canvasWidget) { - SetActiveAsset({}); + tabAssetId.m_canvasWidget->hide(); } - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, tabAssetId); + bool activeSet = false; - if (memoryAsset && memoryAsset->GetView()) + if (tabAssetId.m_assetId == m_activeGraph) { - memoryAsset->GetView()->hide(); + SetActiveAsset({}); + activeSet = true; } m_tabBar->CloseTab(index); m_tabBar->update(); - RemoveScriptCanvasAsset(tabAssetId); + RemoveScriptCanvasAsset(tabAssetId.m_assetId); - if (m_tabBar->count() == 0) + if (!activeSet && m_tabBar->count() == 0) { // The last tab has been removed. SetActiveAsset({}); @@ -2879,7 +2874,6 @@ namespace ScriptCanvasEditor // information AddSystemTickAction(SystemTickActionFlag::CloseNextTabAction); } - */ } void MainWindow::OnNodeAdded(const AZ::EntityId& nodeId, bool isPaste) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp index 761f30f88b..064029eb03 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp @@ -203,15 +203,6 @@ namespace ScriptCanvasEditor , m_path(path) {} - SourceHandle::~SourceHandle() - { - AZ_TracePrintf("ScriptCanvas", "Destroy Handle: %p, count %d", m_data.get(), m_data.use_count()); - if (m_data.use_count() <= 1) - { - AZ_TracePrintf("ScriptCanvas", "BOOM Handle: %p, count %d", m_data.get(), m_data.use_count()); - } - } - bool SourceHandle::AnyEquals(const SourceHandle& other) const { return m_data == other.m_data diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h index 53a0ecdeb3..415c181033 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h @@ -330,7 +330,7 @@ namespace ScriptCanvasEditor SourceHandle(ScriptCanvas::DataPtr graph, const AZ::Uuid& id, AZStd::string_view path); - ~SourceHandle(); + ~SourceHandle() = default; bool AnyEquals(const SourceHandle& other) const; From 47e9d5a1175197f9860640c3dbf098aaea9284c6 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 10 Nov 2021 17:15:42 -0800 Subject: [PATCH 014/128] multi tab close fixed Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Assets/ScriptCanvasFileHandling.cpp | 2 +- .../Code/Editor/View/Widgets/GraphTabBar.cpp | 5 +-- .../Code/Editor/View/Windows/MainWindow.cpp | 32 +++++++++---------- .../Code/Include/ScriptCanvas/Core/Core.cpp | 17 +++++++--- .../Code/Include/ScriptCanvas/Core/Core.h | 6 ++-- 5 files changed, 35 insertions(+), 27 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp index 4af7ff247e..cd8d21543f 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp @@ -144,7 +144,7 @@ namespace ScriptCanvasEditor { namespace JSRU = AZ::JsonSerializationUtils; - if (!source) + if (!source.IsValid()) { return AZ::Failure(AZStd::string("no source graph to save")); } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp index 029d713277..1dfb27ce63 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp @@ -194,7 +194,7 @@ namespace ScriptCanvasEditor if (tabDataVariant.isValid()) { auto tabAssetId = tabDataVariant.value(); - if (tabAssetId.m_assetId == assetId) + if (tabAssetId.m_assetId.AnyEquals(assetId)) { return tabIndex; } @@ -243,7 +243,8 @@ namespace ScriptCanvasEditor if (tabdata.isValid()) { auto tabAssetId = tabdata.value(); - if (tabAssetId.m_assetId && tabAssetId.m_assetId.Get()->GetGraphCanvasGraphId() == graphCanvasGraphId) + if (tabAssetId.m_assetId.IsValid() + && tabAssetId.m_assetId.Get()->GetGraphCanvasGraphId() == graphCanvasGraphId) { return tabAssetId.m_assetId.Get()->GetScriptCanvasId(); } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index 0e4945483e..44a67ac816 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -260,7 +260,7 @@ namespace ScriptCanvasEditor activeAssets.push_back(assetSaveData); } } - else if (assetId == focusedAssetId) + else if (assetId.AnyEquals(focusedAssetId)) { focusedAssetId.Clear(); } @@ -820,7 +820,7 @@ namespace ScriptCanvasEditor void MainWindow::SignalActiveSceneChanged(ScriptCanvasEditor::SourceHandle assetId) { AZ::EntityId graphId; - if (assetId) + if (assetId.IsValid()) { EditorGraphRequestBus::EventResult(graphId, assetId.Get()->GetScriptCanvasId(), &EditorGraphRequests::GetGraphCanvasGraphId); } @@ -1249,7 +1249,7 @@ namespace ScriptCanvasEditor AZ::Outcome MainWindow::OpenScriptCanvasAsset(ScriptCanvasEditor::SourceHandle scriptCanvasAssetId, int tabIndex) { - if (scriptCanvasAssetId) + if (scriptCanvasAssetId.IsValid()) { return OpenScriptCanvasAssetImplementation(scriptCanvasAssetId, tabIndex); } @@ -1270,7 +1270,7 @@ namespace ScriptCanvasEditor m_assetCreationRequests.erase(assetId); GeneralAssetNotificationBus::Event(assetId, &GeneralAssetNotifications::OnAssetUnloaded); - if (assetId) + if (assetId.IsValid()) { // Disconnect scene and asset editor buses GraphCanvas::SceneNotificationBus::MultiHandler::BusDisconnect(assetId.Get()->GetScriptCanvasId()); @@ -1312,7 +1312,7 @@ namespace ScriptCanvasEditor OnFileNew(); - bool createdNewAsset = m_activeGraph != previousAssetId; + bool createdNewAsset = !(m_activeGraph.AnyEquals(previousAssetId)); if (createdNewAsset) { @@ -1752,7 +1752,7 @@ namespace ScriptCanvasEditor return false; } - if (m_activeGraph != inMemoryAssetId) + if (!m_activeGraph.AnyEquals(inMemoryAssetId)) { OnChangeActiveGraphTab(inMemoryAssetId); } @@ -2487,7 +2487,7 @@ namespace ScriptCanvasEditor { AZ::EntityId graphId{}; - if (m_activeGraph) + if (m_activeGraph.IsValid()) { EditorGraphRequestBus::EventResult ( graphId, m_activeGraph.Get()->GetScriptCanvasId(), &EditorGraphRequests::GetGraphCanvasGraphId); @@ -2512,7 +2512,7 @@ namespace ScriptCanvasEditor { AZ::EntityId graphId{}; - if (assetId) + if (assetId.IsValid()) { EditorGraphRequestBus::EventResult ( graphId, assetId.Get()->GetScriptCanvasId(), &EditorGraphRequests::GetGraphCanvasGraphId); @@ -2523,7 +2523,7 @@ namespace ScriptCanvasEditor ScriptCanvas::ScriptCanvasId MainWindow::FindScriptCanvasIdByAssetId(const ScriptCanvasEditor::SourceHandle& assetId) const { - return assetId ? assetId.Get()->GetScriptCanvasId() : ScriptCanvas::ScriptCanvasId{}; + return assetId.IsValid() ? assetId.Get()->GetScriptCanvasId() : ScriptCanvas::ScriptCanvasId{}; } ScriptCanvas::ScriptCanvasId MainWindow::GetScriptCanvasId(const GraphCanvas::GraphId& graphCanvasGraphId) const @@ -2566,7 +2566,7 @@ namespace ScriptCanvasEditor if (tabdata.isValid()) { auto tabAssetId = tabdata.value(); - if (tabAssetId.m_assetId == assetId) + if (tabAssetId.m_assetId.AnyEquals(assetId)) { return tabdata; } @@ -2592,14 +2592,14 @@ namespace ScriptCanvasEditor // Disconnect previous asset AZ::EntityId previousScriptCanvasSceneId; - if (previousAsset) + if (previousAsset.IsValid()) { previousScriptCanvasSceneId = previousAsset.Get()->GetScriptCanvasId(); GraphCanvas::SceneNotificationBus::MultiHandler::BusDisconnect(previousScriptCanvasSceneId); } AZ::EntityId nextAssetGraphCanvasId; - if (nextAsset) + if (nextAsset.IsValid()) { // Connect the next asset EditorGraphRequestBus::EventResult(nextAssetGraphCanvasId, nextAsset.Get()->GetScriptCanvasId(), &EditorGraphRequests::GetGraphCanvasGraphId); @@ -2620,9 +2620,7 @@ namespace ScriptCanvasEditor void MainWindow::SetActiveAsset(const ScriptCanvasEditor::SourceHandle& fileAssetId) { - // #sc_editor_asset - - if (m_activeGraph == fileAssetId) + if (m_activeGraph.AnyEquals(fileAssetId)) { return; } @@ -2825,7 +2823,7 @@ namespace ScriptCanvasEditor { auto assetId = tabdata.value(); - if (assetId.m_assetId != m_skipTabOnClose) + if (!assetId.m_assetId.AnyEquals(m_skipTabOnClose)) { break; } @@ -2853,7 +2851,7 @@ namespace ScriptCanvasEditor bool activeSet = false; - if (tabAssetId.m_assetId == m_activeGraph) + if (tabAssetId.m_assetId.AnyEquals(m_activeGraph)) { SetActiveAsset({}); activeSet = true; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp index 064029eb03..829a25f3d1 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp @@ -229,7 +229,7 @@ namespace ScriptCanvasEditor bool SourceHandle::IsValid() const { - return *this; + return m_data != nullptr; } GraphPtr SourceHandle::Mod() const @@ -237,14 +237,16 @@ namespace ScriptCanvasEditor return m_data ? m_data->ModEditorGraph() : nullptr; } - SourceHandle::operator bool() const + bool SourceHandle::operator==(const SourceHandle& other) const { - return m_data != nullptr; + return m_data.get() == other.m_data.get() + && m_id == other.m_id + && m_path == other.m_path; } - bool SourceHandle::operator!() const + bool SourceHandle::operator!=(const SourceHandle& other) const { - return m_data == nullptr; + return !(*this == other); } const AZStd::string& SourceHandle::Path() const @@ -252,6 +254,11 @@ namespace ScriptCanvasEditor return m_path; } + bool SourceHandle::PathEquals(const SourceHandle& other) const + { + return m_path == other.m_path; + } + AZStd::string SourceHandle::ToString() const { return AZStd::string::format diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h index 415c181033..8d7dc40866 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h @@ -344,12 +344,14 @@ namespace ScriptCanvasEditor GraphPtr Mod() const; - operator bool() const; + bool operator==(const SourceHandle& other) const; - bool operator!() const; + bool operator!=(const SourceHandle& other) const; const AZStd::string& Path() const; + bool PathEquals(const SourceHandle& other) const; + AZStd::string ToString() const; private: From 737ed1b0322c48a1f678879ab55d664fc1e9ebfd Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Thu, 11 Nov 2021 10:36:55 -0800 Subject: [PATCH 015/128] restore source file deleted behavior Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Editor/View/Windows/MainWindow.cpp | 17 ++++++++++++----- .../Code/Editor/View/Windows/MainWindow.h | 4 +++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index 44a67ac816..987f8de6ca 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -662,7 +662,7 @@ namespace ScriptCanvasEditor ScriptCanvas::BatchOperationNotificationBus::Handler::BusConnect(); AssetGraphSceneBus::Handler::BusConnect(); AzToolsFramework::ToolsApplicationNotificationBus::Handler::BusConnect(); - + AzToolsFramework::AssetSystemBus::Handler::BusConnect(); ScriptCanvas::ScriptCanvasSettingsRequestBus::Handler::BusConnect(); UINotificationBus::Broadcast(&UINotifications::MainWindowCreationEvent, this); @@ -706,6 +706,7 @@ namespace ScriptCanvasEditor ScriptCanvasEditor::GeneralRequestBus::Handler::BusDisconnect(); GraphCanvas::AssetEditorAutomationRequestBus::Handler::BusDisconnect(); ScriptCanvas::ScriptCanvasSettingsRequestBus::Handler::BusDisconnect(); + AzToolsFramework::AssetSystemBus::Handler::BusDisconnect(); Clear(); @@ -1109,6 +1110,15 @@ namespace ScriptCanvasEditor RestartAutoTimerSave(forceTimer); } + void MainWindow::SourceFileRemoved + ( AZStd::string relativePath + , [[maybe_unused]] AZStd::string scanFolder + , [[maybe_unused]] AZ::Uuid fileAssetId) + { + ScriptCanvasEditor::SourceHandle handle(nullptr, fileAssetId, relativePath); + UpdateFileState(handle, Tracker::ScriptCanvasFileState::SOURCE_REMOVED); + } + void MainWindow::SignalSceneDirty(ScriptCanvasEditor::SourceHandle assetId) { UpdateFileState(assetId, Tracker::ScriptCanvasFileState::MODIFIED); @@ -2533,7 +2543,6 @@ namespace ScriptCanvasEditor bool MainWindow::IsInUndoRedo(const AZ::EntityId& graphCanvasGraphId) const { - // #sc_editor_asset bool isActive = false; UndoRequestBus::EventResult(isActive, GetScriptCanvasId(graphCanvasGraphId), &UndoRequests::IsActive); return isActive; @@ -2588,12 +2597,10 @@ namespace ScriptCanvasEditor void MainWindow::ReconnectSceneBuses(ScriptCanvasEditor::SourceHandle previousAsset, ScriptCanvasEditor::SourceHandle nextAsset) { - // #sc_editor_asset - // Disconnect previous asset AZ::EntityId previousScriptCanvasSceneId; if (previousAsset.IsValid()) - { + { previousScriptCanvasSceneId = previousAsset.Get()->GetScriptCanvasId(); GraphCanvas::SceneNotificationBus::MultiHandler::BusDisconnect(previousScriptCanvasSceneId); } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h index 7c527a5449..dfe5d9fa13 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h @@ -231,7 +231,6 @@ namespace ScriptCanvasEditor , private VariablePaletteRequestBus::Handler , private ScriptCanvas::BatchOperationNotificationBus::Handler , private AssetGraphSceneBus::Handler - //, private AssetTrackerNotificationBus::MultiHandler #if SCRIPTCANVAS_EDITOR //, public IEditorNotifyListener #endif @@ -240,6 +239,7 @@ namespace ScriptCanvasEditor , private GraphCanvas::ViewNotificationBus::Handler , public AZ::SystemTickBus::Handler , private AzToolsFramework::ToolsApplicationNotificationBus::Handler + , private AzToolsFramework::AssetSystemBus::Handler , private ScriptCanvas::ScriptCanvasSettingsRequestBus::Handler { Q_OBJECT @@ -525,6 +525,8 @@ namespace ScriptCanvasEditor AZ::EntityId FindAssetNodeIdByEditorNodeId(const ScriptCanvasEditor::SourceHandle& assetId, AZ::EntityId editorNodeId) const override; private: + void SourceFileRemoved(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid fileAssetId) override; + void DeleteNodes(const AZ::EntityId& sceneId, const AZStd::vector& nodes) override; void DeleteConnections(const AZ::EntityId& sceneId, const AZStd::vector& connections) override; void DisconnectEndpoints(const AZ::EntityId& sceneId, const AZStd::vector& endpoints) override; From d9622e74ab188de660a95569d17f7dcd73f733db Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Thu, 11 Nov 2021 12:18:50 -0800 Subject: [PATCH 016/128] make default names NOT the default name of a previously existing file Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Editor/View/Windows/MainWindow.cpp | 128 ++++++++++-------- 1 file changed, 74 insertions(+), 54 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index 987f8de6ca..27fd7c8cf8 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -1591,27 +1591,33 @@ namespace ScriptCanvasEditor void MainWindow::OnFileNew() { - static int scriptCanvasEditorDefaultNewNameCount = 0; - - ScriptCanvasAssetDescription description; - - AZStd::string newAssetName = AZStd::string::format(description.GetAssetNamePatternImpl(), ++scriptCanvasEditorDefaultNewNameCount); - - AZStd::array assetRootArray; - if (!AZ::IO::FileIOBase::GetInstance()->ResolvePath(description.GetSuggestedSavePathImpl() - , assetRootArray.data(), assetRootArray.size())) - { - AZ_ErrorOnce("Script Canvas", false, "Unable to resolve @projectroot@ path"); - } + int scriptCanvasEditorDefaultNewNameCount = 0; AZStd::string assetPath; - AzFramework::StringFunc::Path::Join(assetRootArray.data(), (newAssetName + description.GetExtensionImpl()).data(), assetPath); + + for (;;) + { + ScriptCanvasAssetDescription description; + AZStd::string newAssetName = AZStd::string::format(description.GetAssetNamePatternImpl(), ++scriptCanvasEditorDefaultNewNameCount); + + AZStd::array assetRootArray; + if (!AZ::IO::FileIOBase::GetInstance()->ResolvePath(description.GetSuggestedSavePathImpl() + , assetRootArray.data(), assetRootArray.size())) + { + AZ_ErrorOnce("Script Canvas", false, "Unable to resolve @projectroot@ path"); + } + + AzFramework::StringFunc::Path::Join(assetRootArray.data(), (newAssetName + description.GetExtensionImpl()).data(), assetPath); + AZ::Data::AssetInfo assetInfo; + + if (!AssetHelpers::GetAssetInfo(assetPath, assetInfo)) + { + break; + } + } auto createOutcome = CreateScriptCanvasAsset(assetPath); - if (createOutcome) - { - } - else + if (!createOutcome.IsSuccess()) { AZ_Warning("Script Canvas", createOutcome, "%s", createOutcome.GetError().data()); } @@ -1869,7 +1875,6 @@ namespace ScriptCanvasEditor return false; } - void MainWindow::OnSaveCallBack(const VersionExplorer::FileSaveResult& result) { const bool saveSuccess = result.fileSaveError.empty(); @@ -1881,8 +1886,28 @@ namespace ScriptCanvasEditor { // #sc_editor_asset find a tab with the same path name and close non focused old ones with the same name // Update the editor with the new information about this asset. - const ScriptCanvasEditor::SourceHandle& fileAssetId = memoryAsset; + ScriptCanvasEditor::SourceHandle& fileAssetId = memoryAsset; int currentTabIndex = m_tabBar->currentIndex(); + + AZ::Data::AssetId oldId = fileAssetId.Id(); + AZ::Data::AssetInfo assetInfo; + assetInfo.m_assetId = fileAssetId.Id(); + AZ_VerifyWarning("ScriptCanvas", AssetHelpers::GetAssetInfo(fileAssetId.Path(), assetInfo) + , "Failed to find asset info for source file just saved: %s", fileAssetId.Path().c_str()); + + const bool assetIdHasChanged = assetInfo.m_assetId.m_guid != fileAssetId.Id(); + fileAssetId = SourceHandle(fileAssetId, assetInfo.m_assetId.m_guid, fileAssetId.Path()); + + // #sc_editor_asset + // check for saving a graph over another graph with an open tab + { + // find the saved tab by graph* + // find all tabs that match old path, and close them + // update the save tab index + // and the current index + } + + // this path is questionable, this is a save request that is not the current graph // We've saved as over a new graph, so we need to close the old one. if (saveTabIndex != currentTabIndex) { @@ -1906,52 +1931,47 @@ namespace ScriptCanvasEditor } AzFramework::StringFunc::Path::GetFileName(memoryAsset.Path().c_str(), tabName); - // Update the tab's assetId to the file asset Id (necessary when saving a new asset) // #sc_editor_asset used to be configure tab...sets the name and file state - // m_tabBar->ConfigureTab(saveTabIndex, fileAssetId, tabName); -// GeneralAssetNotificationBus::Event(memoryAsset, &GeneralAssetNotifications::OnAssetVisualized); -// -// auto requestorIter = m_assetCreationRequests.find(fileAsset->GetId()); -// -// if (requestorIter != m_assetCreationRequests.end()) -// { -// auto editorComponents = AZ::EntityUtils::FindDerivedComponents(requestorIter->second.first); -// -// if (editorComponents.empty()) -// { -// auto firstRequestBus = EditorScriptCanvasComponentRequestBus::FindFirstHandler(requestorIter->second.first); -// -// if (firstRequestBus) -// { -// firstRequestBus->SetAssetId(fileAsset->GetId()); -// } -// } -// else -// { -// for (auto editorComponent : editorComponents) -// { -// if (editorComponent->GetId() == requestorIter->second.second) -// { -// editorComponent->SetAssetId(fileAsset->GetId()); -// break; -// } -// } -// } -// -// m_assetCreationRequests.erase(requestorIter); -// } + if (assetIdHasChanged) + { + auto entity = memoryAsset.Get()->GetEntity(); + + auto editorComponents = AZ::EntityUtils::FindDerivedComponents(entity); + + if (editorComponents.empty()) + { + if (auto firstRequestBus = EditorScriptCanvasComponentRequestBus::FindFirstHandler(entity->GetId())) + { + firstRequestBus->SetAssetId(memoryAsset.Id()); + } + } + else + { + for (auto editorComponent : editorComponents) + { + if (editorComponent->GetAssetId() == oldId) + { + editorComponent->SetAssetId(memoryAsset.Id()); + break; + } + } + } + } // Soft switch the asset id here. We'll do a double scene switch down below to actually switch the active assetid m_activeGraph = fileAssetId; - if (tabName.at(tabName.size() - 1) == '*') + if (tabName.at(tabName.size() - 1) == '*' || tabName.at(tabName.size() - 1) == '^') { tabName = tabName.substr(0, tabName.size() - 2); } - m_tabBar->UpdateFileState(fileAssetId, Tracker::ScriptCanvasFileState::UNMODIFIED); + auto tabData = m_tabBar->GetTabData(saveTabIndex); + tabData->m_fileState = Tracker::ScriptCanvasFileState::UNMODIFIED; + tabData->m_assetId = fileAssetId; + m_tabBar->SetTabData(*tabData, saveTabIndex); m_tabBar->SetTabText(saveTabIndex, tabName.c_str()); } else From 89a97a5e49d67ecd4b5d68add8315c7cf03ae593 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Fri, 12 Nov 2021 09:33:39 -0800 Subject: [PATCH 017/128] fix scoped compile error Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- Gems/ScriptCanvas/Code/Editor/Nodes/NodeDisplayUtils.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Nodes/NodeDisplayUtils.cpp b/Gems/ScriptCanvas/Code/Editor/Nodes/NodeDisplayUtils.cpp index a59e8497fe..158bfae9a0 100644 --- a/Gems/ScriptCanvas/Code/Editor/Nodes/NodeDisplayUtils.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Nodes/NodeDisplayUtils.cpp @@ -320,7 +320,7 @@ namespace ScriptCanvasEditor::Nodes if (methodNode->HasBusID() && busId == slot.GetId() && slot.GetDescriptor() == ScriptCanvas::SlotDescriptors::DataIn()) { - key = Translation::GlobalKeys::EBusSenderIDKey; + key = ::Translation::GlobalKeys::EBusSenderIDKey; GraphCanvas::TranslationRequestBus::BroadcastResult(details, &GraphCanvas::TranslationRequests::GetDetails, key + ".details", details); } else @@ -428,7 +428,7 @@ namespace ScriptCanvasEditor::Nodes if (busNode->IsIDRequired() && slot->GetDescriptor() == ScriptCanvas::SlotDescriptors::DataIn()) { GraphCanvas::TranslationKey key; - key << Translation::GlobalKeys::EBusHandlerIDKey << "details"; + key << ::Translation::GlobalKeys::EBusHandlerIDKey << "details"; GraphCanvas::TranslationRequests::Details details; details.m_name = slot->GetName(); details.m_tooltip = slot->GetToolTip(); @@ -618,7 +618,7 @@ namespace ScriptCanvasEditor::Nodes if (busNode->IsIDRequired() && slot->GetDescriptor() == ScriptCanvas::SlotDescriptors::DataIn()) { GraphCanvas::TranslationKey key; - key << Translation::GlobalKeys::EBusHandlerIDKey << "details"; + key << ::Translation::GlobalKeys::EBusHandlerIDKey << "details"; GraphCanvas::TranslationRequests::Details details; GraphCanvas::TranslationRequestBus::BroadcastResult(details, &GraphCanvas::TranslationRequests::GetDetails, key, details); GraphCanvas::SlotRequestBus::Event(gcSlotId, &GraphCanvas::SlotRequests::SetDetails, details.m_name, details.m_tooltip); From 0e7d732c612ade28531c294bd2e7e104cc80355b Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Mon, 15 Nov 2021 17:15:05 -0800 Subject: [PATCH 018/128] fix upgrade scanner Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Editor/Components/EditorGraph.cpp | 2 +- .../Code/Editor/Components/GraphUpgrade.cpp | 5 +- .../ScriptCanvas/Bus/EditorScriptCanvasBus.h | 4 +- .../ScriptCanvas/Components/EditorGraph.h | 2 +- .../Components/EditorScriptCanvasComponent.h | 2 + .../ScriptCanvas/Components/GraphUpgrade.h | 4 +- .../Code/Editor/View/Windows/MainWindow.cpp | 10 +- .../Windows/Tools/UpgradeTool/Controller.cpp | 142 ++++++------------ .../Windows/Tools/UpgradeTool/Controller.h | 30 ++-- .../Windows/Tools/UpgradeTool/FileSaver.cpp | 98 +----------- .../Windows/Tools/UpgradeTool/FileSaver.h | 4 +- .../View/Windows/Tools/UpgradeTool/Model.cpp | 6 +- .../Windows/Tools/UpgradeTool/ModelTraits.h | 52 +++---- .../Windows/Tools/UpgradeTool/Modifier.cpp | 57 +++---- .../View/Windows/Tools/UpgradeTool/Modifier.h | 8 +- .../Windows/Tools/UpgradeTool/Scanner.cpp | 103 ++++++++----- .../View/Windows/Tools/UpgradeTool/Scanner.h | 6 +- .../Tools/UpgradeTool/UpgradeHelper.cpp | 22 ++- .../Windows/Tools/UpgradeTool/UpgradeHelper.h | 4 +- .../Code/Include/ScriptCanvas/Core/Core.cpp | 12 +- .../Code/Include/ScriptCanvas/Core/Core.h | 22 +-- 21 files changed, 239 insertions(+), 356 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp index 45b51de270..8d02e61b7d 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp @@ -3490,7 +3490,7 @@ namespace ScriptCanvasEditor m_focusHelper.SetActiveGraph(GetGraphCanvasGraphId()); } - bool Graph::UpgradeGraph(const AZ::Data::Asset& asset, UpgradeRequest request, bool isVerbose) + bool Graph::UpgradeGraph(SourceHandle& asset, UpgradeRequest request, bool isVerbose) { m_upgradeSM.SetAsset(asset); m_upgradeSM.SetVerbose(isVerbose); diff --git a/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp b/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp index 0e5f11fa40..e64a47a753 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp @@ -675,19 +675,18 @@ namespace ScriptCanvasEditor RegisterState(ParseGraph); } - void EditorGraphUpgradeMachine::SetAsset(const AZ::Data::Asset& asset) + void EditorGraphUpgradeMachine::SetAsset(SourceHandle& asset) { if (m_asset != asset) { m_asset = asset; - SetDebugPrefix(asset.GetHint()); + SetDebugPrefix(asset.Path().c_str()); } } void EditorGraphUpgradeMachine::OnComplete(IState::ExitStatus exitStatus) { UpgradeNotificationsBus::Broadcast(&UpgradeNotifications::OnGraphUpgradeComplete, m_asset, exitStatus == IState::ExitStatus::Skipped); - m_asset = {}; } diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h index 7c57d661f0..b55e425d43 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h @@ -26,6 +26,8 @@ #include #include +#include + namespace GraphCanvas { class GraphCanvasTreeItem; @@ -223,7 +225,7 @@ namespace ScriptCanvasEditor virtual void OnUpgradeStart() {} virtual void OnUpgradeCancelled() {} - virtual void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped = false) { (void)skipped; } + virtual void OnGraphUpgradeComplete(SourceHandle&, bool skipped = false) { (void)skipped; } }; using UpgradeNotificationsBus = AZ::EBus; diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h index b5269cc45d..8a98601d54 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h @@ -237,7 +237,7 @@ namespace ScriptCanvasEditor IfOutOfDate, Forced }; - bool UpgradeGraph(const AZ::Data::Asset& asset, UpgradeRequest request, bool isVerbose = true); + bool UpgradeGraph(SourceHandle& asset, UpgradeRequest request, bool isVerbose = true); void ConnectGraphCanvasBuses(); void DisconnectGraphCanvasBuses(); /////// diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h index 87ffff8b19..1bdb4ccb85 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h @@ -37,6 +37,7 @@ namespace ScriptCanvasEditor , private EditorScriptCanvasComponentLoggingBus::Handler , private EditorScriptCanvasComponentRequestBus::Handler , private AssetTrackerNotificationBus::Handler + , private AzToolsFramework::AssetSystemBus::Handler , private AzToolsFramework::EditorEntityContextNotificationBus::Handler { @@ -44,6 +45,7 @@ namespace ScriptCanvasEditor AZ_COMPONENT(EditorScriptCanvasComponent, "{C28E2D29-0746-451D-A639-7F113ECF5D72}", AzToolsFramework::Components::EditorComponentBase); EditorScriptCanvasComponent(); + // EditorScriptCanvasComponent(AZ::Data::Asset asset); EditorScriptCanvasComponent(AZ::Data::Asset asset); ~EditorScriptCanvasComponent() override; diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/GraphUpgrade.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/GraphUpgrade.h index 817b883695..0e6e69c4bf 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/GraphUpgrade.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/GraphUpgrade.h @@ -184,9 +184,9 @@ namespace ScriptCanvasEditor bool m_graphNeedsDirtying = false; Graph* m_graph = nullptr; - AZ::Data::Asset m_asset; + SourceHandle m_asset; - void SetAsset(const AZ::Data::Asset& asset); + void SetAsset(SourceHandle& assetasset); void OnComplete(IState::ExitStatus exitStatus) override; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index 27fd7c8cf8..d43e509905 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -1207,7 +1207,7 @@ namespace ScriptCanvasEditor { if (!m_isRestoringWorkspace) { - AZStd::string errorPath = scriptCanvasAsset.Path(); + AZStd::string errorPath = scriptCanvasAsset.Path().c_str(); if (errorPath.empty()) { @@ -1245,7 +1245,7 @@ namespace ScriptCanvasEditor , fileAssetId.ToString().c_str())); } - AZStd::string assetPath = scriptCanvasAsset.Path(); + AZStd::string assetPath = scriptCanvasAsset.Path().c_str(); if (!assetPath.empty() && !m_loadingNewlySavedFile) { AddRecentFile(assetPath.c_str()); @@ -1784,7 +1784,7 @@ namespace ScriptCanvasEditor { isValidFileName = true; suggestedFileFilter = ScriptCanvasAssetDescription().GetExtensionImpl(); - suggestedFilename = inMemoryAssetId.Path(); + suggestedFilename = inMemoryAssetId.Path().c_str(); } else { @@ -1797,7 +1797,7 @@ namespace ScriptCanvasEditor } else { - suggestedFilename = inMemoryAssetId.Path(); + suggestedFilename = inMemoryAssetId.Path().c_str(); } } @@ -1892,7 +1892,7 @@ namespace ScriptCanvasEditor AZ::Data::AssetId oldId = fileAssetId.Id(); AZ::Data::AssetInfo assetInfo; assetInfo.m_assetId = fileAssetId.Id(); - AZ_VerifyWarning("ScriptCanvas", AssetHelpers::GetAssetInfo(fileAssetId.Path(), assetInfo) + AZ_VerifyWarning("ScriptCanvas", AssetHelpers::GetAssetInfo(fileAssetId.Path().c_str(), assetInfo) , "Failed to find asset info for source file just saved: %s", fileAssetId.Path().c_str()); const bool assetIdHasChanged = assetInfo.m_assetId.m_guid != fileAssetId.Id(); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp index dbcd176ee5..5189895a56 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp @@ -104,9 +104,9 @@ namespace ScriptCanvasEditor } } - QList Controller::FindTableItems(const AZ::Data::AssetInfo& info) + QList Controller::FindTableItems(const SourceHandle& info) { - return m_view->tableWidget->findItems(info.m_relativePath.c_str(), Qt::MatchFlag::MatchExactly); + return m_view->tableWidget->findItems(info.Path().c_str(), Qt::MatchFlag::MatchExactly); } void Controller::OnButtonPressClose() @@ -117,30 +117,20 @@ namespace ScriptCanvasEditor void Controller::OnButtonPressScan() { // \todo move to another file - auto isUpToDate = [this](AZ::Data::Asset asset) + auto isUpToDate = [this](const SourceHandle& asset) { - AZ::Entity* scriptCanvasEntity = nullptr; + auto graphComponent = asset.Get(); - if (asset.GetType() == azrtti_typeid()) - { - ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); - if (!scriptCanvasAsset) - { - AZ_Warning - (ScriptCanvas::k_VersionExplorerWindow.data() - , false - , "InspectAsset: %s, AsestData failed to return ScriptCanvasAsset" - , asset.GetHint().c_str()); - return true; - } + AZ_Warning + ( ScriptCanvas::k_VersionExplorerWindow.data() + , asset.Get() != nullptr + , "InspectAsset: %s, failed to load valid graph" + , asset.Path().c_str()); - scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "The Script Canvas asset must have a valid entity"); - } - - auto graphComponent = scriptCanvasEntity->FindComponent(); - AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); - return !m_view->forceUpgrade->isChecked() && graphComponent->GetVersion().IsLatest(); + return graphComponent + && (!graphComponent->GetVersion().IsLatest() || m_view->forceUpgrade->isChecked()) + ? ScanConfiguration::Filter::Include + : ScanConfiguration::Filter::Exclude; }; ScanConfiguration config; @@ -156,59 +146,19 @@ namespace ScriptCanvasEditor OnButtonPressUpgradeImplementation({}); } - void Controller::OnButtonPressUpgradeImplementation(const AZ::Data::AssetInfo& assetInfo) + void Controller::OnButtonPressUpgradeImplementation(const SourceHandle& assetInfo) { - auto simpleUpdate = [this](AZ::Data::Asset asset) + auto simpleUpdate = [this](SourceHandle& asset) { - if (asset.GetType() == azrtti_typeid()) + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), asset.Get() != nullptr + , "The Script Canvas asset must have a Graph component"); + + if (asset.Get()) { - ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); - AZ_Assert(scriptCanvasAsset, "Unable to get the asset of ScriptCanvasAsset, but received type: %s" - , azrtti_typeid().template ToString().c_str()); - if (!scriptCanvasAsset) - { - return; - } - - AZ::Entity* scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "View::UpgradeGraph The Script Canvas asset must have a valid entity"); - if (!scriptCanvasEntity) - { - return; - } - - AZ::Entity* queryEntity = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(queryEntity, &AZ::ComponentApplicationRequests::FindEntity, scriptCanvasEntity->GetId()); - if (queryEntity) - { - if (queryEntity->GetState() == AZ::Entity::State::Active) - { - queryEntity->Deactivate(); - } - - scriptCanvasEntity = queryEntity; - } - - if (scriptCanvasEntity->GetState() == AZ::Entity::State::Constructed) - { - scriptCanvasEntity->Init(); - } - - if (scriptCanvasEntity->GetState() == AZ::Entity::State::Init) - { - scriptCanvasEntity->Activate(); - } - - AZ_Assert(scriptCanvasEntity->GetState() == AZ::Entity::State::Active, "Graph entity is not active"); - auto graphComponent = scriptCanvasEntity->FindComponent(); - AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); - if (graphComponent) - { - graphComponent->UpgradeGraph - (asset - , m_view->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate - , m_view->verbose->isChecked()); - } + asset.Mod()->UpgradeGraph + ( asset + , m_view->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate + , m_view->verbose->isChecked()); } }; @@ -235,12 +185,12 @@ namespace ScriptCanvasEditor ModelRequestsBus::Broadcast(&ModelRequestsTraits::Modify, config); } - void Controller::OnButtonPressUpgradeSingle(const AZ::Data::AssetInfo& assetInfo) + void Controller::OnButtonPressUpgradeSingle(const SourceHandle& info) { - OnButtonPressUpgradeImplementation(assetInfo); + OnButtonPressUpgradeImplementation(info); } - void Controller::OnUpgradeModificationBegin([[maybe_unused]] const ModifyConfiguration& config, const AZ::Data::AssetInfo& info) + void Controller::OnUpgradeModificationBegin([[maybe_unused]] const ModifyConfiguration& config, const SourceHandle& info) { for (auto* item : FindTableItems(info)) { @@ -252,16 +202,16 @@ namespace ScriptCanvasEditor void Controller::OnUpgradeModificationEnd ( [[maybe_unused]] const ModifyConfiguration& config - , const AZ::Data::AssetInfo& info + , const SourceHandle& info , ModificationResult result) { if (result.errorMessage.empty()) { - VE_LOG("Successfully modified %s", result.assetInfo.m_relativePath.c_str()); + VE_LOG("Successfully modified %s", result.asset.Path().c_str()); } else { - VE_LOG("Failed to modify %s: %s", result.assetInfo.m_relativePath.c_str(), result.errorMessage.data()); + VE_LOG("Failed to modify %s: %s", result.asset.Path().c_str(), result.errorMessage.data()); } for (auto* item : FindTableItems(info)) @@ -289,12 +239,10 @@ namespace ScriptCanvasEditor AddLogEntries(); } - void Controller::OnGraphUpgradeComplete(AZ::Data::Asset& asset, bool skipped) + void Controller::OnGraphUpgradeComplete(ScriptCanvasEditor::SourceHandle& asset, bool skipped) { ModificationResult result; result.asset = asset; - AZ::Data::AssetCatalogRequestBus::BroadcastResult - ( result.assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, asset.GetId()); if (skipped) { @@ -342,19 +290,19 @@ namespace ScriptCanvasEditor } } - void Controller::OnScanFilteredGraph(const AZ::Data::AssetInfo& info) + void Controller::OnScanFilteredGraph(const SourceHandle& info) { OnScannedGraph(info, Filtered::Yes); } - void Controller::OnScannedGraph(const AZ::Data::AssetInfo& assetInfo, [[maybe_unused]] Filtered filtered) + void Controller::OnScannedGraph(const SourceHandle& assetInfo, [[maybe_unused]] Filtered filtered) { const int rowIndex = m_view->tableWidget->rowCount(); if (filtered == Filtered::No || !m_view->onlyShowOutdated->isChecked()) { m_view->tableWidget->insertRow(rowIndex); - QTableWidgetItem* rowName = new QTableWidgetItem(tr(assetInfo.m_relativePath.c_str())); + QTableWidgetItem* rowName = new QTableWidgetItem(tr(assetInfo.Path().c_str())); m_view->tableWidget->setItem(rowIndex, static_cast(ColumnAsset), rowName); SetRowSucceeded(rowIndex); @@ -378,7 +326,7 @@ namespace ScriptCanvasEditor } char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; - AZStd::string path = AZStd::string::format("@devroot@/%s", assetInfo.m_relativePath.c_str()); + AZStd::string path = AZStd::string::format("@devroot@/%s", assetInfo.Path().c_str()); AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); AZ::StringFunc::Path::GetFullPath(resolvedBuffer, path); AZ::StringFunc::Path::Normalize(path); @@ -386,7 +334,7 @@ namespace ScriptCanvasEditor bool result = false; AZ::Data::AssetInfo info; AZStd::string watchFolder; - QByteArray assetNameUtf8 = assetInfo.m_relativePath.c_str(); + QByteArray assetNameUtf8 = assetInfo.Path().c_str(); AzToolsFramework::AssetSystemRequestBus::BroadcastResult ( result , &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath @@ -413,41 +361,41 @@ namespace ScriptCanvasEditor OnScannedGraphResult(assetInfo); } - void Controller::OnScannedGraphResult([[maybe_unused]] const AZ::Data::AssetInfo& info) + void Controller::OnScannedGraphResult([[maybe_unused]] const SourceHandle& info) { m_view->progressBar->setValue(aznumeric_cast(m_handledAssetCount)); ++m_handledAssetCount; AddLogEntries(); } - void Controller::OnScanLoadFailure(const AZ::Data::AssetInfo& info) + void Controller::OnScanLoadFailure(const SourceHandle& info) { const int rowIndex = m_view->tableWidget->rowCount(); m_view->tableWidget->insertRow(rowIndex); QTableWidgetItem* rowName = new QTableWidgetItem - ( tr(AZStd::string::format("Load Error: %s", info.m_relativePath.c_str()).c_str())); + ( tr(AZStd::string::format("Load Error: %s", info.Path().c_str()).c_str())); m_view->tableWidget->setItem(rowIndex, static_cast(ColumnAsset), rowName); SetRowFailed(rowIndex, "Load failed"); OnScannedGraphResult(info); } - void Controller::OnScanUnFilteredGraph(const AZ::Data::AssetInfo& info) + void Controller::OnScanUnFilteredGraph(const SourceHandle& info) { OnScannedGraph(info, Filtered::No); } void Controller::OnUpgradeBegin ( const ModifyConfiguration& config - , [[maybe_unused]] const WorkingAssets& assets) + , [[maybe_unused]] const AZStd::vector& assets) { QString spinnerText = QStringLiteral("Upgrade in progress - "); - if (config.modifySingleAsset.m_assetId.IsValid()) + if (!config.modifySingleAsset.Path().empty()) { spinnerText.append(" single graph"); if (assets.size() == 1) { - for (auto* item : FindTableItems(assets.front().info)) + for (auto* item : FindTableItems(assets.front())) { int row = item->row(); SetRowBusy(row); @@ -498,7 +446,7 @@ namespace ScriptCanvasEditor m_view->scanButton->setEnabled(true); } - void Controller::OnUpgradeDependenciesGathered(const AZ::Data::AssetInfo& info, Result result) + void Controller::OnUpgradeDependenciesGathered(const SourceHandle& info, Result result) { for (auto* item : FindTableItems(info)) { @@ -527,7 +475,7 @@ namespace ScriptCanvasEditor void Controller::OnUpgradeDependencySortBegin ( [[maybe_unused]] const ModifyConfiguration& config - , const WorkingAssets& assets) + , const AZStd::vector& assets) { m_handledAssetCount = 0; m_view->progressBar->setVisible(true); @@ -553,7 +501,7 @@ namespace ScriptCanvasEditor void Controller::OnUpgradeDependencySortEnd ( [[maybe_unused]] const ModifyConfiguration& config - , const WorkingAssets& assets + , const AZStd::vector& assets , [[maybe_unused]] const AZStd::vector& sortedOrder) { m_handledAssetCount = 0; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h index 9842ea3da4..2d7b78060e 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h @@ -65,36 +65,36 @@ namespace ScriptCanvasEditor void AddLogEntries(); void EnableAllUpgradeButtons(); - QList FindTableItems(const AZ::Data::AssetInfo& assetInfo); + QList FindTableItems(const SourceHandle& assetInfo); void OnButtonPressClose(); void OnButtonPressScan(); void OnButtonPressUpgrade(); - void OnButtonPressUpgradeImplementation(const AZ::Data::AssetInfo& assetInfo); - void OnButtonPressUpgradeSingle(const AZ::Data::AssetInfo& assetInfo); + void OnButtonPressUpgradeImplementation(const SourceHandle& assetInfo); + void OnButtonPressUpgradeSingle(const SourceHandle& assetInfo); - void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped) override; + void OnGraphUpgradeComplete(SourceHandle&, bool skipped) override; void OnScanBegin(size_t assetCount) override; void OnScanComplete(const ScanResult& result) override; - void OnScanFilteredGraph(const AZ::Data::AssetInfo& info) override; - void OnScanLoadFailure(const AZ::Data::AssetInfo& info) override; - void OnScanUnFilteredGraph(const AZ::Data::AssetInfo& info) override; + void OnScanFilteredGraph(const SourceHandle& info) override; + void OnScanLoadFailure(const SourceHandle& info) override; + void OnScanUnFilteredGraph(const SourceHandle& info) override; enum class Filtered { No, Yes }; - void OnScannedGraph(const AZ::Data::AssetInfo& info, Filtered filtered); - void OnScannedGraphResult(const AZ::Data::AssetInfo& info); + void OnScannedGraph(const SourceHandle& info, Filtered filtered); + void OnScannedGraphResult(const SourceHandle& info); // for single operation UI updates, just check the assets size, or note it on the request - void OnUpgradeBegin(const ModifyConfiguration& config, const WorkingAssets& assets) override; + void OnUpgradeBegin(const ModifyConfiguration& config, const AZStd::vector& assets) override; void OnUpgradeComplete(const ModificationResults& results) override; - void OnUpgradeDependenciesGathered(const AZ::Data::AssetInfo& info, Result result) override; - void OnUpgradeDependencySortBegin(const ModifyConfiguration& config, const WorkingAssets& assets) override; + void OnUpgradeDependenciesGathered(const SourceHandle& info, Result result) override; + void OnUpgradeDependencySortBegin(const ModifyConfiguration& config, const AZStd::vector& assets) override; void OnUpgradeDependencySortEnd ( const ModifyConfiguration& config - , const WorkingAssets& assets + , const AZStd::vector& assets , const AZStd::vector& sortedOrder) override; - void OnUpgradeModificationBegin(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info) override; - void OnUpgradeModificationEnd(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info, ModificationResult result) override; + void OnUpgradeModificationBegin(const ModifyConfiguration& config, const SourceHandle& info) override; + void OnUpgradeModificationEnd(const ModifyConfiguration& config, const SourceHandle& info, ModificationResult result) override; void SetLoggingPreferences(); void SetSpinnerIsBusy(bool isBusy); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp index f36f72234b..a88c6c2c7e 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp @@ -127,74 +127,9 @@ namespace ScriptCanvasEditor } } - void FileSaver::OnSourceFileReleased(AZ::Data::Asset asset) - { - AZStd::string relativePath, fullPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); - bool fullPathFound = false; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); - AZStd::string tmpFileName; - // here we are saving the graph to a temp file instead of the original file and then copying the temp file to the original file. - // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. Temp files are ignored by AP. - if (!AZ::IO::CreateTempFileName(fullPath.c_str(), tmpFileName)) - { - FileSaveResult result; - result.fileSaveError = "Failure to create temporary file name"; - m_onComplete(result); - return; - } - - bool tempSavedSucceeded = false; - AZ::IO::FileIOStream fileStream(tmpFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); - if (fileStream.IsOpen()) - { - if (asset.GetType() == azrtti_typeid()) - { - ScriptCanvasEditor::ScriptCanvasAssetHandler handler; - tempSavedSucceeded = handler.SaveAssetData(asset, &fileStream); - } - - fileStream.Close(); - } - - if (!tempSavedSucceeded) - { - FileSaveResult result; - result.fileSaveError = "Save asset data to temporary file failed"; - m_onComplete(result); - return; - } - - AzToolsFramework::SourceControlCommandBus::Broadcast - ( &AzToolsFramework::SourceControlCommandBus::Events::RequestEdit - , fullPath.c_str() - , true - , [this, fullPath, tmpFileName]([[maybe_unused]] bool success, const AzToolsFramework::SourceControlFileInfo& info) - { - constexpr const size_t k_maxAttemps = 10; - - if (!info.IsReadOnly()) - { - PerformMove(tmpFileName, fullPath, k_maxAttemps); - } - else if (m_onReadOnlyFile && m_onReadOnlyFile()) - { - AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); - PerformMove(tmpFileName, fullPath, k_maxAttemps); - } - else - { - FileSaveResult result; - result.fileSaveError = "Source file is read-only"; - result.tempFileRemovalError = RemoveTempFile(tmpFileName); - m_onComplete(result); - } - }); - } - void FileSaver::OnSourceFileReleased(const SourceHandle& source) { - AZStd::string fullPath = source.Path(); + AZStd::string fullPath = source.Path().c_str(); AZStd::string tmpFileName; // here we are saving the graph to a temp file instead of the original file and then copying the temp file to the original file. // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. @@ -285,7 +220,7 @@ namespace ScriptCanvasEditor else { auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(source.Path()); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(source.Path().c_str()); streamer->SetRequestCompleteCallback(flushRequest, [this, source]([[maybe_unused]] AZ::IO::FileRequestHandle request) { this->OnSourceFileReleased(source); @@ -293,34 +228,5 @@ namespace ScriptCanvasEditor streamer->QueueRequest(flushRequest); } } - - void FileSaver::Save(AZ::Data::Asset asset) - { - // #sc_editor_asset fix/remove this path that is used by the version explorer - AZStd::string relativePath, fullPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); - bool fullPathFound = false; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult - ( fullPathFound - , &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath - , relativePath, fullPath); - - if (!fullPathFound) - { - FileSaveResult result; - result.fileSaveError = "Full source path not found"; - m_onComplete(result); - } - else - { - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(fullPath); - streamer->SetRequestCompleteCallback(flushRequest, [this, asset]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - this->OnSourceFileReleased(asset); - }); - streamer->QueueRequest(flushRequest); - } - } } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h index 439db2d260..d04b543b0c 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h @@ -30,7 +30,6 @@ namespace ScriptCanvasEditor , AZStd::function onComplete); const SourceHandle& GetSource() const; - void Save(AZ::Data::Asset asset); void Save(const SourceHandle& source); private: @@ -39,8 +38,7 @@ namespace ScriptCanvasEditor AZStd::function m_onReadOnlyFile; void OnSourceFileReleased(const SourceHandle& source); - void OnSourceFileReleased(AZ::Data::Asset asset); - + void PerformMove ( AZStd::string source , AZStd::string target diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp index d8d242adbb..86a1c1f42e 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp @@ -101,7 +101,7 @@ namespace ScriptCanvasEditor return; } - if (modification.modifySingleAsset.m_assetId.IsValid()) + if (!modification.modifySingleAsset.Path().empty()) { const auto& results = m_scanner->GetResult(); auto iter = AZStd::find_if @@ -109,7 +109,7 @@ namespace ScriptCanvasEditor , results.m_unfiltered.end() , [&modification](const auto& candidate) { - return candidate.info.m_assetId == modification.modifySingleAsset.m_assetId; + return candidate.AnyEquals(modification.modifySingleAsset); }); if (iter == results.m_unfiltered.end()) @@ -120,7 +120,7 @@ namespace ScriptCanvasEditor m_state = State::ModifySingle; - m_modifier = AZStd::make_unique(modification, WorkingAssets{ *iter }, [this]() { OnModificationComplete(); }); + m_modifier = AZStd::make_unique(modification, AZStd::vector{ *iter }, [this]() { OnModificationComplete(); }); } else { diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h index 01eb200542..4ab9015a6c 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h @@ -9,53 +9,51 @@ #include #include +#include namespace ScriptCanvasEditor { namespace VersionExplorer { - struct WorkingAsset - { - AZ::Data::Asset asset; - AZ::Data::AssetInfo info; - }; - - using WorkingAssets = AZStd::vector; - struct ModifyConfiguration { - AZStd::function)> modification; + AZStd::function modification; AZStd::function onReadOnlyFile; - AZ::Data::AssetInfo modifySingleAsset; + SourceHandle modifySingleAsset; bool backupGraphBeforeModification = false; bool successfulDependencyUpgradeRequired = true; }; struct ModificationResult { - AZ::Data::Asset asset; - AZ::Data::AssetInfo assetInfo; + SourceHandle asset; AZStd::string errorMessage; }; struct ModificationResults { - AZStd::vector m_successes; + AZStd::vector m_successes; AZStd::vector m_failures; }; struct ScanConfiguration { - AZStd::function)> filter; + enum class Filter + { + Include, + Exclude + }; + + AZStd::function filter; bool reportFilteredGraphs = false; }; struct ScanResult { - AZStd::vector m_catalogAssets; - WorkingAssets m_unfiltered; - AZStd::vector m_filteredAssets; - AZStd::vector m_loadErrors; + AZStd::vector m_catalogAssets; + AZStd::vector m_unfiltered; + AZStd::vector m_filteredAssets; + AZStd::vector m_loadErrors; }; enum Result @@ -88,20 +86,20 @@ namespace ScriptCanvasEditor public: virtual void OnScanBegin(size_t assetCount) = 0; virtual void OnScanComplete(const ScanResult& result) = 0; - virtual void OnScanFilteredGraph(const AZ::Data::AssetInfo& info) = 0; - virtual void OnScanLoadFailure(const AZ::Data::AssetInfo& info) = 0; - virtual void OnScanUnFilteredGraph(const AZ::Data::AssetInfo& info) = 0; + virtual void OnScanFilteredGraph(const SourceHandle& info) = 0; + virtual void OnScanLoadFailure(const SourceHandle& info) = 0; + virtual void OnScanUnFilteredGraph(const SourceHandle& info) = 0; - virtual void OnUpgradeBegin(const ModifyConfiguration& config, const WorkingAssets& assets) = 0; + virtual void OnUpgradeBegin(const ModifyConfiguration& config, const AZStd::vector& assets) = 0; virtual void OnUpgradeComplete(const ModificationResults& results) = 0; - virtual void OnUpgradeDependenciesGathered(const AZ::Data::AssetInfo& info, Result result) = 0; - virtual void OnUpgradeDependencySortBegin(const ModifyConfiguration& config, const WorkingAssets& assets) = 0; + virtual void OnUpgradeDependenciesGathered(const SourceHandle& info, Result result) = 0; + virtual void OnUpgradeDependencySortBegin(const ModifyConfiguration& config, const AZStd::vector& assets) = 0; virtual void OnUpgradeDependencySortEnd ( const ModifyConfiguration& config - , const WorkingAssets& assets + , const AZStd::vector& assets , const AZStd::vector& sortedOrder) = 0; - virtual void OnUpgradeModificationBegin(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info) = 0; - virtual void OnUpgradeModificationEnd(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info, ModificationResult result) = 0; + virtual void OnUpgradeModificationBegin(const ModifyConfiguration& config, const SourceHandle& info) = 0; + virtual void OnUpgradeModificationEnd(const ModifyConfiguration& config, const SourceHandle& info, ModificationResult result) = 0; }; using ModelNotificationsBus = AZ::EBus; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp index 0e4190b18d..56d7264859 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp @@ -6,24 +6,21 @@ * */ +#include #include #include #include #include +#include #include -namespace ModifierCpp -{ - -} - namespace ScriptCanvasEditor { namespace VersionExplorer { Modifier::Modifier ( const ModifyConfiguration& modification - , WorkingAssets&& assets + , AZStd::vector&& assets , AZStd::function onComplete) : m_state(State::GatheringDependencies) , m_config(modification) @@ -35,11 +32,11 @@ namespace ScriptCanvasEditor AZ::SystemTickBus::Handler::BusConnect(); } - const AZ::Data::AssetInfo& Modifier::GetCurrentAsset() const + const SourceHandle& Modifier::GetCurrentAsset() const { return m_state == State::GatheringDependencies - ? m_assets[m_assetIndex].info - : m_assets[m_dependencyOrderedAssetIndicies[m_assetIndex]].info; + ? m_assets[m_assetIndex] + : m_assets[m_dependencyOrderedAssetIndicies[m_assetIndex]]; } AZStd::unordered_set& Modifier::GetOrCreateDependencyIndexSet() @@ -66,13 +63,9 @@ namespace ScriptCanvasEditor bool anyFailures = false; auto asset = LoadAsset(); - - if (asset - && asset.GetAs() - && asset.GetAs()->GetScriptCanvasGraph() - && asset.GetAs()->GetScriptCanvasGraph()->GetGraphData()) + if (asset.Get() && asset.Mod()->GetGraphData()) { - auto graphData = asset.GetAs()->GetScriptCanvasGraph()->GetGraphData(); + auto graphData = asset.Mod()->GetGraphData(); auto dependencyGrabber = [this] ( void* instancePointer @@ -107,15 +100,15 @@ namespace ScriptCanvasEditor , nullptr)) { anyFailures = true; - VE_LOG("Modifier: ERROR - Failed to gather dependencies from graph data: %s" - , GetCurrentAsset().m_relativePath.c_str()) + VE_LOG("Modifier: ERROR - Failed to gather dependencies from graph data: %s" + , GetCurrentAsset().Path().c_str()) } } else { anyFailures = true; VE_LOG("Modifier: ERROR - Failed to load asset %s for modification, even though it scanned properly" - , GetCurrentAsset().m_relativePath.c_str()); + , GetCurrentAsset().Path().c_str()); } ModelNotificationsBus::Broadcast @@ -127,18 +120,12 @@ namespace ScriptCanvasEditor AZ::Data::AssetManager::Instance().DispatchEvents(); } - AZ::Data::Asset Modifier::LoadAsset() + SourceHandle Modifier::LoadAsset() { - AZ::Data::Asset asset = AZ::Data::AssetManager::Instance().GetAsset - ( GetCurrentAsset().m_assetId - , azrtti_typeid() - , AZ::Data::AssetLoadBehavior::PreLoad); - - asset.BlockUntilLoadComplete(); - - if (asset.IsReady()) + auto outcome = LoadFromFile(GetCurrentAsset().Path().c_str()); + if (outcome.IsSuccess()) { - return asset; + return outcome.TakeValue(); } else { @@ -163,11 +150,11 @@ namespace ScriptCanvasEditor void Modifier::ModifyCurrentAsset() { m_result = {}; - m_result.assetInfo = GetCurrentAsset(); + m_result.asset = GetCurrentAsset(); ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeModificationBegin, m_config, GetCurrentAsset()); - if (auto asset = LoadAsset()) + if (auto asset = LoadAsset(); asset.IsValid()) { ModificationNotificationsBus::Handler::BusConnect(); m_modifyState = ModifyState::InProgress; @@ -199,7 +186,7 @@ namespace ScriptCanvasEditor void Modifier::ReportModificationSuccess() { - m_results.m_successes.push_back(m_result.assetInfo); + m_results.m_successes.push_back(m_result.asset); ModifyNextAsset(); } @@ -227,7 +214,7 @@ namespace ScriptCanvasEditor { VE_LOG ( "Temporary file not removed for %s: %s" - , m_result.assetInfo.m_relativePath.c_str() + , m_result.asset.Path().c_str() , result.tempFileRemovalError.c_str()); } @@ -287,7 +274,7 @@ namespace ScriptCanvasEditor for (size_t index = 0; index != m_assets.size(); ++index) { - m_assetInfoIndexById.insert({ m_assets[index].info.m_assetId.m_guid, index }); + m_assetInfoIndexById.insert({ m_assets[index].Id(), index }); } } else @@ -380,10 +367,10 @@ namespace ScriptCanvasEditor if (markedTemporary.contains(index)) { AZ_Error - (ScriptCanvas::k_VersionExplorerWindow.data() + (ScriptCanvas::k_VersionExplorerWindow.data() , false , "Modifier: Dependency sort has failed during, circular dependency detected for Asset: %s" - , modifier->GetCurrentAsset().m_relativePath.c_str()); + , modifier->GetCurrentAsset().Path().c_str()); return; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h index 981a1eb746..c57af605e3 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h @@ -26,7 +26,7 @@ namespace ScriptCanvasEditor Modifier ( const ModifyConfiguration& modification - , WorkingAssets&& assets + , AZStd::vector&& assets , AZStd::function onComplete); const ModificationResults& GetResult() const; @@ -69,7 +69,7 @@ namespace ScriptCanvasEditor size_t m_assetIndex = 0; AZStd::function m_onComplete; // asset infos in scanned order - WorkingAssets m_assets; + AZStd::vector m_assets; // dependency sorted order indices into the asset vector AZStd::vector m_dependencyOrderedAssetIndicies; // dependency indices by asset info index (only exist if graphs have them) @@ -83,9 +83,9 @@ namespace ScriptCanvasEditor FileSaveResult m_fileSaveResult; void GatherDependencies(); - const AZ::Data::AssetInfo& GetCurrentAsset() const; + const SourceHandle& GetCurrentAsset() const; AZStd::unordered_set& GetOrCreateDependencyIndexSet(); - AZ::Data::Asset LoadAsset(); + SourceHandle LoadAsset(); void ModifyCurrentAsset(); void ModifyNextAsset(); void ModificationComplete(const ModificationResult& result) override; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp index bc69f6e634..d959a6b6ab 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp @@ -6,9 +6,45 @@ * */ +#include +#include +#include +#include +#include #include #include -#include +#include + +namespace ScannerCpp +{ + void TraverseTree + ( QModelIndex index + , AzToolsFramework::AssetBrowser::AssetBrowserFilterModel& model + , ScriptCanvasEditor::VersionExplorer::ScanResult& result) + { + QModelIndex sourceIndex = model.mapToSource(index); + AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry = + reinterpret_cast(sourceIndex.internalPointer()); + + if (entry + && entry->GetEntryType() == AzToolsFramework::AssetBrowser::AssetBrowserEntry::AssetEntryType::Source + && azrtti_istypeof(entry) + && entry->GetFullPath().ends_with(".scriptcanvas")) + { + auto sourceEntry = azrtti_cast(entry); + result.m_catalogAssets.push_back( + ScriptCanvasEditor::SourceHandle(nullptr, sourceEntry->GetSourceUuid(), sourceEntry->GetFullPath())); + } + + const int rowCount = model.rowCount(index); + + for (int i = 0; i < rowCount; ++i) + { + TraverseTree(model.index(i, 0, index), model, result); + } + } +} + namespace ScriptCanvasEditor { @@ -18,39 +54,44 @@ namespace ScriptCanvasEditor : m_config(config) , m_onComplete(onComplete) { - AZ::Data::AssetCatalogRequestBus::Broadcast - ( &AZ::Data::AssetCatalogRequestBus::Events::EnumerateAssets - , nullptr - , [this](const AZ::Data::AssetId, const AZ::Data::AssetInfo& assetInfo) - { - if (assetInfo.m_assetType == azrtti_typeid()) - { - m_result.m_catalogAssets.push_back(assetInfo); - } - } - , nullptr); + AzToolsFramework::AssetBrowser::AssetBrowserModel* assetBrowserModel = nullptr; + AzToolsFramework::AssetBrowser::AssetBrowserComponentRequestBus::BroadcastResult + ( assetBrowserModel, &AzToolsFramework::AssetBrowser::AssetBrowserComponentRequests::GetAssetBrowserModel); + + if (assetBrowserModel) + { + auto stringFilter = new AzToolsFramework::AssetBrowser::StringFilter(); + stringFilter->SetName("ScriptCanvas"); + stringFilter->SetFilterString(".scriptcanvas"); + stringFilter->SetFilterPropagation(AzToolsFramework::AssetBrowser::AssetBrowserEntryFilter::PropagateDirection::Down); + + AzToolsFramework::AssetBrowser::AssetBrowserFilterModel assetFilterModel; + assetFilterModel.SetFilter(AzToolsFramework::AssetBrowser::FilterConstType(stringFilter)); + assetFilterModel.setSourceModel(assetBrowserModel); + + ScannerCpp::TraverseTree(QModelIndex(), assetFilterModel, m_result); + } - ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanBegin, m_result.m_catalogAssets.size()); AZ::SystemTickBus::Handler::BusConnect(); } - void Scanner::FilterAsset(AZ::Data::Asset asset) + void Scanner::FilterAsset(SourceHandle asset) { - if (m_config.filter && m_config.filter(asset)) + if (m_config.filter && m_config.filter(asset) == ScanConfiguration::Filter::Exclude) { - VE_LOG("Scanner: Excluded: %s ", GetCurrentAsset().m_relativePath.c_str()); - m_result.m_filteredAssets.push_back(GetCurrentAsset()); + VE_LOG("Scanner: Excluded: %s ", GetCurrentAsset().Path().c_str()); + m_result.m_filteredAssets.push_back(GetCurrentAsset().Describe()); ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanFilteredGraph, GetCurrentAsset()); } else { - VE_LOG("Scanner: Included: %s ", GetCurrentAsset().m_relativePath.c_str()); - m_result.m_unfiltered.push_back({ asset, GetCurrentAsset() }); + VE_LOG("Scanner: Included: %s ", GetCurrentAsset().Path().c_str()); + m_result.m_unfiltered.push_back(GetCurrentAsset().Describe()); ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanUnFilteredGraph, GetCurrentAsset()); } } - const AZ::Data::AssetInfo& Scanner::GetCurrentAsset() const + const SourceHandle& Scanner::GetCurrentAsset() const { return m_result.m_catalogAssets[m_catalogAssetIndex]; } @@ -60,18 +101,12 @@ namespace ScriptCanvasEditor return m_result; } - AZ::Data::Asset Scanner::LoadAsset() + SourceHandle Scanner::LoadAsset() { - AZ::Data::Asset asset = AZ::Data::AssetManager::Instance().GetAsset - ( GetCurrentAsset().m_assetId - , azrtti_typeid() - , AZ::Data::AssetLoadBehavior::PreLoad); - - asset.BlockUntilLoadComplete(); - - if (asset.IsReady()) + auto fileOutcome = LoadFromFile(GetCurrentAsset().Path().c_str()); + if (fileOutcome.IsSuccess()) { - return asset; + return fileOutcome.GetValue(); } else { @@ -93,19 +128,19 @@ namespace ScriptCanvasEditor } else { - if (auto asset = LoadAsset()) + if (auto asset = LoadAsset(); asset.IsValid()) { - VE_LOG("Scanner: Loaded: %s ", GetCurrentAsset().m_relativePath.c_str()); + VE_LOG("Scanner: Loaded: %s ", GetCurrentAsset().Path().c_str()); FilterAsset(asset); } else { - VE_LOG("Scanner: Failed to load: %s ", GetCurrentAsset().m_relativePath.c_str()); + VE_LOG("Scanner: Failed to load: %s ", GetCurrentAsset().Path().c_str()); m_result.m_loadErrors.push_back(GetCurrentAsset()); ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanLoadFailure, GetCurrentAsset()); } - VE_LOG("Scanner: scan of %s complete", GetCurrentAsset().m_relativePath.c_str()); + VE_LOG("Scanner: scan of %s complete", GetCurrentAsset().Path().c_str()); ++m_catalogAssetIndex; } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h index fb030845c7..f276c146da 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h @@ -33,9 +33,9 @@ namespace ScriptCanvasEditor ScanConfiguration m_config; ScanResult m_result; - void FilterAsset(AZ::Data::Asset); - const AZ::Data::AssetInfo& GetCurrentAsset() const; - AZ::Data::Asset LoadAsset(); + void FilterAsset(SourceHandle); + const SourceHandle& GetCurrentAsset() const; + SourceHandle LoadAsset(); void OnSystemTick() override; }; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp index e88675814b..3522f3cfa2 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp @@ -55,26 +55,25 @@ namespace ScriptCanvasEditor for (auto& failedUpdate : result->m_failures) { - auto& assetInfo = failedUpdate.assetInfo; - auto assetId = assetInfo.m_assetId; - + auto asset = failedUpdate.asset; + m_ui->tableWidget->insertRow(rows); connect(m_ui->closeButton, &QPushButton::pressed, this, &QDialog::accept); - connect(m_ui->tableWidget, &QTableWidget::itemDoubleClicked, this, [this, rows, assetId](QTableWidgetItem* item) + connect(m_ui->tableWidget, &QTableWidget::itemDoubleClicked, this, [this, rows, asset](QTableWidgetItem* item) { if (item && item->data(Qt::UserRole).toInt() == rows) { - OpenGraph(assetId); + OpenGraph(asset); } } ); - auto openGraph = [this, assetId] { - OpenGraph(assetId); + auto openGraph = [this, asset] { + OpenGraph(asset); }; - QTableWidgetItem* rowName = new QTableWidgetItem(tr(assetInfo.m_relativePath.c_str())); + QTableWidgetItem* rowName = new QTableWidgetItem(tr(asset.Path().c_str())); rowName->setData(Qt::UserRole, rows); m_ui->tableWidget->setItem(rows, 0, rowName); @@ -91,16 +90,15 @@ namespace ScriptCanvasEditor } } - void UpgradeHelper::OpenGraph(AZ::Data::AssetId assetId) + void UpgradeHelper::OpenGraph(const SourceHandle& asset) { // Open the graph in SC editor AzToolsFramework::OpenViewPane(/*LyViewPane::ScriptCanvas*/"Script Canvas"); AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); - if (assetId.IsValid()) + if (!asset.Path().empty()) { - // #sc_editor_asset - // GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, assetId, -1); + GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, asset, -1); } if (!openOutcome) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.h index 36949c1828..4c0c073d70 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.h @@ -35,6 +35,8 @@ namespace Ui namespace ScriptCanvasEditor { + // class SourceHandle; + //! A tool that collects and upgrades all Script Canvas graphs in the asset catalog class UpgradeHelper : public AzQtComponents::StyledDialog @@ -51,6 +53,6 @@ namespace ScriptCanvasEditor AZStd::unique_ptr m_ui; - void OpenGraph(AZ::Data::AssetId assetId); + void OpenGraph(const SourceHandle& assetId); }; } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp index 829a25f3d1..7bfa9fabd2 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp @@ -189,7 +189,7 @@ namespace ScriptCanvas namespace ScriptCanvasEditor { - SourceHandle::SourceHandle(const SourceHandle& data, const AZ::Uuid& id, AZStd::string_view path) + SourceHandle::SourceHandle(const SourceHandle& data, const AZ::Uuid& id, const AZ::IO::Path& path) : m_data(data.m_data) , m_id(id) , m_path(path) @@ -197,7 +197,7 @@ namespace ScriptCanvasEditor } - SourceHandle::SourceHandle(ScriptCanvas::DataPtr graph, const AZ::Uuid& id, AZStd::string_view path) + SourceHandle::SourceHandle(ScriptCanvas::DataPtr graph, const AZ::Uuid& id, const AZ::IO::Path& path) : m_data(graph) , m_id(id) , m_path(path) @@ -217,6 +217,12 @@ namespace ScriptCanvasEditor m_path.clear(); } + // return a SourceHandle with only the Id and Path, but without a pointer to the data + SourceHandle SourceHandle::Describe() const + { + return SourceHandle(nullptr, m_id, m_path); + } + GraphPtrConst SourceHandle::Get() const { return m_data ? m_data->GetEditorGraph() : nullptr; @@ -249,7 +255,7 @@ namespace ScriptCanvasEditor return !(*this == other); } - const AZStd::string& SourceHandle::Path() const + const AZ::IO::Path& SourceHandle::Path() const { return m_path; } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h index 8d7dc40866..9e7ffc96f8 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h @@ -9,18 +9,19 @@ #pragma once #include +#include +#include +#include #include +#include #include #include -#include #include +#include #include #include #include #include -#include -#include -#include #include #include @@ -326,16 +327,17 @@ namespace ScriptCanvasEditor SourceHandle() = default; - SourceHandle(const SourceHandle& data, const AZ::Uuid& id, AZStd::string_view path); + SourceHandle(const SourceHandle& data, const AZ::Uuid& id, const AZ::IO::Path& path); - SourceHandle(ScriptCanvas::DataPtr graph, const AZ::Uuid& id, AZStd::string_view path); - - ~SourceHandle() = default; + SourceHandle(ScriptCanvas::DataPtr graph, const AZ::Uuid& id, const AZ::IO::Path& path); bool AnyEquals(const SourceHandle& other) const; void Clear(); + // return a SourceHandle with only the Id and Path, but without a pointer to the data + SourceHandle Describe() const; + GraphPtrConst Get() const; const AZ::Uuid& Id() const; @@ -348,7 +350,7 @@ namespace ScriptCanvasEditor bool operator!=(const SourceHandle& other) const; - const AZStd::string& Path() const; + const AZ::IO::Path& Path() const; bool PathEquals(const SourceHandle& other) const; @@ -357,7 +359,7 @@ namespace ScriptCanvasEditor private: ScriptCanvas::DataPtr m_data; AZ::Uuid m_id = AZ::Uuid::CreateNull(); - AZStd::string m_path; + AZ::IO::Path m_path; }; } From 63f98e7dd951c1ab97719a118f0d0aa689cfedbc Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Tue, 16 Nov 2021 09:12:36 -0800 Subject: [PATCH 019/128] isolate the loading problem during version explorer Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp | 2 +- .../Code/Builder/ScriptCanvasBuilderComponent.cpp | 2 +- .../Code/Editor/Assets/ScriptCanvasFileHandling.cpp | 5 +++++ .../Editor/View/Windows/Tools/UpgradeTool/Controller.cpp | 1 - 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp b/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp index 1c383d04bd..2a3da9f351 100644 --- a/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp +++ b/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp @@ -64,7 +64,7 @@ namespace ScriptCanvasEditor void EditorAssetSystemComponent::Activate() { - m_editorAssetRegistry.Register(); + // m_editorAssetRegistry.Register(); m_editorAssetRegistry.Register(); AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect(); diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.cpp index a37fa47b62..a08e006a19 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.cpp @@ -48,7 +48,7 @@ namespace ScriptCanvasBuilder SharedHandlers HandleAssetTypes() { SharedHandlers handlers; - handlers.m_editorAssetHandler = RegisterHandler("scriptcanvas", false); + // handlers.m_editorAssetHandler = RegisterHandler("scriptcanvas", false); handlers.m_subgraphInterfaceHandler = RegisterHandler("scriptcanvas_fn_compiled", true); handlers.m_runtimeAssetHandler = RegisterHandler("scriptcanvas_compiled", true); diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp index cd8d21543f..ec225017fe 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp @@ -194,6 +194,11 @@ namespace ScriptCanvasEditor auto saveOutcome = JSRU::SaveObjectToStream(graphData, stream, nullptr, &settings); if (!saveOutcome.IsSuccess()) { + + Here is the allocation failure. + + AZStd::string result = saveOutcome.TakeError(); + return AZ::Failure(AZStd::string("JSON serialization failed to save source: %s", saveOutcome.GetError().c_str())); } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp index 5189895a56..035152a521 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp @@ -53,7 +53,6 @@ namespace ScriptCanvasEditor m_view->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); connect(m_view->scanButton, &QPushButton::pressed, this, &Controller::OnButtonPressScan); connect(m_view->closeButton, &QPushButton::pressed, this, &Controller::OnButtonPressClose); - m_view->upgradeAllButton->setVisible(false); connect(m_view->upgradeAllButton, &QPushButton::pressed, this, &Controller::OnButtonPressUpgrade); m_view->progressBar->setValue(0); m_view->progressBar->setVisible(false); From 0367a3297f21e07c38f5f277ce1e500457e21650 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 17 Nov 2021 12:17:45 -0800 Subject: [PATCH 020/128] fixed version explorer issue Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Editor/Assets/ScriptCanvasFileHandling.cpp | 10 +++------- .../Code/Editor/View/Windows/MainWindow.cpp | 2 +- .../View/Windows/Tools/UpgradeTool/Controller.cpp | 2 +- .../View/Windows/Tools/UpgradeTool/FileSaver.cpp | 10 ++++++++-- .../Editor/View/Windows/Tools/UpgradeTool/FileSaver.h | 3 +++ .../Code/Include/ScriptCanvas/Core/Core.cpp | 6 +++--- 6 files changed, 19 insertions(+), 14 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp index ec225017fe..68648a71f3 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp @@ -175,7 +175,7 @@ namespace ScriptCanvasEditor auto saveTarget = graphData->ModGraph(); if (!saveTarget || !saveTarget->GetGraphData()) { - return AZ::Failure(AZStd::string("source save container failed to return graph data")); + return AZ::Failure(AZStd::string("source save container failed to return serializable graph data")); } AZ::JsonSerializerSettings settings; @@ -194,12 +194,8 @@ namespace ScriptCanvasEditor auto saveOutcome = JSRU::SaveObjectToStream(graphData, stream, nullptr, &settings); if (!saveOutcome.IsSuccess()) { - - Here is the allocation failure. - - AZStd::string result = saveOutcome.TakeError(); - - return AZ::Failure(AZStd::string("JSON serialization failed to save source: %s", saveOutcome.GetError().c_str())); + AZStd::string result = saveOutcome.TakeError(); + return AZ::Failure(AZStd::string("JSON serialization failed to save source: %s", result.c_str())); } return AZ::Success(); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index d43e509905..ecfef7c059 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -1407,7 +1407,7 @@ namespace ScriptCanvasEditor AZ::Outcome outcome = LoadFromFile(fullPath); if (!outcome.IsSuccess()) { - QMessageBox::warning(this, "Invalid Source File", QString("'%1' is not a valid file path.").arg(fullPath), QMessageBox::Ok); + QMessageBox::warning(this, "Invalid Source File", QString("'%1' failed to load properly.").arg(fullPath), QMessageBox::Ok); m_errorFilePath = fullPath; AZ_Warning("ScriptCanvas", false, "Unable to open file as a ScriptCanvas graph: %s", fullPath); return; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp index 035152a521..888f183151 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp @@ -165,7 +165,7 @@ namespace ScriptCanvasEditor { int result = QMessageBox::No; QMessageBox mb - (QMessageBox::Warning + ( QMessageBox::Warning , QObject::tr("Failed to Save Upgraded File") , QObject::tr("The upgraded file could not be saved because the file is read only.\n" "Do you want to make it writeable and overwrite it?") diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp index a88c6c2c7e..c23a3d915b 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp @@ -221,10 +221,16 @@ namespace ScriptCanvasEditor { auto streamer = AZ::Interface::Get(); AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(source.Path().c_str()); - streamer->SetRequestCompleteCallback(flushRequest, [this, source]([[maybe_unused]] AZ::IO::FileRequestHandle request) + streamer->SetRequestCompleteCallback(flushRequest, [this]([[maybe_unused]] AZ::IO::FileRequestHandle request) { - this->OnSourceFileReleased(source); + AZStd::lock_guard lock(m_mutex); + if (!m_sourceFileReleased) + { + m_sourceFileReleased = true; + AZ::SystemTickBus::QueueFunction([this]() { this->OnSourceFileReleased(m_source); }); + } }); + streamer->QueueRequest(flushRequest); } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h index d04b543b0c..e87ee060f7 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h @@ -33,6 +33,9 @@ namespace ScriptCanvasEditor void Save(const SourceHandle& source); private: + AZStd::mutex m_mutex; + + bool m_sourceFileReleased = false; SourceHandle m_source; AZStd::function m_onComplete; AZStd::function m_onReadOnlyFile; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp index 7bfa9fabd2..de96c9953b 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp @@ -205,9 +205,9 @@ namespace ScriptCanvasEditor bool SourceHandle::AnyEquals(const SourceHandle& other) const { - return m_data == other.m_data - || m_id == other.m_id - || m_path == other.m_path; + return m_data && m_data == other.m_data + || !m_id.IsNull() && m_id == other.m_id + || !m_path.empty() && m_path == other.m_path; } void SourceHandle::Clear() From 5b9896d2c4db4bbebcd75845a47538757022b865 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 17 Nov 2021 13:47:51 -0800 Subject: [PATCH 021/128] fixed unit test running system Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Asset/EditorAssetConversionBus.h | 7 ++----- .../Code/Asset/EditorAssetSystemComponent.cpp | 21 +++---------------- .../Code/Asset/EditorAssetSystemComponent.h | 5 ++--- .../Builder/ScriptCanvasBuilderWorker.cpp | 1 + .../Code/Builder/ScriptCanvasBuilderWorker.h | 5 +++-- .../ScriptCanvasBuilderWorkerUtility.cpp | 13 ++++++------ .../Framework/ScriptCanvasGraphUtilities.h | 1 + .../Framework/ScriptCanvasGraphUtilities.inl | 18 +++++++--------- .../Framework/ScriptCanvasTraceUtilities.h | 4 ++-- 9 files changed, 28 insertions(+), 47 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Asset/EditorAssetConversionBus.h b/Gems/ScriptCanvas/Code/Asset/EditorAssetConversionBus.h index 12313021f7..3b120af5da 100644 --- a/Gems/ScriptCanvas/Code/Asset/EditorAssetConversionBus.h +++ b/Gems/ScriptCanvas/Code/Asset/EditorAssetConversionBus.h @@ -26,17 +26,14 @@ namespace ScriptCanvas namespace ScriptCanvasEditor { - class ScriptCanvasAsset; - class EditorAssetConversionBusTraits : public AZ::EBusTraits { public: static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; - virtual AZ::Data::Asset LoadAsset(AZStd::string_view graphPath) = 0; - virtual AZ::Outcome CreateLuaAsset(const AZ::Data::Asset& editAsset, AZStd::string_view graphPathForRawLuaFile) = 0; - virtual AZ::Outcome, AZStd::string> CreateRuntimeAsset(const AZ::Data::Asset& editAsset) = 0; + virtual AZ::Outcome CreateLuaAsset(const SourceHandle& editAsset, AZStd::string_view graphPathForRawLuaFile) = 0; + virtual AZ::Outcome, AZStd::string> CreateRuntimeAsset(const SourceHandle& editAsset) = 0; }; using EditorAssetConversionBus = AZ::EBus; diff --git a/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp b/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp index 2a3da9f351..3515eaf34f 100644 --- a/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp +++ b/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp @@ -64,7 +64,6 @@ namespace ScriptCanvasEditor void EditorAssetSystemComponent::Activate() { - // m_editorAssetRegistry.Register(); m_editorAssetRegistry.Register(); AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect(); @@ -98,28 +97,14 @@ namespace ScriptCanvasEditor return false; } - AZ::Data::Asset EditorAssetSystemComponent::LoadAsset(AZStd::string_view graphPath) - { - auto outcome = ScriptCanvasBuilder::LoadEditorAsset(graphPath, AZ::Data::AssetId(AZ::Uuid::CreateRandom())); - - if (outcome.IsSuccess()) - { - return outcome.GetValue(); - } - else - { - return {}; - } - } - - AZ::Outcome, AZStd::string> EditorAssetSystemComponent::CreateRuntimeAsset(const AZ::Data::Asset& editAsset) + AZ::Outcome, AZStd::string> EditorAssetSystemComponent::CreateRuntimeAsset(const SourceHandle& editAsset) { return ScriptCanvasBuilder::CreateRuntimeAsset(editAsset); } - AZ::Outcome EditorAssetSystemComponent::CreateLuaAsset(const AZ::Data::Asset& editAsset, AZStd::string_view graphPathForRawLuaFile) + AZ::Outcome EditorAssetSystemComponent::CreateLuaAsset(const SourceHandle& editAsset, AZStd::string_view graphPathForRawLuaFile) { - return ScriptCanvasBuilder::CreateLuaAsset(editAsset->GetScriptCanvasEntity(), editAsset->GetId(), graphPathForRawLuaFile); + return ScriptCanvasBuilder::CreateLuaAsset(editAsset, graphPathForRawLuaFile); } void EditorAssetSystemComponent::AddSourceFileOpeners([[maybe_unused]] const char* fullSourceFileName, [[maybe_unused]] const AZ::Uuid& sourceUuid, [[maybe_unused]] AzToolsFramework::AssetBrowser::SourceFileOpenerList& openers) diff --git a/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.h b/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.h index 96e1280cbc..7937950a05 100644 --- a/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.h +++ b/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.h @@ -49,9 +49,8 @@ namespace ScriptCanvasEditor ////////////////////////////////////////////////////////////////////////// // EditorAssetConversionBus::Handler... - AZ::Data::Asset LoadAsset(AZStd::string_view graphPath) override; - AZ::Outcome, AZStd::string> CreateRuntimeAsset(const AZ::Data::Asset& editAsset) override; - AZ::Outcome CreateLuaAsset(const AZ::Data::Asset& editAsset, AZStd::string_view graphPathForRawLuaFile) override; + AZ::Outcome, AZStd::string> CreateRuntimeAsset(const SourceHandle& editAsset) override; + AZ::Outcome CreateLuaAsset(const SourceHandle& editAsset, AZStd::string_view graphPathForRawLuaFile) override; ////////////////////////////////////////////////////////////////////////// ScriptCanvas::AssetRegistry& GetAssetRegistry(); diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp index 7a7dbfff0b..f38654f565 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp @@ -29,6 +29,7 @@ #include #include #include +#include namespace ScriptCanvasBuilder { diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h index 84c9285362..816206ce33 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h @@ -37,6 +37,7 @@ namespace ScriptCanvasEditor { class Graph; class ScriptCanvasAsset; + class SourceHandle; } namespace ScriptCanvasBuilder @@ -125,13 +126,13 @@ namespace ScriptCanvasBuilder } }; - AZ::Outcome, AZStd::string> CreateRuntimeAsset(const AZ::Data::Asset& asset); + AZ::Outcome, AZStd::string> CreateRuntimeAsset(const ScriptCanvasEditor::SourceHandle& asset); AZ::Outcome CompileGraphData(AZ::Entity* scriptCanvasEntity); AZ::Outcome CompileVariableData(AZ::Entity* scriptCanvasEntity); - AZ::Outcome CreateLuaAsset(AZ::Entity* buildEntity, AZ::Data::AssetId scriptAssetId, AZStd::string_view rawLuaFilePath); + AZ::Outcome CreateLuaAsset(const ScriptCanvasEditor::SourceHandle& editAsset, AZStd::string_view rawLuaFilePath); int GetBuilderVersion(); diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp index 7d4cfec909..f337580cf3 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp @@ -29,6 +29,7 @@ #include #include #include +#include namespace ScriptCanvasBuilder { @@ -77,17 +78,17 @@ namespace ScriptCanvasBuilder return ScriptCanvas::Translation::ParseGraph(request); } - AZ::Outcome CreateLuaAsset(AZ::Entity* buildEntity, AZ::Data::AssetId scriptAssetId, AZStd::string_view rawLuaFilePath) + AZ::Outcome CreateLuaAsset(const ScriptCanvasEditor::SourceHandle& editAsset, AZStd::string_view rawLuaFilePath) { AZStd::string fullPath(rawLuaFilePath); AZStd::string fileNameOnly; AzFramework::StringFunc::Path::GetFullFileName(rawLuaFilePath.data(), fileNameOnly); AzFramework::StringFunc::Path::Normalize(fullPath); - auto sourceGraph = PrepareSourceGraph(buildEntity); + auto sourceGraph = PrepareSourceGraph(editAsset.Mod()->GetEntity()); ScriptCanvas::Grammar::Request request; - request.scriptAssetId = scriptAssetId; + request.scriptAssetId = editAsset.Id(); request.graph = sourceGraph; request.name = fileNameOnly; request.rawSaveDebugOutput = ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile; @@ -117,7 +118,7 @@ namespace ScriptCanvasBuilder auto& translation = translationResult.m_translations.find(ScriptCanvas::Translation::TargetFlags::Lua)->second; AZ::Data::Asset asset; - scriptAssetId.m_subId = AZ::ScriptAsset::CompiledAssetSubId; + AZ::Data::AssetId scriptAssetId(editAsset.Id(), AZ::ScriptAsset::CompiledAssetSubId); asset.Create(scriptAssetId); auto writeStream = asset.Get()->CreateWriteStream(); @@ -144,12 +145,12 @@ namespace ScriptCanvasBuilder return AZ::Success(result); } - AZ::Outcome, AZStd::string> CreateRuntimeAsset(const AZ::Data::Asset& editAsset) + AZ::Outcome, AZStd::string> CreateRuntimeAsset(const ScriptCanvasEditor::SourceHandle& editAsset) { // Flush asset manager events to ensure no asset references are held by closures queued on Ebuses. AZ::Data::AssetManager::Instance().DispatchEvents(); - auto runtimeAssetId = editAsset.GetId(); + AZ::Data::AssetId runtimeAssetId = editAsset.Id(); runtimeAssetId.m_subId = AZ_CRC("RuntimeData", 0x163310ae); AZ::Data::Asset runtimeAsset; runtimeAsset.Create(runtimeAssetId); diff --git a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.h b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.h index 4d1be42d35..8593429b92 100644 --- a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.h +++ b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.h @@ -11,6 +11,7 @@ #include #include #include +#include namespace ScriptCanvas { diff --git a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl index 05541196f7..b1bc7321e6 100644 --- a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl +++ b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl @@ -75,7 +75,7 @@ namespace ScriptCanvasEditor AZ_Assert(loadResult.m_runtimeAsset, "failed to load dependent asset"); AZ::Outcome luaAssetOutcome = AZ::Failure(AZStd::string("lua asset creation for function failed")); - ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(luaAssetOutcome, &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateLuaAsset, loadResult.m_editorAsset, loadResult.m_graphPath); + ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(luaAssetOutcome, &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateLuaAsset, loadResult.m_editorAsset, loadResult.m_editorAsset.Path().c_str()); AZ_Assert(luaAssetOutcome.IsSuccess(), "failed to create Lua asset"); AZStd::string modulePath = namespacePath[0].data(); @@ -112,18 +112,14 @@ namespace ScriptCanvasEditor AZ_INLINE LoadTestGraphResult LoadTestGraph(AZStd::string_view graphPath) { - AZ::Data::Asset editorAsset; - ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(editorAsset, &ScriptCanvasEditor::EditorAssetConversionBusTraits::LoadAsset, graphPath); - - if (editorAsset.GetData()) + if (auto loadFileOutcome = LoadFromFile(graphPath); loadFileOutcome.IsSuccess()) { AZ::Outcome< AZ::Data::Asset, AZStd::string> assetOutcome = AZ::Failure(AZStd::string("asset creation failed")); - ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(assetOutcome, &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateRuntimeAsset, editorAsset); + ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(assetOutcome, &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateRuntimeAsset, loadFileOutcome.GetValue()); if (assetOutcome.IsSuccess()) { LoadTestGraphResult result; - result.m_graphPath = graphPath; - result.m_editorAsset = editorAsset; + result.m_editorAsset = loadFileOutcome.TakeValue(); result.m_runtimeAsset = assetOutcome.GetValue(); result.m_entity = AZStd::make_unique("Loaded Graph"); return result; @@ -164,8 +160,7 @@ namespace ScriptCanvasEditor reporter.SetExecutionMode(mode); LoadTestGraphResult loadResult; - loadResult.m_graphPath = asset.GetHint().c_str(); - loadResult.m_editorAsset = asset; + loadResult.m_editorAsset = SourceHandle(nullptr, assetId.m_guid, asset.GetHint()); AZ::EntityId scriptCanvasId; loadResult.m_entity = AZStd::make_unique("Loaded test graph"); loadResult.m_runtimeAsset = runtimeAsset; @@ -206,7 +201,8 @@ namespace ScriptCanvasEditor { ScopedOutputSuppression outputSuppressor; AZ::Outcome luaAssetOutcome = AZ::Failure(AZStd::string("lua asset creation failed")); - ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(luaAssetOutcome, &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateLuaAsset, loadResult.m_editorAsset, loadResult.m_graphPath); + ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(luaAssetOutcome + , &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateLuaAsset, loadResult.m_editorAsset, loadResult.m_editorAsset.Path().c_str()); reporter.MarkParseAttemptMade(); if (luaAssetOutcome.IsSuccess()) diff --git a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasTraceUtilities.h b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasTraceUtilities.h index a87f4450c2..033eed3efd 100644 --- a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasTraceUtilities.h +++ b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasTraceUtilities.h @@ -27,6 +27,7 @@ #include #include #include +#include namespace AZ { @@ -45,11 +46,10 @@ namespace ScriptCanvasEditor struct LoadTestGraphResult { - AZStd::string_view m_graphPath; AZStd::unique_ptr m_entity; ScriptCanvas::RuntimeComponent* m_runtimeComponent = nullptr; bool m_nativeFunctionFound = false; - AZ::Data::Asset m_editorAsset; + SourceHandle m_editorAsset; AZ::Data::Asset m_runtimeAsset; AZ::Data::Asset m_scriptAsset; }; From 62878489a352e2ca8b456dd25e219d630a40bea2 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Thu, 18 Nov 2021 10:41:46 -0800 Subject: [PATCH 022/128] more aggressively release graph memory in version explorer Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Builder/ScriptCanvasBuilderComponent.cpp | 1 - .../Builder/ScriptCanvasBuilderWorker.cpp | 44 ++------------- .../Code/Builder/ScriptCanvasBuilderWorker.h | 4 +- .../ScriptCanvasBuilderWorkerUtility.cpp | 4 +- .../Windows/Tools/UpgradeTool/Modifier.cpp | 55 +++++++++++-------- .../View/Windows/Tools/UpgradeTool/Modifier.h | 3 +- .../Windows/Tools/UpgradeTool/Scanner.cpp | 40 ++++++++------ .../View/Windows/Tools/UpgradeTool/Scanner.h | 2 +- .../Code/Include/ScriptCanvas/Core/Core.h | 2 +- .../Code/Include/ScriptCanvas/Core/Graph.cpp | 16 +++++- 10 files changed, 80 insertions(+), 91 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.cpp index a08e006a19..019dd4f5e3 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.cpp @@ -48,7 +48,6 @@ namespace ScriptCanvasBuilder SharedHandlers HandleAssetTypes() { SharedHandlers handlers; - // handlers.m_editorAssetHandler = RegisterHandler("scriptcanvas", false); handlers.m_subgraphInterfaceHandler = RegisterHandler("scriptcanvas_fn_compiled", true); handlers.m_runtimeAssetHandler = RegisterHandler("scriptcanvas_compiled", true); diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp index f38654f565..faad1871ac 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp @@ -35,7 +35,6 @@ namespace ScriptCanvasBuilder { void Worker::Activate(const AssetHandlers& handlers) { - m_editorAssetHandler = handlers.m_editorAssetHandler; m_runtimeAssetHandler = handlers.m_runtimeAssetHandler; m_subgraphInterfaceHandler = handlers.m_subgraphInterfaceHandler; } @@ -255,49 +254,14 @@ namespace ScriptCanvasBuilder return; } - if (!m_editorAssetHandler) - { - AZ_Error(s_scriptCanvasBuilder, false, R"(Exporting of .scriptcanvas for "%s" file failed as no editor asset handler was registered for script canvas. The ScriptCanvas Gem might not be enabled.)", fullPath.data()); - return; - } - if (!m_runtimeAssetHandler) { AZ_Error(s_scriptCanvasBuilder, false, R"(Exporting of .scriptcanvas for "%s" file failed as no runtime asset handler was registered for script canvas.)", fullPath.data()); return; } - AZStd::shared_ptr assetDataStream = AZStd::make_shared(); - - AZ::IO::FileIOStream stream(fullPath.c_str(), AZ::IO::OpenMode::ModeRead); - if (!AZ::IO::RetryOpenStream(stream)) - { - AZ_Warning(s_scriptCanvasBuilder, false, "CreateJobs for \"%s\" failed because the source file could not be opened.", fullPath.data()); - return; - } - - // Read the asset into a memory buffer, then hand ownership of the buffer to assetDataStream - { - AZ::IO::FileIOStream ioStream; - if (!ioStream.Open(fullPath.data(), AZ::IO::OpenMode::ModeRead)) - { - AZ_Warning(s_scriptCanvasBuilder, false, "CreateJobs for \"%s\" failed because the source file could not be opened.", fullPath.data()); - return; - } - AZStd::vector fileBuffer(ioStream.GetLength()); - size_t bytesRead = ioStream.Read(fileBuffer.size(), fileBuffer.data()); - if (bytesRead != ioStream.GetLength()) - { - AZ_Warning(s_scriptCanvasBuilder, false, AZStd::string::format("File failed to read completely: %s", fullPath.data()).c_str()); - return; - } - - assetDataStream->Open(AZStd::move(fileBuffer)); - } - - AZ::Data::Asset asset; - asset.Create(request.m_sourceFileUUID); - if (m_editorAssetHandler->LoadAssetDataFromStream(asset, assetDataStream, nullptr) != AZ::Data::AssetHandler::LoadResult::LoadComplete) + auto loadOutcome = ScriptCanvasEditor::LoadFromFile(request.m_fullPath); + if (!loadOutcome.IsSuccess()) { AZ_Error(s_scriptCanvasBuilder, false, R"(Loading of ScriptCanvas asset for source file "%s" has failed)", fullPath.data()); return; @@ -310,9 +274,11 @@ namespace ScriptCanvasBuilder AzFramework::StringFunc::Path::Join(request.m_tempDirPath.c_str(), fileNameOnly.c_str(), runtimeScriptCanvasOutputPath, true, true); AzFramework::StringFunc::Path::ReplaceExtension(runtimeScriptCanvasOutputPath, ScriptCanvas::RuntimeAsset::GetFileExtension()); + auto sourceHandle = loadOutcome.TakeValue(); + if (request.m_jobDescription.m_jobKey == s_scriptCanvasProcessJobKey) { - AZ::Entity* buildEntity = asset.Get()->GetScriptCanvasEntity(); + AZ::Entity* buildEntity = sourceHandle.Get()->GetEntity(); ProcessTranslationJobInput input; input.assetID = AZ::Data::AssetId(request.m_sourceFileUUID, AZ_CRC("RuntimeData", 0x163310ae)); input.request = &request; diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h index 816206ce33..e1bf80aa2e 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h @@ -62,6 +62,7 @@ namespace ScriptCanvasBuilder ForceBuildForDevTest0, ForceBuildForDevTest1, + ForceBuildForDevTest2, // add new entries above Current, @@ -73,7 +74,6 @@ namespace ScriptCanvasBuilder struct AssetHandlers { - AZ::Data::AssetHandler* m_editorAssetHandler = nullptr; AZ::Data::AssetHandler* m_editorFunctionAssetHandler = nullptr; AZ::Data::AssetHandler* m_runtimeAssetHandler = nullptr; AZ::Data::AssetHandler* m_subgraphInterfaceHandler = nullptr; @@ -84,7 +84,6 @@ namespace ScriptCanvasBuilder struct SharedHandlers { - HandlerOwnership m_editorAssetHandler{}; HandlerOwnership m_editorFunctionAssetHandler{}; HandlerOwnership m_runtimeAssetHandler{}; HandlerOwnership m_subgraphInterfaceHandler{}; @@ -173,7 +172,6 @@ namespace ScriptCanvasBuilder void ShutDown() override {}; private: - AZ::Data::AssetHandler* m_editorAssetHandler = nullptr; AZ::Data::AssetHandler* m_runtimeAssetHandler = nullptr; AZ::Data::AssetHandler* m_subgraphInterfaceHandler = nullptr; diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp index f337580cf3..a68aeae5e9 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp @@ -34,15 +34,13 @@ namespace ScriptCanvasBuilder { AssetHandlers::AssetHandlers(SharedHandlers& source) - : m_editorAssetHandler(source.m_editorAssetHandler.first) - , m_editorFunctionAssetHandler(source.m_editorFunctionAssetHandler.first) + : m_editorFunctionAssetHandler(source.m_editorFunctionAssetHandler.first) , m_runtimeAssetHandler(source.m_runtimeAssetHandler.first) , m_subgraphInterfaceHandler(source.m_subgraphInterfaceHandler.first) {} void SharedHandlers::DeleteOwnedHandlers() { - DeleteIfOwned(m_editorAssetHandler); DeleteIfOwned(m_editorFunctionAssetHandler); DeleteIfOwned(m_runtimeAssetHandler); DeleteIfOwned(m_subgraphInterfaceHandler); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp index 56d7264859..830d09c7dd 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp @@ -32,13 +32,6 @@ namespace ScriptCanvasEditor AZ::SystemTickBus::Handler::BusConnect(); } - const SourceHandle& Modifier::GetCurrentAsset() const - { - return m_state == State::GatheringDependencies - ? m_assets[m_assetIndex] - : m_assets[m_dependencyOrderedAssetIndicies[m_assetIndex]]; - } - AZStd::unordered_set& Modifier::GetOrCreateDependencyIndexSet() { auto iter = m_dependencies.find(m_assetIndex); @@ -101,36 +94,40 @@ namespace ScriptCanvasEditor { anyFailures = true; VE_LOG("Modifier: ERROR - Failed to gather dependencies from graph data: %s" - , GetCurrentAsset().Path().c_str()) + , ModCurrentAsset().Path().c_str()) } } else { anyFailures = true; VE_LOG("Modifier: ERROR - Failed to load asset %s for modification, even though it scanned properly" - , GetCurrentAsset().Path().c_str()); + , ModCurrentAsset().Path().c_str()); } ModelNotificationsBus::Broadcast ( &ModelNotificationsTraits::OnUpgradeDependenciesGathered - , GetCurrentAsset() + , ModCurrentAsset() , anyFailures ? Result::Failure : Result::Success); + ReleaseCurrentAsset(); + // Flush asset database events to ensure no asset references are held by closures queued on Ebuses. AZ::Data::AssetManager::Instance().DispatchEvents(); } SourceHandle Modifier::LoadAsset() { - auto outcome = LoadFromFile(GetCurrentAsset().Path().c_str()); - if (outcome.IsSuccess()) + auto& handle = ModCurrentAsset(); + if (!handle.IsValid()) { - return outcome.TakeValue(); - } - else - { - return {}; + auto outcome = LoadFromFile(handle.Path().c_str()); + if (outcome.IsSuccess()) + { + handle = outcome.TakeValue(); + } } + + return handle; } void Modifier::ModificationComplete(const ModificationResult& result) @@ -147,12 +144,19 @@ namespace ScriptCanvasEditor } } + SourceHandle& Modifier::ModCurrentAsset() + { + return m_state == State::GatheringDependencies + ? m_assets[m_assetIndex] + : m_assets[m_dependencyOrderedAssetIndicies[m_assetIndex]]; + } + void Modifier::ModifyCurrentAsset() { m_result = {}; - m_result.asset = GetCurrentAsset(); + m_result.asset = ModCurrentAsset(); - ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeModificationBegin, m_config, GetCurrentAsset()); + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeModificationBegin, m_config, ModCurrentAsset()); if (auto asset = LoadAsset(); asset.IsValid()) { @@ -169,13 +173,19 @@ namespace ScriptCanvasEditor void Modifier::ModifyNextAsset() { ModelNotificationsBus::Broadcast - ( &ModelNotificationsTraits::OnUpgradeModificationEnd, m_config, GetCurrentAsset(), m_result); + ( &ModelNotificationsTraits::OnUpgradeModificationEnd, m_config, ModCurrentAsset(), m_result); ModificationNotificationsBus::Handler::BusDisconnect(); m_modifyState = ModifyState::Idle; + ReleaseCurrentAsset(); ++m_assetIndex; m_result = {}; } + void Modifier::ReleaseCurrentAsset() + { + ModCurrentAsset() = ModCurrentAsset().Describe(); + } + void Modifier::ReportModificationError(AZStd::string_view report) { m_result.asset = {}; @@ -286,7 +296,7 @@ namespace ScriptCanvasEditor m_dependencyOrderedAssetIndicies.push_back(index); } - // go straight into ModifyinGraphs + // go straight into ModifyingGraphs m_assetIndex = m_assets.size(); } } @@ -309,6 +319,7 @@ namespace ScriptCanvasEditor else { GatherDependencies(); + ReleaseCurrentAsset(); ++m_assetIndex; } } @@ -370,7 +381,7 @@ namespace ScriptCanvasEditor (ScriptCanvas::k_VersionExplorerWindow.data() , false , "Modifier: Dependency sort has failed during, circular dependency detected for Asset: %s" - , modifier->GetCurrentAsset().Path().c_str()); + , modifier->ModCurrentAsset().Path().c_str()); return; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h index c57af605e3..78c9b3a877 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h @@ -83,12 +83,13 @@ namespace ScriptCanvasEditor FileSaveResult m_fileSaveResult; void GatherDependencies(); - const SourceHandle& GetCurrentAsset() const; AZStd::unordered_set& GetOrCreateDependencyIndexSet(); SourceHandle LoadAsset(); + SourceHandle& ModCurrentAsset(); void ModifyCurrentAsset(); void ModifyNextAsset(); void ModificationComplete(const ModificationResult& result) override; + void ReleaseCurrentAsset(); void ReportModificationError(AZStd::string_view report); void ReportModificationSuccess(); void ReportSaveResult(); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp index d959a6b6ab..f9fc6e497d 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp @@ -32,8 +32,12 @@ namespace ScannerCpp && entry->GetFullPath().ends_with(".scriptcanvas")) { auto sourceEntry = azrtti_cast(entry); + + AZStd::string fullPath = sourceEntry->GetFullPath(); + AzFramework::StringFunc::Path::Normalize(fullPath); + result.m_catalogAssets.push_back( - ScriptCanvasEditor::SourceHandle(nullptr, sourceEntry->GetSourceUuid(), sourceEntry->GetFullPath())); + ScriptCanvasEditor::SourceHandle(nullptr, sourceEntry->GetSourceUuid(), fullPath)); } const int rowCount = model.rowCount(index); @@ -79,23 +83,18 @@ namespace ScriptCanvasEditor { if (m_config.filter && m_config.filter(asset) == ScanConfiguration::Filter::Exclude) { - VE_LOG("Scanner: Excluded: %s ", GetCurrentAsset().Path().c_str()); - m_result.m_filteredAssets.push_back(GetCurrentAsset().Describe()); - ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanFilteredGraph, GetCurrentAsset()); + VE_LOG("Scanner: Excluded: %s ", ModCurrentAsset().Path().c_str()); + m_result.m_filteredAssets.push_back(ModCurrentAsset().Describe()); + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanFilteredGraph, ModCurrentAsset()); } else { - VE_LOG("Scanner: Included: %s ", GetCurrentAsset().Path().c_str()); - m_result.m_unfiltered.push_back(GetCurrentAsset().Describe()); - ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanUnFilteredGraph, GetCurrentAsset()); + VE_LOG("Scanner: Included: %s ", ModCurrentAsset().Path().c_str()); + m_result.m_unfiltered.push_back(ModCurrentAsset().Describe()); + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanUnFilteredGraph, ModCurrentAsset()); } } - const SourceHandle& Scanner::GetCurrentAsset() const - { - return m_result.m_catalogAssets[m_catalogAssetIndex]; - } - const ScanResult& Scanner::GetResult() const { return m_result; @@ -103,7 +102,7 @@ namespace ScriptCanvasEditor SourceHandle Scanner::LoadAsset() { - auto fileOutcome = LoadFromFile(GetCurrentAsset().Path().c_str()); + auto fileOutcome = LoadFromFile(ModCurrentAsset().Path().c_str()); if (fileOutcome.IsSuccess()) { return fileOutcome.GetValue(); @@ -114,6 +113,11 @@ namespace ScriptCanvasEditor } } + SourceHandle& Scanner::ModCurrentAsset() + { + return m_result.m_catalogAssets[m_catalogAssetIndex]; + } + void Scanner::OnSystemTick() { if (m_catalogAssetIndex == m_result.m_catalogAssets.size()) @@ -130,17 +134,17 @@ namespace ScriptCanvasEditor { if (auto asset = LoadAsset(); asset.IsValid()) { - VE_LOG("Scanner: Loaded: %s ", GetCurrentAsset().Path().c_str()); + VE_LOG("Scanner: Loaded: %s ", ModCurrentAsset().Path().c_str()); FilterAsset(asset); } else { - VE_LOG("Scanner: Failed to load: %s ", GetCurrentAsset().Path().c_str()); - m_result.m_loadErrors.push_back(GetCurrentAsset()); - ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanLoadFailure, GetCurrentAsset()); + VE_LOG("Scanner: Failed to load: %s ", ModCurrentAsset().Path().c_str()); + m_result.m_loadErrors.push_back(ModCurrentAsset().Describe()); + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanLoadFailure, ModCurrentAsset()); } - VE_LOG("Scanner: scan of %s complete", GetCurrentAsset().Path().c_str()); + VE_LOG("Scanner: scan of %s complete", ModCurrentAsset().Path().c_str()); ++m_catalogAssetIndex; } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h index f276c146da..8e086a10b0 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h @@ -34,8 +34,8 @@ namespace ScriptCanvasEditor ScanResult m_result; void FilterAsset(SourceHandle); - const SourceHandle& GetCurrentAsset() const; SourceHandle LoadAsset(); + SourceHandle& ModCurrentAsset(); void OnSystemTick() override; }; } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h index 9e7ffc96f8..a57d2dc3a1 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h @@ -27,7 +27,7 @@ #define OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED -#define EDITOR_ASSET_SUPPORT_ENABLED +// #define EDITOR_ASSET_SUPPORT_ENABLED namespace AZ { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp index ee500514dc..3d802e4fbc 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp @@ -52,6 +52,7 @@ namespace GraphCpp VariablePanelSymantics, AddVersionData, RemoveFunctionGraphMarker, + FixupVersionDataTypeId, // label your version above Current }; @@ -71,13 +72,24 @@ namespace ScriptCanvas componentElementNode.AddElementWithData(context, "m_assetType", azrtti_typeid()); } - if (componentElementNode.GetVersion() < GraphCpp::GraphVersion::RemoveFunctionGraphMarker) + if (componentElementNode.GetVersion() <= GraphCpp::GraphVersion::RemoveFunctionGraphMarker) { componentElementNode.RemoveElementByName(AZ_CRC_CE("isFunctionGraph")); } + if (componentElementNode.GetVersion() < GraphCpp::GraphVersion::FixupVersionDataTypeId) + { + if (auto subElement = componentElementNode.FindSubElement(AZ_CRC_CE("versionData"))) + { + if (subElement->GetId() == azrtti_typeid()) + { + componentElementNode.RemoveElementByName(AZ_CRC_CE("versionData")); + } + } + } + return true; - } + }s Graph::Graph(const ScriptCanvasId& scriptCanvasId) : m_scriptCanvasId(scriptCanvasId) From 487e2fb5bb984af8f701feff5f7f894522699f12 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Thu, 18 Nov 2021 13:31:00 -0800 Subject: [PATCH 023/128] remove typo Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp index 3d802e4fbc..aff212fa4c 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp @@ -89,7 +89,7 @@ namespace ScriptCanvas } return true; - }s + } Graph::Graph(const ScriptCanvasId& scriptCanvasId) : m_scriptCanvasId(scriptCanvasId) From e89ec94c380947ee6dbc5c5eb031888dcce59b18 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Thu, 18 Nov 2021 16:59:35 -0800 Subject: [PATCH 024/128] update CMakeLists.txt in preparation for removing the TestSuite_Main_GPU_Optimized file, add compare_screenshot_to_golden_image function, add hydra_AtomGPU_LightComponentScreenshotsMatch.py hydra script Signed-off-by: jromnoa <80134229+jromnoa@users.noreply.github.com> --- .../Gem/PythonTests/Atom/CMakeLists.txt | 14 - .../PythonTests/Atom/TestSuite_Main_GPU.py | 87 ----- .../Atom/TestSuite_Main_GPU_Optimized.py | 47 ++- .../Atom/atom_utils/atom_component_helper.py | 326 +++++++++--------- ..._AtomGPU_LightComponentScreenshotsMatch.py | 0 5 files changed, 213 insertions(+), 261 deletions(-) create mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_LightComponentScreenshotsMatch.py diff --git a/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt index 87a66c880e..26eb96e7ec 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt @@ -47,18 +47,4 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED) COMPONENT Atom ) - ly_add_pytest( - NAME AutomatedTesting::Atom_TestSuite_Main_GPU_Optimized - TEST_SUITE main - TEST_REQUIRES gpu - TEST_SERIAL - TIMEOUT 1200 - PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_GPU_Optimized.py - RUNTIME_DEPENDENCIES - AssetProcessor - AutomatedTesting.Assets - Editor - COMPONENT - Atom - ) endif() diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py index f0e92c7e3e..690f8aeea5 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py @@ -5,10 +5,8 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import datetime import logging import os -import zipfile import pytest @@ -23,96 +21,11 @@ DEFAULT_SUBFOLDER_PATH = 'user/PythonTests/Automated/Screenshots' TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests") -def golden_images_directory(): - """ - Uses this file location to return the valid location for golden image files. - :return: The path to the golden_images directory, but raises an IOError if the golden_images directory is missing. - """ - current_file_directory = os.path.join(os.path.dirname(__file__)) - golden_images_dir = os.path.join(current_file_directory, 'golden_images') - - if not os.path.exists(golden_images_dir): - raise IOError( - f'golden_images" directory was not found at path "{golden_images_dir}"' - f'Please add a "golden_images" directory inside: "{current_file_directory}"' - ) - - return golden_images_dir - - -def create_screenshots_archive(screenshot_path): - """ - Creates a new zip file archive at archive_path containing all files listed within archive_path. - :param screenshot_path: location containing the files to archive, the zip archive file will also be saved here. - :return: None, but creates a new zip file archive inside path containing all of the files inside archive_path. - """ - files_to_archive = [] - - # Search for .png and .ppm files to add to the zip archive file. - for (folder_name, sub_folders, file_names) in os.walk(screenshot_path): - for file_name in file_names: - if file_name.endswith(".png") or file_name.endswith(".ppm"): - file_path = os.path.join(folder_name, file_name) - files_to_archive.append(file_path) - - # Setup variables for naming the zip archive file. - timestamp = datetime.datetime.now().timestamp() - formatted_timestamp = datetime.datetime.utcfromtimestamp(timestamp).strftime("%Y-%m-%d_%H-%M-%S") - screenshots_file = os.path.join(screenshot_path, f'zip_archive_{formatted_timestamp}.zip') - - # Write all of the valid .png and .ppm files to the archive file. - with zipfile.ZipFile(screenshots_file, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=True) as zip_archive: - for file_path in files_to_archive: - file_name = os.path.basename(file_path) - zip_archive.write(file_path, file_name) - - @pytest.mark.parametrize("project", ["AutomatedTesting"]) @pytest.mark.parametrize("launcher_platform", ["windows_editor"]) @pytest.mark.parametrize("level", ["Base"]) class TestAllComponentsIndepthTests(object): - @pytest.mark.parametrize("screenshot_name", ["AtomBasicLevelSetup.ppm"]) - @pytest.mark.test_case_id("C34603773") - def test_BasicLevelSetup_SetsUpLevel( - self, request, editor, workspace, project, launcher_platform, level, screenshot_name): - """ - Please review the hydra script run by this test for more specific test info. - Tests that a basic rendering level setup can be created (lighting, meshes, materials, etc.). - """ - # Clear existing test screenshots before starting test. - screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH) - test_screenshots = [os.path.join(screenshot_directory, screenshot_name)] - file_system.delete(test_screenshots, True, True) - - golden_images = [os.path.join(golden_images_directory(), screenshot_name)] - - level_creation_expected_lines = [ - "Viewport is set to the expected size: True", - "Exited game mode" - ] - unexpected_lines = ["Traceback (most recent call last):"] - - hydra.launch_and_validate_results( - request, - TEST_DIRECTORY, - editor, - "hydra_GPUTest_BasicLevelSetup.py", - timeout=180, - expected_lines=level_creation_expected_lines, - unexpected_lines=unexpected_lines, - halt_on_unexpected=True, - cfg_args=[level], - null_renderer=False, - ) - - similarity_threshold = 0.99 - for test_screenshot, golden_image in zip(test_screenshots, golden_images): - screenshot_comparison_result = compare_screenshot_similarity( - test_screenshot, golden_image, similarity_threshold, True, screenshot_directory) - if screenshot_comparison_result != "Screenshots match": - raise Exception(f"Screenshot test failed: {screenshot_comparison_result}") - @pytest.mark.test_case_id("C34525095") def test_LightComponent_ScreenshotMatchesGoldenImage( self, request, editor, workspace, project, launcher_platform, level): diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU_Optimized.py index 568768e12e..2cb5828958 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU_Optimized.py @@ -11,12 +11,12 @@ import pytest import ly_test_tools.environment.file_system as file_system from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite from ly_test_tools.image.screenshot_compare_qssim import qssim as compare_screenshots -from .atom_utils.atom_component_helper import create_screenshots_archive, golden_images_directory +from .atom_utils.atom_component_helper import ( + create_screenshots_archive, compare_screenshot_to_golden_image, golden_images_directory) DEFAULT_SUBFOLDER_PATH = 'user/PythonTests/Automated/Screenshots' -@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.") @pytest.mark.parametrize("project", ["AutomatedTesting"]) @pytest.mark.parametrize("launcher_platform", ['windows_editor']) class TestAutomation(EditorTestSuite): @@ -36,9 +36,44 @@ class TestAutomation(EditorTestSuite): test_screenshots = [os.path.join(screenshot_directory, self.screenshot_name)] file_system.delete(test_screenshots, True, True) + golden_images = [os.path.join(golden_images_directory(), screenshot_name)] + from Atom.tests import hydra_AtomGPU_BasicLevelSetup as test_module - golden_images = [os.path.join(golden_images_directory(), screenshot_name)] - for test_screenshot, golden_screenshot in zip(test_screenshots, golden_images): - compare_screenshots(test_screenshot, golden_screenshot) - create_screenshots_archive(screenshot_directory) + assert compare_screenshot_to_golden_image(screenshot_directory, test_screenshots, golden_images, 0.99) is True + + @pytest.mark.test_case_id("C34525095") + class AtomGPU_LightComponent_ScreenshotMatchesGoldenImage(EditorSharedTest): + use_null_renderer = False # Default is True + screenshot_names = [ + "AreaLight_1.ppm", + "AreaLight_2.ppm", + "AreaLight_3.ppm", + "AreaLight_4.ppm", + "AreaLight_5.ppm", + "SpotLight_1.ppm", + "SpotLight_2.ppm", + "SpotLight_3.ppm", + "SpotLight_4.ppm", + "SpotLight_5.ppm", + "SpotLight_6.ppm", + ] + test_screenshots = [] # Gets set by setup() + screenshot_directory = "" # Gets set by setup() + + # Clear existing test screenshots before starting test. + def setup(self, workspace): + screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH) + for screenshot in self.screenshot_names: + screenshot_path = os.path.join(screenshot_directory, screenshot) + self.test_screenshots.append(screenshot_path) + file_system.delete(self.test_screenshots, True, True) + + golden_images = [] + for golden_image in screenshot_names: + golden_image_path = os.path.join(golden_images_directory(), golden_image) + golden_images.append(golden_image_path) + + from Atom.tests import hydra_AtomGPU_LightComponentScreenshotsMatch as test_module + + assert compare_screenshot_to_golden_image(screenshot_directory, test_screenshots, golden_images, 0.99) is True diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py index 9f37873557..28ae72c2b3 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py @@ -93,161 +93,179 @@ def compare_screenshot_similarity( return result -def create_basic_atom_level(level_name): +def compare_screenshot_to_golden_image( + screenshot_directory, test_screenshots, golden_images, similarity_threshold=0.99): """ - Creates a new level inside the Editor matching level_name & adds the following: - 1. "default_level" entity to hold all other entities. - 2. Adds Grid, Global Skylight (IBL), ground Mesh, Directional Light, Sphere w/ material+mesh, & Camera components. - 3. Each of these components has its settings tweaked slightly to match the ideal scene to test Atom rendering. - :param level_name: name of the level to create and apply this basic setup to. - :return: None + Compares a list of test_screenshots to a list of golden_images and return True if they match within the + similarity threshold set. Otherwise, it will raise ImageComparisonTestFailure with a failure message. + :param screenshot_directory: path to the directory containing screenshots for creating .zip archives. + :param test_screenshots: list of test screenshot path strings. + :param golden_images: list of golden image path strings. + :param similarity_threshold: float threshold tolerance to set when comparing screenshots to golden images. """ - import azlmbr.asset as asset - import azlmbr.bus as bus - import azlmbr.camera as camera - import azlmbr.editor as editor - import azlmbr.entity as entity - import azlmbr.legacy.general as general - import azlmbr.math as math - import azlmbr.object + for test_screenshot, golden_image in zip(test_screenshots, golden_images): + screenshot_comparison_result = compare_screenshot_similarity( + test_screenshot, golden_image, similarity_threshold, True, screenshot_directory) + if screenshot_comparison_result != "Screenshots match": + raise ImageComparisonTestFailure(f"Screenshot test failed: {screenshot_comparison_result}") - import editor_python_test_tools.hydra_editor_utils as hydra - from editor_python_test_tools.editor_test_helper import EditorTestHelper + return True - helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper") - - # Wait for Editor idle loop before executing Python hydra scripts. - general.idle_enable(True) - - # Basic setup for opened level. - helper.open_level(level_name="Base") - general.idle_wait(1.0) - general.update_viewport() - general.idle_wait(0.5) # half a second is more than enough for updating the viewport. - - # Close out problematic windows, FPS meters, and anti-aliasing. - if general.is_helpers_shown(): # Turn off the helper gizmos if visible - general.toggle_helpers() - general.idle_wait(1.0) - if general.is_pane_visible("Error Report"): # Close Error Report windows that block focus. - general.close_pane("Error Report") - if general.is_pane_visible("Error Log"): # Close Error Log windows that block focus. - general.close_pane("Error Log") - general.idle_wait(1.0) - general.run_console("r_displayInfo=0") - general.idle_wait(1.0) - - # Delete all existing entities & create default_level entity - search_filter = azlmbr.entity.SearchFilter() - all_entities = entity.SearchBus(azlmbr.bus.Broadcast, "SearchEntities", search_filter) - editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", all_entities) - default_level = hydra.Entity("default_level") - default_position = math.Vector3(0.0, 0.0, 0.0) - default_level.create_entity(default_position, ["Grid"]) - default_level.get_set_test(0, "Controller|Configuration|Secondary Grid Spacing", 1.0) - - # Set the viewport up correctly after adding the parent default_level entity. - screen_width = 1280 - screen_height = 720 - degree_radian_factor = 0.0174533 # Used by "Rotation" property for the Transform component. - general.set_viewport_size(screen_width, screen_height) - general.update_viewport() - helper.wait_for_condition( - function=lambda: helper.isclose(a=general.get_viewport_size().x, b=screen_width, rel_tol=0.1) - and helper.isclose(a=general.get_viewport_size().y, b=screen_height, rel_tol=0.1), - timeout_in_seconds=4.0 - ) - result = helper.isclose(a=general.get_viewport_size().x, b=screen_width, rel_tol=0.1) and helper.isclose( - a=general.get_viewport_size().y, b=screen_height, rel_tol=0.1) - general.log(general.get_viewport_size().x) - general.log(general.get_viewport_size().y) - general.log(general.get_viewport_size().z) - general.log(f"Viewport is set to the expected size: {result}") - general.log("Basic level created") - general.run_console("r_DisplayInfo = 0") - - # Create global_skylight entity and set the properties - global_skylight = hydra.Entity("global_skylight") - global_skylight.create_entity( - entity_position=default_position, - components=["HDRi Skybox", "Global Skylight (IBL)"], - parent_id=default_level.id) - global_skylight_asset_path = os.path.join("LightingPresets", "default_iblskyboxcm.exr.streamingimage") - global_skylight_asset_value = asset.AssetCatalogRequestBus( - bus.Broadcast, "GetAssetIdByPath", global_skylight_asset_path, math.Uuid(), False) - global_skylight.get_set_test(0, "Controller|Configuration|Cubemap Texture", global_skylight_asset_value) - global_skylight.get_set_test(1, "Controller|Configuration|Diffuse Image", global_skylight_asset_value) - global_skylight.get_set_test(1, "Controller|Configuration|Specular Image", global_skylight_asset_value) - - # Create ground_plane entity and set the properties - ground_plane = hydra.Entity("ground_plane") - ground_plane.create_entity( - entity_position=default_position, - components=["Material"], - parent_id=default_level.id) - azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalUniformScale", ground_plane.id, 32.0) - - # Work around to add the correct Atom Mesh component and asset. - mesh_type_id = azlmbr.globals.property.EditorMeshComponentTypeId - ground_plane.components.append( - editor.EditorComponentAPIBus( - bus.Broadcast, "AddComponentsOfType", ground_plane.id, [mesh_type_id] - ).GetValue()[0] - ) - ground_plane_mesh_asset_path = os.path.join("TestData", "Objects", "plane.azmodel") - ground_plane_mesh_asset_value = asset.AssetCatalogRequestBus( - bus.Broadcast, "GetAssetIdByPath", ground_plane_mesh_asset_path, math.Uuid(), False) - ground_plane.get_set_test(1, "Controller|Configuration|Mesh Asset", ground_plane_mesh_asset_value) - - # Add Atom Material component and asset. - ground_plane_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_chrome.azmaterial") - ground_plane_material_asset_value = asset.AssetCatalogRequestBus( - bus.Broadcast, "GetAssetIdByPath", ground_plane_material_asset_path, math.Uuid(), False) - ground_plane.get_set_test(0, "Default Material|Material Asset", ground_plane_material_asset_value) - - # Create directional_light entity and set the properties - directional_light = hydra.Entity("directional_light") - directional_light.create_entity( - entity_position=math.Vector3(0.0, 0.0, 10.0), - components=["Directional Light"], - parent_id=default_level.id) - directional_light_rotation = math.Vector3(degree_radian_factor * -90.0, 0.0, 0.0) - azlmbr.components.TransformBus( - azlmbr.bus.Event, "SetLocalRotation", directional_light.id, directional_light_rotation) - - # Create sphere entity and set the properties - sphere_entity = hydra.Entity("sphere") - sphere_entity.create_entity( - entity_position=math.Vector3(0.0, 0.0, 1.0), - components=["Material"], - parent_id=default_level.id) - - # Work around to add the correct Atom Mesh component and asset. - sphere_entity.components.append( - editor.EditorComponentAPIBus( - bus.Broadcast, "AddComponentsOfType", sphere_entity.id, [mesh_type_id] - ).GetValue()[0] - ) - sphere_mesh_asset_path = os.path.join("Models", "sphere.azmodel") - sphere_mesh_asset_value = asset.AssetCatalogRequestBus( - bus.Broadcast, "GetAssetIdByPath", sphere_mesh_asset_path, math.Uuid(), False) - sphere_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", sphere_mesh_asset_value) - - # Add Atom Material component and asset. - sphere_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_brass_polished.azmaterial") - sphere_material_asset_value = asset.AssetCatalogRequestBus( - bus.Broadcast, "GetAssetIdByPath", sphere_material_asset_path, math.Uuid(), False) - sphere_entity.get_set_test(0, "Default Material|Material Asset", sphere_material_asset_value) - - # Create camera component and set the properties - camera_entity = hydra.Entity("camera") - camera_entity.create_entity( - entity_position=math.Vector3(5.5, -12.0, 9.0), - components=["Camera"], - parent_id=default_level.id) - rotation = math.Vector3( - degree_radian_factor * -27.0, degree_radian_factor * -12.0, degree_radian_factor * 25.0 - ) - azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", camera_entity.id, rotation) - camera_entity.get_set_test(0, "Controller|Configuration|Field of view", 60.0) - camera.EditorCameraViewRequestBus(azlmbr.bus.Event, "ToggleCameraAsActiveView", camera_entity.id) +# def create_basic_atom_level(level_name): +# """ +# Creates a new level inside the Editor matching level_name & adds the following: +# 1. "default_level" entity to hold all other entities. +# 2. Adds Grid, Global Skylight (IBL), ground Mesh, Directional Light, Sphere w/ material+mesh, & Camera components. +# 3. Each of these components has its settings tweaked slightly to match the ideal scene to test Atom rendering. +# :param level_name: name of the level to create and apply this basic setup to. +# :return: None +# """ +# import azlmbr.asset as asset +# import azlmbr.bus as bus +# import azlmbr.camera as camera +# import azlmbr.editor as editor +# import azlmbr.entity as entity +# import azlmbr.legacy.general as general +# import azlmbr.math as math +# import azlmbr.object +# +# import editor_python_test_tools.hydra_editor_utils as hydra +# from editor_python_test_tools.editor_test_helper import EditorTestHelper +# +# helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper") +# +# # Wait for Editor idle loop before executing Python hydra scripts. +# general.idle_enable(True) +# +# # Basic setup for opened level. +# helper.open_level(level_name="Base") +# general.idle_wait(1.0) +# general.update_viewport() +# general.idle_wait(0.5) # half a second is more than enough for updating the viewport. +# +# # Close out problematic windows, FPS meters, and anti-aliasing. +# if general.is_helpers_shown(): # Turn off the helper gizmos if visible +# general.toggle_helpers() +# general.idle_wait(1.0) +# if general.is_pane_visible("Error Report"): # Close Error Report windows that block focus. +# general.close_pane("Error Report") +# if general.is_pane_visible("Error Log"): # Close Error Log windows that block focus. +# general.close_pane("Error Log") +# general.idle_wait(1.0) +# general.run_console("r_displayInfo=0") +# general.idle_wait(1.0) +# +# # Delete all existing entities & create default_level entity +# search_filter = azlmbr.entity.SearchFilter() +# all_entities = entity.SearchBus(azlmbr.bus.Broadcast, "SearchEntities", search_filter) +# editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", all_entities) +# default_level = hydra.Entity("default_level") +# default_position = math.Vector3(0.0, 0.0, 0.0) +# default_level.create_entity(default_position, ["Grid"]) +# default_level.get_set_test(0, "Controller|Configuration|Secondary Grid Spacing", 1.0) +# +# # Set the viewport up correctly after adding the parent default_level entity. +# screen_width = 1280 +# screen_height = 720 +# degree_radian_factor = 0.0174533 # Used by "Rotation" property for the Transform component. +# general.set_viewport_size(screen_width, screen_height) +# general.update_viewport() +# helper.wait_for_condition( +# function=lambda: helper.isclose(a=general.get_viewport_size().x, b=screen_width, rel_tol=0.1) +# and helper.isclose(a=general.get_viewport_size().y, b=screen_height, rel_tol=0.1), +# timeout_in_seconds=4.0 +# ) +# result = helper.isclose(a=general.get_viewport_size().x, b=screen_width, rel_tol=0.1) and helper.isclose( +# a=general.get_viewport_size().y, b=screen_height, rel_tol=0.1) +# general.log(general.get_viewport_size().x) +# general.log(general.get_viewport_size().y) +# general.log(general.get_viewport_size().z) +# general.log(f"Viewport is set to the expected size: {result}") +# general.log("Basic level created") +# general.run_console("r_DisplayInfo = 0") +# +# # Create global_skylight entity and set the properties +# global_skylight = hydra.Entity("global_skylight") +# global_skylight.create_entity( +# entity_position=default_position, +# components=["HDRi Skybox", "Global Skylight (IBL)"], +# parent_id=default_level.id) +# global_skylight_asset_path = os.path.join("LightingPresets", "default_iblskyboxcm.exr.streamingimage") +# global_skylight_asset_value = asset.AssetCatalogRequestBus( +# bus.Broadcast, "GetAssetIdByPath", global_skylight_asset_path, math.Uuid(), False) +# global_skylight.get_set_test(0, "Controller|Configuration|Cubemap Texture", global_skylight_asset_value) +# global_skylight.get_set_test(1, "Controller|Configuration|Diffuse Image", global_skylight_asset_value) +# global_skylight.get_set_test(1, "Controller|Configuration|Specular Image", global_skylight_asset_value) +# +# # Create ground_plane entity and set the properties +# ground_plane = hydra.Entity("ground_plane") +# ground_plane.create_entity( +# entity_position=default_position, +# components=["Material"], +# parent_id=default_level.id) +# azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalUniformScale", ground_plane.id, 32.0) +# +# # Work around to add the correct Atom Mesh component and asset. +# mesh_type_id = azlmbr.globals.property.EditorMeshComponentTypeId +# ground_plane.components.append( +# editor.EditorComponentAPIBus( +# bus.Broadcast, "AddComponentsOfType", ground_plane.id, [mesh_type_id] +# ).GetValue()[0] +# ) +# ground_plane_mesh_asset_path = os.path.join("TestData", "Objects", "plane.azmodel") +# ground_plane_mesh_asset_value = asset.AssetCatalogRequestBus( +# bus.Broadcast, "GetAssetIdByPath", ground_plane_mesh_asset_path, math.Uuid(), False) +# ground_plane.get_set_test(1, "Controller|Configuration|Mesh Asset", ground_plane_mesh_asset_value) +# +# # Add Atom Material component and asset. +# ground_plane_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_chrome.azmaterial") +# ground_plane_material_asset_value = asset.AssetCatalogRequestBus( +# bus.Broadcast, "GetAssetIdByPath", ground_plane_material_asset_path, math.Uuid(), False) +# ground_plane.get_set_test(0, "Default Material|Material Asset", ground_plane_material_asset_value) +# +# # Create directional_light entity and set the properties +# directional_light = hydra.Entity("directional_light") +# directional_light.create_entity( +# entity_position=math.Vector3(0.0, 0.0, 10.0), +# components=["Directional Light"], +# parent_id=default_level.id) +# directional_light_rotation = math.Vector3(degree_radian_factor * -90.0, 0.0, 0.0) +# azlmbr.components.TransformBus( +# azlmbr.bus.Event, "SetLocalRotation", directional_light.id, directional_light_rotation) +# +# # Create sphere entity and set the properties +# sphere_entity = hydra.Entity("sphere") +# sphere_entity.create_entity( +# entity_position=math.Vector3(0.0, 0.0, 1.0), +# components=["Material"], +# parent_id=default_level.id) +# +# # Work around to add the correct Atom Mesh component and asset. +# sphere_entity.components.append( +# editor.EditorComponentAPIBus( +# bus.Broadcast, "AddComponentsOfType", sphere_entity.id, [mesh_type_id] +# ).GetValue()[0] +# ) +# sphere_mesh_asset_path = os.path.join("Models", "sphere.azmodel") +# sphere_mesh_asset_value = asset.AssetCatalogRequestBus( +# bus.Broadcast, "GetAssetIdByPath", sphere_mesh_asset_path, math.Uuid(), False) +# sphere_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", sphere_mesh_asset_value) +# +# # Add Atom Material component and asset. +# sphere_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_brass_polished.azmaterial") +# sphere_material_asset_value = asset.AssetCatalogRequestBus( +# bus.Broadcast, "GetAssetIdByPath", sphere_material_asset_path, math.Uuid(), False) +# sphere_entity.get_set_test(0, "Default Material|Material Asset", sphere_material_asset_value) +# +# # Create camera component and set the properties +# camera_entity = hydra.Entity("camera") +# camera_entity.create_entity( +# entity_position=math.Vector3(5.5, -12.0, 9.0), +# components=["Camera"], +# parent_id=default_level.id) +# rotation = math.Vector3( +# degree_radian_factor * -27.0, degree_radian_factor * -12.0, degree_radian_factor * 25.0 +# ) +# azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", camera_entity.id, rotation) +# camera_entity.get_set_test(0, "Controller|Configuration|Field of view", 60.0) +# camera.EditorCameraViewRequestBus(azlmbr.bus.Event, "ToggleCameraAsActiveView", camera_entity.id) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_LightComponentScreenshotsMatch.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_LightComponentScreenshotsMatch.py new file mode 100644 index 0000000000..e69de29bb2 From 81f80710385a0a115c3057f13fd52d04501ac934 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Fri, 19 Nov 2021 09:07:31 -0600 Subject: [PATCH 025/128] Added regular expression filter for asset browser entries. Signed-off-by: Chris Galvan --- .../AssetBrowser/Search/Filter.cpp | 34 +++++++++++++++++++ .../AssetBrowser/Search/Filter.h | 22 ++++++++++++ 2 files changed, 56 insertions(+) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.cpp index 3f267dedd0..d617638632 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.cpp @@ -251,6 +251,40 @@ namespace AzToolsFramework return false; } + ////////////////////////////////////////////////////////////////////////// + // RegExpFilter + ////////////////////////////////////////////////////////////////////////// + RegExpFilter::RegExpFilter() + : m_filterPattern("") + { + } + + void RegExpFilter::SetFilterPattern(const QString& filterPattern) + { + m_filterPattern = filterPattern; + Q_EMIT updatedSignal(); + } + + QString RegExpFilter::GetNameInternal() const + { + return m_filterPattern; + } + + bool RegExpFilter::MatchInternal(const AssetBrowserEntry* entry) const + { + // no filter pattern matches any asset + if (m_filterPattern.isEmpty()) + { + return true; + } + + // entry's name matches regular expression pattern + QRegExp regExp(m_filterPattern); + regExp.setPatternSyntax(QRegExp::Wildcard); + + return regExp.exactMatch(entry->GetDisplayName()); + } + ////////////////////////////////////////////////////////////////////////// // AssetTypeFilter ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.h index 5819ae92d7..94f47e0599 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Search/Filter.h @@ -115,6 +115,28 @@ namespace AzToolsFramework QString m_filterString; }; + ////////////////////////////////////////////////////////////////////////// + // RegExpFilter + ////////////////////////////////////////////////////////////////////////// + //! RegExpFilter filters assets based on a regular expression pattern + class RegExpFilter + : public AssetBrowserEntryFilter + { + Q_OBJECT + public: + RegExpFilter(); + ~RegExpFilter() override = default; + + void SetFilterPattern(const QString& filterPattern); + + protected: + QString GetNameInternal() const override; + bool MatchInternal(const AssetBrowserEntry* entry) const override; + + private: + QString m_filterPattern; + }; + ////////////////////////////////////////////////////////////////////////// // AssetTypeFilter ////////////////////////////////////////////////////////////////////////// From f1632b099c9c5119d04e7e8d2f2aa3980b912c0e Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Fri, 19 Nov 2021 10:03:16 -0800 Subject: [PATCH 026/128] editor sc component switched over to source handle, not yet connected to file notifications Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../EditorScriptCanvasComponent.cpp | 249 +++++++----------- .../Code/Editor/Components/EditorUtils.cpp | 39 +++ .../ScriptCanvas/Bus/EditorScriptCanvasBus.h | 29 +- .../Components/EditorScriptCanvasComponent.h | 38 +-- .../ScriptCanvas/Components/EditorUtils.h | 2 + .../Code/Editor/ReflectComponent.cpp | 1 + .../Code/Editor/View/Windows/MainWindow.cpp | 14 +- .../Code/Include/ScriptCanvas/Core/Core.cpp | 33 ++- .../Code/Include/ScriptCanvas/Core/Core.h | 8 +- .../$tmp29198_Test_LY_79396.scriptcanvas | 69 +++++ 10 files changed, 271 insertions(+), 211 deletions(-) create mode 100644 Gems/ScriptCanvasTesting/Assets/ScriptCanvas/Tests/$tmp29198_Test_LY_79396.scriptcanvas diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp index d73273103c..3b495f6822 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp @@ -26,18 +26,20 @@ #include #include #include +#include #include #include #include #include - +#include +#include namespace EditorScriptCanvasComponentCpp { enum Version { PrefabIntegration = 10, - + AddSourceHandle, // add description above Current }; @@ -142,6 +144,25 @@ namespace ScriptCanvasEditor } } + if (rootElement.GetVersion() < EditorScriptCanvasComponentCpp::Version::AddSourceHandle) + { + ScriptCanvasAssetHolder assetHolder; + if (!rootElement.FindSubElementAndGetData(AZ_CRC_CE("m_assetHolder"), assetHolder)) + { + AZ_Error("ScriptCanvas", false, "EditorScriptCanvasComponent conversion failed: could not retrieve old 'm_assetHolder'"); + return false; + } + + auto assetId = assetHolder.GetAssetId(); + auto path = assetHolder.GetAssetHint(); + + if (!rootElement.AddElementWithData(serializeContext, "runtimeDataOverrides", SourceHandle(nullptr, assetId.m_guid, path))) + { + AZ_Error("ScriptCanvas", false, "EditorScriptCanvasComponent conversion failed: failed to add 'sourceHandle'"); + return false; + } + } + return true; } @@ -153,9 +174,9 @@ namespace ScriptCanvasEditor serializeContext->Class() ->Version(EditorScriptCanvasComponentCpp::Version::Current, &EditorScriptCanvasComponentVersionConverter) ->Field("m_name", &EditorScriptCanvasComponent::m_name) - ->Field("m_assetHolder", &EditorScriptCanvasComponent::m_scriptCanvasAssetHolder) ->Field("runtimeDataIsValid", &EditorScriptCanvasComponent::m_runtimeDataIsValid) ->Field("runtimeDataOverrides", &EditorScriptCanvasComponent::m_variableOverrides) + ->Field("sourceHandle", &EditorScriptCanvasComponent::m_sourceHandle) ; if (AZ::EditContext* editContext = serializeContext->GetEditContext()) @@ -171,7 +192,7 @@ namespace ScriptCanvasEditor ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("UI", 0x27ff46b0)) ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Level", 0x9aeacc13)) ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/scripting/script-canvas/") - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorScriptCanvasComponent::m_scriptCanvasAssetHolder, "Script Canvas Asset", "Script Canvas asset associated with this component") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorScriptCanvasComponent::m_sourceHandle, "Script Canvas Source File", "Script Canvas source file associated with this component") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorScriptCanvasComponent::m_variableOverrides, "Properties", "Script Canvas Graph Properties") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) @@ -181,19 +202,13 @@ namespace ScriptCanvasEditor } EditorScriptCanvasComponent::EditorScriptCanvasComponent() - : EditorScriptCanvasComponent(AZ::Data::Asset()) + : EditorScriptCanvasComponent(SourceHandle()) { } - EditorScriptCanvasComponent::EditorScriptCanvasComponent(AZ::Data::Asset asset) - : m_scriptCanvasAssetHolder() + EditorScriptCanvasComponent::EditorScriptCanvasComponent(const SourceHandle& sourceHandle) + : m_sourceHandle(sourceHandle) { - if (asset.GetId().IsValid()) - { - m_scriptCanvasAssetHolder.SetAsset(asset.GetId()); - } - - m_scriptCanvasAssetHolder.SetScriptChangedCB([this](AZ::Data::AssetId assetId) { OnScriptCanvasAssetChanged(assetId); }); } EditorScriptCanvasComponent::~EditorScriptCanvasComponent() @@ -209,42 +224,35 @@ namespace ScriptCanvasEditor void EditorScriptCanvasComponent::UpdateName() { - AZ::Data::AssetId assetId = m_scriptCanvasAssetHolder.GetAssetId(); - if (assetId.IsValid()) - { - // Pathname from the asset doesn't seem to return a value unless the asset has been loaded up once(which isn't done until we try to show it). - // Using the Job system to determine the asset name instead. - AZ::Outcome jobOutcome = AZ::Failure(); - AzToolsFramework::AssetSystemJobRequestBus::BroadcastResult(jobOutcome, &AzToolsFramework::AssetSystemJobRequestBus::Events::GetAssetJobsInfoByAssetID, assetId, false, false); - - AZStd::string assetPath; - AZStd::string assetName; - - if (jobOutcome.IsSuccess()) - { - AzToolsFramework::AssetSystem::JobInfoContainer& jobs = jobOutcome.GetValue(); - - // Get the asset relative path - if (!jobs.empty()) - { - assetPath = jobs[0].m_sourceFile; - } - - // Get the asset file name - assetName = assetPath; - - if (!assetPath.empty()) - { - AzFramework::StringFunc::Path::GetFileName(assetPath.c_str(), assetName); - SetName(assetName); - } - } - } + SetName(m_sourceHandle.Path().Filename().Native()); } void EditorScriptCanvasComponent::OpenEditor() { - m_scriptCanvasAssetHolder.OpenEditor(); + AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); + + AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); + + if (m_sourceHandle.IsValid()) + { + GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, m_sourceHandle, -1); + + if (!openOutcome) + { + AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data()); + } + } + else if (GetEntityId().IsValid()) + { + AzToolsFramework::EntityIdList selectedEntityIds; + AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(selectedEntityIds, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities); + + // Going to bypass the multiple selected entities flow for right now. + if (selectedEntityIds.size() == 1) + { + GeneralRequestBus::Broadcast(&GeneralRequests::CreateScriptCanvasAssetFor, AZStd::make_pair(GetEntityId(), GetId())); + } + } } void EditorScriptCanvasComponent::Init() @@ -260,6 +268,8 @@ namespace ScriptCanvasEditor { EditorComponentBase::Activate(); + AzToolsFramework::AssetSystemBus::Handler::BusConnect(); + AZ::EntityId entityId = GetEntityId(); EditorContextMenuRequestBus::Handler::BusConnect(entityId); @@ -268,19 +278,13 @@ namespace ScriptCanvasEditor EditorScriptCanvasComponentLoggingBus::Handler::BusConnect(entityId); EditorLoggingComponentNotificationBus::Broadcast(&EditorLoggingComponentNotifications::OnEditorScriptCanvasComponentActivated, GetNamedEntityId(), GetGraphIdentifier()); - AZ::Data::AssetId fileAssetId = m_scriptCanvasAssetHolder.GetAssetId(); - - if (fileAssetId.IsValid()) - { - AssetTrackerNotificationBus::Handler::BusConnect(fileAssetId); - AzToolsFramework::ToolsApplicationNotificationBus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree_NewContent); - } + AzToolsFramework::ToolsApplicationNotificationBus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree_NewContent); } //========================================================================= void EditorScriptCanvasComponent::Deactivate() { - AssetTrackerNotificationBus::Handler::BusDisconnect(); + AzToolsFramework::AssetSystemBus::Handler::BusDisconnect(); EditorScriptCanvasComponentLoggingBus::Handler::BusDisconnect(); EditorLoggingComponentNotificationBus::Broadcast(&EditorLoggingComponentNotifications::OnEditorScriptCanvasComponentDeactivated, GetNamedEntityId(), GetGraphIdentifier()); @@ -297,7 +301,7 @@ namespace ScriptCanvasEditor m_runtimeDataIsValid = false; - auto assetTreeOutcome = LoadEditorAssetTree(m_scriptCanvasAssetHolder.GetAssetId(), m_scriptCanvasAssetHolder.GetAssetHint()); + auto assetTreeOutcome = LoadEditorAssetTree(m_sourceHandle.Id(), m_sourceHandle.Path().c_str()); if (!assetTreeOutcome.IsSuccess()) { AZ_Warning("ScriptCanvas", false, "EditorScriptCanvasComponent::BuildGameEntityData failed: %s", assetTreeOutcome.GetError().c_str()); @@ -335,7 +339,8 @@ namespace ScriptCanvasEditor if (!m_runtimeDataIsValid) { - AZ_Error("ScriptCanvasBuilder", false, "Runtime information did not build for ScriptCanvas Component using asset: %s", m_scriptCanvasAssetHolder.GetAssetId().ToString().c_str()); + AZ_Error("ScriptCanvasBuilder", false, "Runtime information did not build for ScriptCanvas Component using asset: %s" + , m_sourceHandle.ToString().c_str()); return; } @@ -343,123 +348,53 @@ namespace ScriptCanvasEditor runtimeComponent->TakeRuntimeDataOverrides(ConvertToRuntime(m_variableOverrides)); } - void EditorScriptCanvasComponent::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId) - { - if (m_removedCatalogId == assetId) - { - if (!m_scriptCanvasAssetHolder.GetAssetId().IsValid()) - { - SetPrimaryAsset(assetId); - m_removedCatalogId.SetInvalid(); - } - } - } - void EditorScriptCanvasComponent::OnCatalogAssetRemoved(const AZ::Data::AssetId& removedAssetId, const AZ::Data::AssetInfo& /*assetInfo*/) - { - AZ::Data::AssetId assetId = m_scriptCanvasAssetHolder.GetAssetId(); - if (assetId == removedAssetId) - { - m_removedCatalogId = assetId; - SetPrimaryAsset({}); - } - } - void EditorScriptCanvasComponent::SetPrimaryAsset(const AZ::Data::AssetId& assetId) { - m_scriptCanvasAssetHolder.ClearAsset(); + m_sourceHandle = SourceHandle(nullptr, assetId.m_guid, {}); - if (assetId.IsValid()) + auto completeAsset = CompleteDescription(m_sourceHandle); + if (completeAsset) { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); - - if (memoryAsset) - { - m_scriptCanvasAssetHolder.SetAsset(memoryAsset->GetFileAssetId()); - OnScriptCanvasAssetChanged(memoryAsset->GetFileAssetId()); - SetName(memoryAsset->GetTabName()); - } - else - { - auto scriptCanvasAsset = AZ::Data::AssetManager::Instance().FindAsset(assetId, AZ::Data::AssetLoadBehavior::Default); - if (scriptCanvasAsset) - { - m_scriptCanvasAssetHolder.SetAsset(assetId); - } - } + m_sourceHandle = *completeAsset; } + OnScriptCanvasAssetChanged(m_sourceHandle); + SetName(m_sourceHandle.Path().Filename().Native()); AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues); } AZ::Data::AssetId EditorScriptCanvasComponent::GetAssetId() const { - return m_scriptCanvasAssetHolder.GetAssetId(); + return m_sourceHandle.Id(); } - AZ::EntityId EditorScriptCanvasComponent::GetGraphEntityId() const + void EditorScriptCanvasComponent::OnScriptCanvasAssetChanged(const SourceHandle& assetId) { - AZ::EntityId scriptCanvasEntityId; - AZ::Data::AssetId assetId = m_scriptCanvasAssetHolder.GetAssetId(); - - if (assetId.IsValid()) - { - AssetTrackerRequestBus::BroadcastResult(scriptCanvasEntityId, &AssetTrackerRequests::GetScriptCanvasId, assetId); - } - - return scriptCanvasEntityId; - } - - void EditorScriptCanvasComponent::OnAssetReady(const ScriptCanvasMemoryAsset::pointer asset) - { - OnScriptCanvasAssetReady(asset); - } - - void EditorScriptCanvasComponent::OnAssetSaved(const ScriptCanvasMemoryAsset::pointer asset, bool isSuccessful) - { - if (isSuccessful) - { - OnScriptCanvasAssetReady(asset); - } - } - - void EditorScriptCanvasComponent::OnAssetReloaded(const ScriptCanvasMemoryAsset::pointer asset) - { - OnScriptCanvasAssetReady(asset); - } - - void EditorScriptCanvasComponent::OnScriptCanvasAssetChanged(AZ::Data::AssetId assetId) - { - AssetTrackerNotificationBus::Handler::BusDisconnect(); ScriptCanvas::GraphIdentifier newIdentifier = GetGraphIdentifier(); - newIdentifier.m_assetId = assetId; + newIdentifier.m_assetId = assetId.Id(); ScriptCanvas::GraphIdentifier oldIdentifier = GetGraphIdentifier(); - oldIdentifier.m_assetId = m_previousAssetId; + oldIdentifier.m_assetId = m_previousHandle.Id(); EditorLoggingComponentNotificationBus::Broadcast(&EditorLoggingComponentNotifications::OnAssetSwitched, GetNamedEntityId(), newIdentifier, oldIdentifier); - m_previousAssetId = m_scriptCanvasAssetHolder.GetAssetId(); + m_previousHandle = m_sourceHandle.Describe(); // Only clear our variables when we are given a new asset id // or when the asset was explicitly set to empty. // // i.e. do not clear variables when we lose the catalog asset. - if ((assetId.IsValid() && assetId != m_removedCatalogId) - || (!assetId.IsValid() && !m_removedCatalogId.IsValid())) + if ((assetId.IsValidDescription() && assetId.Describe() != m_removedHandle.Describe()) + || (!assetId.IsValidDescription() && !m_removedHandle.IsValidDescription())) { ClearVariables(); } - if (assetId.IsValid()) + if (assetId.IsValidDescription()) { - AssetTrackerNotificationBus::Handler::BusConnect(assetId); - - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); - if (memoryAsset && memoryAsset->GetAsset().GetStatus() == AZ::Data::AssetData::AssetStatus::Ready) + if (auto loaded = LoadFromFile(assetId.Path().c_str()); loaded.IsSuccess()) { - OnScriptCanvasAssetReady(memoryAsset); + OnScriptCanvasAssetReady(loaded.GetValue()); } } @@ -476,39 +411,49 @@ namespace ScriptCanvasEditor AZ::ScriptSystemRequestBus::Broadcast(&AZ::ScriptSystemRequests::GarbageCollect); } - void EditorScriptCanvasComponent::SetAssetId(const AZ::Data::AssetId& assetId) + void EditorScriptCanvasComponent::SetAssetId(const SourceHandle& assetId) { - if (m_scriptCanvasAssetHolder.GetAssetId() != assetId) + if (m_sourceHandle.Describe() != assetId.Describe()) { // Invalidate the previously removed catalog id if we are setting a new asset id - m_removedCatalogId.SetInvalid(); - SetPrimaryAsset(assetId); + m_removedHandle = {}; + SetPrimaryAsset(assetId.Id()); } } + void EditorScriptCanvasComponent::SourceFileChanged(AZStd::string /*relativePath*/, AZStd::string /*scanFolder*/, AZ::Uuid /*fileAssetId*/) + {} + + void EditorScriptCanvasComponent::SourceFileRemoved(AZStd::string /*relativePath*/, AZStd::string /*scanFolder*/, AZ::Uuid /*fileAssetId*/) + {} + + void EditorScriptCanvasComponent::SourceFileFailed(AZStd::string /*relativePath*/, AZStd::string /*scanFolder*/, AZ::Uuid /*fileAssetId*/) + {} + bool EditorScriptCanvasComponent::HasAssetId() const { - return m_scriptCanvasAssetHolder.GetAssetId().IsValid(); + return !m_sourceHandle.Id().IsNull(); } ScriptCanvas::GraphIdentifier EditorScriptCanvasComponent::GetGraphIdentifier() const { // For now we don't want to deal with disambiguating duplicates of the same script running on one entity. // Should that change we need to add the component id back into this. - return ScriptCanvas::GraphIdentifier(m_scriptCanvasAssetHolder.GetAssetId(), 0); + return ScriptCanvas::GraphIdentifier(m_sourceHandle.Id(), 0); } - void EditorScriptCanvasComponent::OnScriptCanvasAssetReady(const ScriptCanvasMemoryAsset::pointer memoryAsset) + void EditorScriptCanvasComponent::OnScriptCanvasAssetReady(const SourceHandle& sourceHandle) { - if (memoryAsset->GetFileAssetId() == m_scriptCanvasAssetHolder.GetAssetId()) + if (sourceHandle.IsValid()) { - auto assetData = memoryAsset->GetAsset(); - [[maybe_unused]] AZ::Entity* scriptCanvasEntity = assetData->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "This graph must have a valid entity"); BuildGameEntityData(); UpdateName(); AzToolsFramework::ToolsApplicationNotificationBus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree_NewContent); } + else + { + // #sc_editor_asset clear or disable something + } } void EditorScriptCanvasComponent::ClearVariables() diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp index 650be01387..9b83acefa5 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp @@ -17,6 +17,7 @@ AZ_POP_DISABLE_WARNING #include #include #include +#include #include #include @@ -30,6 +31,44 @@ AZ_POP_DISABLE_WARNING namespace ScriptCanvasEditor { + AZStd::optional CompleteDescription(const SourceHandle& source) + { + if (source.IsValidDescription()) + { + return source.Describe(); + } + + AZStd::string watchFolder; + AZ::Data::AssetInfo assetInfo; + bool sourceInfoFound{}; + + if (!source.Id().IsNull()) + { + AzToolsFramework::AssetSystemRequestBus::BroadcastResult + ( sourceInfoFound + , &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourceUUID, source.Id(), assetInfo, watchFolder); + + if (sourceInfoFound && !assetInfo.m_relativePath.empty()) + { + return SourceHandle(nullptr, assetInfo.m_assetId.m_guid, assetInfo.m_relativePath); + } + } + + if (!source.Path().empty()) + { + AzToolsFramework::AssetSystemRequestBus::BroadcastResult + ( sourceInfoFound + , &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, source.Path().c_str(), assetInfo, watchFolder); + + if (sourceInfoFound && assetInfo.m_assetId.IsValid()) + { + return SourceHandle(nullptr, assetInfo.m_assetId.m_guid, assetInfo.m_relativePath); + } + } + + return AZStd::nullopt; + } + ////////////////////////// // NodeIdentifierFactory ////////////////////////// diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h index b55e425d43..b1fd291a1b 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h @@ -72,7 +72,7 @@ namespace ScriptCanvasEditor static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; using BusIdType = AZ::EntityId; - virtual void SetAssetId(const AZ::Data::AssetId& assetId) = 0; + virtual void SetAssetId(const SourceHandle& assetId) = 0; virtual bool HasAssetId() const = 0; }; @@ -91,32 +91,7 @@ namespace ScriptCanvasEditor }; using EditorContextMenuRequestBus = AZ::EBus; - - class EditorScriptCanvasAssetNotifications : public AZ::EBusTraits - { - public: - static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; - using BusIdType = AZ::Data::AssetId; - - //! Notification which fires after an EditorGraph has received it's on AssetReady callback - //! \param scriptCanvasAsset Script Canvas asset which is now ready for use in the Editor - virtual void OnScriptCanvasAssetReady(const AZ::Data::Asset& /*scriptCanvasAsset*/) {}; - - //! Notification which fires after an EditorGraph has received it's on AssetReloaded callback - //! \param scriptCanvasAsset Script Canvas asset which is now ready for use in the Editor - virtual void OnScriptCanvasAssetReloaded(const AZ::Data::Asset& /*scriptCanvaAsset */) {}; - - //! Notification which fires after an EditorGraph has received it's on AssetReady callback - //! \param AssetId AssetId of unloaded ScriptCanvas - virtual void OnScriptCanvasAssetUnloaded(const AZ::Data::AssetId& /*assetId*/) {}; - - //! Notification which fires after an EditorGraph has received an onAssetSaved callback - //! \param scriptCanvasAsset Script Canvas asset which was attempted to be saved - //! \param isSuccessful specified where the Script Canvas asset was successfully saved - virtual void OnScriptCanvasAssetSaved(const AZ::Data::AssetId) {}; - }; - using EditorScriptCanvasAssetNotificationBus = AZ::EBus; - + class EditorGraphRequests : public AZ::EBusTraits { public: diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h index 1bdb4ccb85..38a84bc75e 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h @@ -17,6 +17,7 @@ #include #include #include +#include namespace ScriptCanvasEditor { @@ -34,10 +35,9 @@ namespace ScriptCanvasEditor : public AzToolsFramework::Components::EditorComponentBase , private EditorContextMenuRequestBus::Handler , private AzFramework::AssetCatalogEventBus::Handler + , private AzToolsFramework::AssetSystemBus::Handler , private EditorScriptCanvasComponentLoggingBus::Handler , private EditorScriptCanvasComponentRequestBus::Handler - , private AssetTrackerNotificationBus::Handler - , private AzToolsFramework::AssetSystemBus::Handler , private AzToolsFramework::EditorEntityContextNotificationBus::Handler { @@ -46,7 +46,7 @@ namespace ScriptCanvasEditor EditorScriptCanvasComponent(); // EditorScriptCanvasComponent(AZ::Data::Asset asset); - EditorScriptCanvasComponent(AZ::Data::Asset asset); + EditorScriptCanvasComponent(const SourceHandle& sourceHandle); ~EditorScriptCanvasComponent() override; //===================================================================== @@ -70,14 +70,14 @@ namespace ScriptCanvasEditor void OpenEditor(); - void SetName(const AZStd::string& name) { m_name = name; } + void SetName(AZStd::string_view name) { m_name = name; } const AZStd::string& GetName() const; AZ::EntityId GetEditorEntityId() const { return GetEntity() ? GetEntityId() : AZ::EntityId(); } AZ::NamedEntityId GetNamedEditorEntityId() const { return GetEntity() ? GetNamedEntityId() : AZ::NamedEntityId(); } //===================================================================== // EditorScriptCanvasComponentRequestBus - void SetAssetId(const AZ::Data::AssetId& assetId) override; + void SetAssetId(const SourceHandle& assetId) override; bool HasAssetId() const override; //===================================================================== @@ -85,13 +85,12 @@ namespace ScriptCanvasEditor // EditorContextMenuRequestBus AZ::Data::AssetId GetAssetId() const override; //===================================================================== - AZ::EntityId GetGraphEntityId() const; - + //===================================================================== // AssetTrackerNotificationBus - void OnAssetReady(const ScriptCanvasMemoryAsset::pointer asset) override; - void OnAssetSaved(const ScriptCanvasMemoryAsset::pointer asset, bool isSuccessful) override; - void OnAssetReloaded(const ScriptCanvasMemoryAsset::pointer asset) override; + void OnAssetReady(const ScriptCanvasMemoryAsset::pointer asset) ; + void OnAssetSaved(const ScriptCanvasMemoryAsset::pointer asset, bool isSuccessful) ; + void OnAssetReloaded(const ScriptCanvasMemoryAsset::pointer asset) ; //===================================================================== @@ -119,25 +118,30 @@ namespace ScriptCanvasEditor (void)incompatible; } - void OnCatalogAssetAdded(const AZ::Data::AssetId& assetId) override; - void OnCatalogAssetRemoved(const AZ::Data::AssetId& assetId, const AZ::Data::AssetInfo& assetInfo) override; - void OnScriptCanvasAssetChanged(AZ::Data::AssetId assetId); + // complete the id, load call OnScriptCanvasAssetChanged + void SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid fileAssetId) override; + + // update the display icon for failure, save the values in the graph + void SourceFileRemoved(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid fileAssetId) override; + void SourceFileFailed(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid fileAssetId) override; + + void OnScriptCanvasAssetChanged(const SourceHandle& sourceHandle); void UpdateName(); //===================================================================== - void OnScriptCanvasAssetReady(const ScriptCanvasMemoryAsset::pointer asset); + void OnScriptCanvasAssetReady(const SourceHandle& sourceHandle); //===================================================================== void BuildGameEntityData(); void ClearVariables(); private: - AZ::Data::AssetId m_removedCatalogId; - AZ::Data::AssetId m_previousAssetId; AZStd::string m_name; - ScriptCanvasAssetHolder m_scriptCanvasAssetHolder; bool m_runtimeDataIsValid = false; ScriptCanvasBuilder::BuildVariableOverrides m_variableOverrides; + SourceHandle m_sourceHandle; + SourceHandle m_previousHandle; + SourceHandle m_removedHandle; }; } diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorUtils.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorUtils.h index 15100cbf4e..7685133ca4 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorUtils.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorUtils.h @@ -21,6 +21,8 @@ namespace GraphCanvas namespace ScriptCanvasEditor { + AZStd::optional CompleteDescription(const SourceHandle& source); + class Graph; class NodePaletteModel; diff --git a/Gems/ScriptCanvas/Code/Editor/ReflectComponent.cpp b/Gems/ScriptCanvas/Code/Editor/ReflectComponent.cpp index a75671d0f8..7f2a170a4d 100644 --- a/Gems/ScriptCanvas/Code/Editor/ReflectComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/ReflectComponent.cpp @@ -31,6 +31,7 @@ namespace ScriptCanvasEditor { void ReflectComponent::Reflect(AZ::ReflectContext* context) { + SourceHandle::Reflect(context); ScriptCanvas::ScriptCanvasData::Reflect(context); ScriptCanvasAssetHolder::Reflect(context); EditorSettings::EditorWorkspace::Reflect(context); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index ecfef7c059..d5182351fd 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -1944,7 +1944,7 @@ namespace ScriptCanvasEditor { if (auto firstRequestBus = EditorScriptCanvasComponentRequestBus::FindFirstHandler(entity->GetId())) { - firstRequestBus->SetAssetId(memoryAsset.Id()); + firstRequestBus->SetAssetId(memoryAsset.Describe()); } } else @@ -1953,7 +1953,7 @@ namespace ScriptCanvasEditor { if (editorComponent->GetAssetId() == oldId) { - editorComponent->SetAssetId(memoryAsset.Id()); + editorComponent->SetAssetId(memoryAsset.Describe()); break; } } @@ -4377,15 +4377,7 @@ namespace ScriptCanvasEditor if (usableRequestBus) { - ScriptCanvasMemoryAsset::pointer memoryAsset; - // #sc_editor_asset - // AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, m_activeGraph); - - if (memoryAsset) - { - // We need to assign the AssetId for the file asset, not the in-memory asset - usableRequestBus->SetAssetId(memoryAsset->GetFileAssetId()); - } + usableRequestBus->SetAssetId(m_activeGraph.Describe()); } } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp index de96c9953b..ae85dbc6a9 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp @@ -6,6 +6,7 @@ * */ + #include #include #include @@ -14,9 +15,8 @@ #include #include -#include "Core.h" #include "Attributes.h" - +#include "Core.h" #include namespace ScriptCanvas @@ -238,6 +238,11 @@ namespace ScriptCanvasEditor return m_data != nullptr; } + bool SourceHandle::IsValidDescription() const + { + return !m_id.IsNull() && !m_path.empty(); + } + GraphPtr SourceHandle::Mod() const { return m_data ? m_data->ModEditorGraph() : nullptr; @@ -265,6 +270,30 @@ namespace ScriptCanvasEditor return m_path == other.m_path; } + void SourceHandle::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(0) + ->Field("id", &SourceHandle::m_id) + ->Field("path", &SourceHandle::m_path) + ; + + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + { + editContext->Class("Script Canvas Source Handle", "References a source editor file") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Category, "Scripting") + ->Attribute(AZ::Edit::Attributes::Icon, "Icons/ScriptCanvas/ScriptCanvas.svg") + ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/ScriptCanvas/Viewport/ScriptCanvas.svg") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->DataElement(AZ::Edit::UIHandlers::Default, &SourceHandle::m_path); + ; + } + } + } + AZStd::string SourceHandle::ToString() const { return AZStd::string::format diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h index a57d2dc3a1..d514683b55 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h @@ -325,6 +325,8 @@ namespace ScriptCanvasEditor AZ_TYPE_INFO(SourceHandle, "{65855A98-AE2F-427F-BFC8-69D45265E312}"); AZ_CLASS_ALLOCATOR(SourceHandle, AZ::SystemAllocator, 0); + static void Reflect(AZ::ReflectContext* context); + SourceHandle() = default; SourceHandle(const SourceHandle& data, const AZ::Uuid& id, const AZ::IO::Path& path); @@ -344,6 +346,8 @@ namespace ScriptCanvasEditor bool IsValid() const; + bool IsValidDescription() const; + GraphPtr Mod() const; bool operator==(const SourceHandle& other) const; @@ -372,8 +376,8 @@ namespace ScriptCanvas AZ_RTTI(ScriptCanvasData, "{1072E894-0C67-4091-8B64-F7DB324AD13C}"); AZ_CLASS_ALLOCATOR(ScriptCanvasData, AZ::SystemAllocator, 0); - ScriptCanvasData() {} - virtual ~ScriptCanvasData() {} + ScriptCanvasData() = default; + virtual ~ScriptCanvasData() = default; ScriptCanvasData(ScriptCanvasData&& other); ScriptCanvasData& operator=(ScriptCanvasData&& other); diff --git a/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/Tests/$tmp29198_Test_LY_79396.scriptcanvas b/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/Tests/$tmp29198_Test_LY_79396.scriptcanvas new file mode 100644 index 0000000000..278d74c28d --- /dev/null +++ b/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/Tests/$tmp29198_Test_LY_79396.scriptcanvas @@ -0,0 +1,69 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "ScriptCanvasData", + "ClassData": { + "m_scriptCanvas": { + "Id": { + "id": 32884619828465 + }, + "Name": "Script Canvas Graph", + "Components": { + "Component_[14322649685925277086]": { + "$type": "EditorGraphVariableManagerComponent", + "Id": 14322649685925277086, + "m_variableData": { + "m_nameVariableMap": [ + { + "Key": { + "m_id": "{142C0457-38E5-496E-A4F2-67E91852CBCB}" + }, + "Value": { + "Datum": { + "isOverloadedStorage": false, + "scriptCanvasType": { + "m_type": 4, + "m_azType": "{5CBE5640-DF5C-5A49-9195-D790881A0747}" + }, + "isNullPointer": false, + "$type": "{5CBE5640-DF5C-5A49-9195-D790881A0747} AZStd::vector", + "value": [ + [ + 0.0, + 0.0, + -498814079205376.0, + 0.0 + ], + [ + 0.0, + 0.0, + 1.1865528051967005e38, + 0.0 + ] + ], + "label": "Variable 7" + }, + "VariableId": { + "m_id": "{142C0457-38E5-496E-A4F2-67E91852CBCB}" + }, + "VariableName": "Variable 7" + } + }, + { + "Key": { + "m_id": "{21DD2B3D-ADC9-46E1-B44C-965A6E2AE543}" + }, + "Value": { + "Datum": { + "isOverloadedStorage": false, + "scriptCanvasType": { + "m_type": 4, + "m_azType": "{9ABF5933-C8FC-53CD-A518-B6AF433CF496}" + }, + "isNullPointer": false, + "$type": "{9ABF5933-C8FC-53CD-A518-B6AF433CF496} AZStd::unordered_map", + "value": [ + { + "Key": true, + "Value": { + "roll": \ No newline at end of file From 7aec710cff18d19b2686f2a1b5e2d4dfa4c65123 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Fri, 19 Nov 2021 12:22:12 -0800 Subject: [PATCH 027/128] fix graph tab selection: Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Builder/ScriptCanvasBuilder.cpp | 15 +++++-- .../EditorScriptCanvasComponent.cpp | 40 +++++++++++++++---- .../Components/EditorScriptCanvasComponent.h | 3 +- .../Code/Editor/View/Widgets/GraphTabBar.cpp | 10 +---- 4 files changed, 47 insertions(+), 21 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp index 0eb748b2f1..a75b68b518 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp @@ -39,10 +39,19 @@ namespace ScriptCanvasBuilder void BuildVariableOverrides::CopyPreviousOverriddenValues(const BuildVariableOverrides& source) { - auto copyPreviousIfFound = [](ScriptCanvas::GraphVariable& overriddenValue, const AZStd::vector& source) + auto isEqual = [](const ScriptCanvas::GraphVariable& overrideValue, const ScriptCanvas::GraphVariable& candidate) { - if (auto iter = AZStd::find_if(source.begin(), source.end(), [&overriddenValue](const auto& candidate) { return candidate.GetVariableId() == overriddenValue.GetVariableId(); }); - iter != source.end()) + return candidate.GetVariableId() == overrideValue.GetVariableId() + || (candidate.GetVariableName() == overrideValue.GetVariableName() + && candidate.GetDataType() == overrideValue.GetDataType()); + }; + + auto copyPreviousIfFound = [isEqual](ScriptCanvas::GraphVariable& overriddenValue, const AZStd::vector& source) + { + auto iter = AZStd::find_if(source.begin(), source.end() + , [&overriddenValue, isEqual](const auto& candidate) { return isEqual(candidate, overriddenValue); }); + + if (iter != source.end()) { overriddenValue.DeepCopy(*iter); overriddenValue.SetScriptInputControlVisibility(AZ::Edit::PropertyVisibility::Hide); diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp index 3b495f6822..27b03874ae 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp @@ -394,7 +394,7 @@ namespace ScriptCanvasEditor { if (auto loaded = LoadFromFile(assetId.Path().c_str()); loaded.IsSuccess()) { - OnScriptCanvasAssetReady(loaded.GetValue()); + UpdatePropertyDisplay(loaded.GetValue()); } } @@ -421,14 +421,38 @@ namespace ScriptCanvasEditor } } - void EditorScriptCanvasComponent::SourceFileChanged(AZStd::string /*relativePath*/, AZStd::string /*scanFolder*/, AZ::Uuid /*fileAssetId*/) - {} + void EditorScriptCanvasComponent::SourceFileChanged([[maybe_unused]] AZStd::string relativePath + , [[maybe_unused]] AZStd::string scanFolder, [[maybe_unused]] AZ::Uuid fileAssetId) + { + if (fileAssetId == m_sourceHandle.Id()) + { + if (auto handle = CompleteDescription(SourceHandle(nullptr, fileAssetId, {}))) + { + // consider queueing on tick bus + OnScriptCanvasAssetChanged(*handle); + } + } + } - void EditorScriptCanvasComponent::SourceFileRemoved(AZStd::string /*relativePath*/, AZStd::string /*scanFolder*/, AZ::Uuid /*fileAssetId*/) - {} + void EditorScriptCanvasComponent::SourceFileRemoved([[maybe_unused]] AZStd::string relativePath + , [[maybe_unused]] AZStd::string scanFolder, [[maybe_unused]] AZ::Uuid fileAssetId) + { + if (fileAssetId == m_sourceHandle.Id()) + { + m_removedHandle = m_sourceHandle; + OnScriptCanvasAssetChanged(m_removedHandle); + } + } - void EditorScriptCanvasComponent::SourceFileFailed(AZStd::string /*relativePath*/, AZStd::string /*scanFolder*/, AZ::Uuid /*fileAssetId*/) - {} + void EditorScriptCanvasComponent::SourceFileFailed([[maybe_unused]] AZStd::string relativePath + , [[maybe_unused]] AZStd::string scanFolder, [[maybe_unused]] AZ::Uuid fileAssetId) + { + if (fileAssetId == m_sourceHandle.Id()) + { + m_removedHandle = m_sourceHandle; + OnScriptCanvasAssetChanged(m_removedHandle); + } + } bool EditorScriptCanvasComponent::HasAssetId() const { @@ -442,7 +466,7 @@ namespace ScriptCanvasEditor return ScriptCanvas::GraphIdentifier(m_sourceHandle.Id(), 0); } - void EditorScriptCanvasComponent::OnScriptCanvasAssetReady(const SourceHandle& sourceHandle) + void EditorScriptCanvasComponent::UpdatePropertyDisplay(const SourceHandle& sourceHandle) { if (sourceHandle.IsValid()) { diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h index 38a84bc75e..f9ea8b08e5 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h @@ -45,7 +45,6 @@ namespace ScriptCanvasEditor AZ_COMPONENT(EditorScriptCanvasComponent, "{C28E2D29-0746-451D-A639-7F113ECF5D72}", AzToolsFramework::Components::EditorComponentBase); EditorScriptCanvasComponent(); - // EditorScriptCanvasComponent(AZ::Data::Asset asset); EditorScriptCanvasComponent(const SourceHandle& sourceHandle); ~EditorScriptCanvasComponent() override; @@ -130,7 +129,7 @@ namespace ScriptCanvasEditor void UpdateName(); //===================================================================== - void OnScriptCanvasAssetReady(const SourceHandle& sourceHandle); + void UpdatePropertyDisplay(const SourceHandle& sourceHandle); //===================================================================== void BuildGameEntityData(); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp index 1dfb27ce63..cc43098ad4 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp @@ -181,11 +181,6 @@ namespace ScriptCanvasEditor return false; } -// void GraphTabBar::ConfigureTab(int /*tabIndex*/, ScriptCanvasEditor::SourceHandle fileAssetId, const AZStd::string& tabName) -// { -// -// } - int GraphTabBar::FindTab(ScriptCanvasEditor::SourceHandle assetId) const { for (int tabIndex = 0; tabIndex < count(); ++tabIndex) @@ -451,10 +446,9 @@ namespace ScriptCanvasEditor return; } - auto assetId = tabdata.value(); + auto assetId = tabdata.value().m_assetId; - // #sc_editor_asset - // ScriptCanvasEditor::GeneralRequestBus::Broadcast(&ScriptCanvasEditor::GeneralRequests::OnChangeActiveGraphTab, assetId); + ScriptCanvasEditor::GeneralRequestBus::Broadcast(&ScriptCanvasEditor::GeneralRequests::OnChangeActiveGraphTab, assetId); if (m_signalSaveOnChangeTo >= 0 && m_signalSaveOnChangeTo == index) { From 5f29891dfaa771c6dcfe89a2609a1fc644dfecf7 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Fri, 19 Nov 2021 14:48:12 -0600 Subject: [PATCH 028/128] Added asset selection model option for a source asset type based on regex. Signed-off-by: Chris Galvan --- .../AssetBrowser/AssetSelectionModel.cpp | 69 ++++++++++++++++--- .../AssetBrowser/AssetSelectionModel.h | 11 ++- 2 files changed, 70 insertions(+), 10 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.cpp index 3547cf57b3..2fbdcaf40b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.cpp @@ -10,18 +10,24 @@ #include #include +#if !defined(Q_MOC_RUN) +AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") +#include +AZ_POP_DISABLE_WARNING +#endif + namespace AzToolsFramework { namespace AssetBrowser { namespace { - FilterConstType ProductsNoFoldersFilter() + FilterConstType EntryTypeNoFoldersFilter(AssetBrowserEntry::AssetEntryType entryType = AssetBrowserEntry::AssetEntryType::Product) { - EntryTypeFilter* productFilter = new EntryTypeFilter(); - productFilter->SetEntryType(AssetBrowserEntry::AssetEntryType::Product); + EntryTypeFilter* entryTypeFilter = new EntryTypeFilter(); + entryTypeFilter->SetEntryType(entryType); // in case entry is a source or folder, it may still contain relevant product - productFilter->SetFilterPropagation(AssetBrowserEntryFilter::PropagateDirection::Down); + entryTypeFilter->SetFilterPropagation(AssetBrowserEntryFilter::PropagateDirection::Down); EntryTypeFilter* foldersFilter = new EntryTypeFilter(); foldersFilter->SetEntryType(AssetBrowserEntry::AssetEntryType::Folder); @@ -30,7 +36,7 @@ namespace AzToolsFramework noFoldersFilter->SetFilter(FilterConstType(foldersFilter)); CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND); - compFilter->AddFilter(FilterConstType(productFilter)); + compFilter->AddFilter(FilterConstType(entryTypeFilter)); compFilter->AddFilter(FilterConstType(noFoldersFilter)); return FilterConstType(compFilter); @@ -79,15 +85,39 @@ namespace AzToolsFramework void AssetSelectionModel::SetSelectedAssetIds(const AZStd::vector& selectedAssetIds) { + m_selectedFilePaths.clear(); + m_selectedAssetIds = selectedAssetIds; } void AssetSelectionModel::SetSelectedAssetId(const AZ::Data::AssetId& selectedAssetId) { + m_selectedFilePaths.clear(); + m_selectedAssetIds.clear(); m_selectedAssetIds.push_back(selectedAssetId); } + const AZStd::vector& AssetSelectionModel::GetSelectedFilePaths() const + { + return m_selectedFilePaths; + } + + void AssetSelectionModel::SetSelectedFilePaths(const AZStd::vector& selectedFilePaths) + { + m_selectedAssetIds.clear(); + + m_selectedFilePaths = selectedFilePaths; + } + + void AssetSelectionModel::SetSelectedFilePath(const AZStd::string& selectedFilePath) + { + m_selectedAssetIds.clear(); + + m_selectedFilePaths.clear(); + m_selectedFilePaths.push_back(selectedFilePath); + } + void AssetSelectionModel::SetDefaultDirectory(AZStd::string_view defaultDirectory) { m_defaultDirectory = defaultDirectory; @@ -136,7 +166,7 @@ namespace AzToolsFramework CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND); compFilter->AddFilter(assetTypeFilterPtr); - compFilter->AddFilter(ProductsNoFoldersFilter()); + compFilter->AddFilter(EntryTypeNoFoldersFilter()); selection.SetSelectionFilter(FilterConstType(compFilter)); selection.SetMultiselect(multiselect); @@ -169,7 +199,7 @@ namespace AzToolsFramework CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND); compFilter->AddFilter(anyAssetTypeFilterPtr); - compFilter->AddFilter(ProductsNoFoldersFilter()); + compFilter->AddFilter(EntryTypeNoFoldersFilter()); selection.SetSelectionFilter(FilterConstType(compFilter)); selection.SetMultiselect(multiselect); @@ -190,7 +220,28 @@ namespace AzToolsFramework CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND); compFilter->AddFilter(assetGroupFilterPtr); - compFilter->AddFilter(ProductsNoFoldersFilter()); + compFilter->AddFilter(EntryTypeNoFoldersFilter()); + + selection.SetSelectionFilter(FilterConstType(compFilter)); + selection.SetMultiselect(multiselect); + + return selection; + } + + AssetSelectionModel AssetSelectionModel::SourceAssetTypeSelection(const QString& pattern, bool multiselect) + { + AssetSelectionModel selection; + + RegExpFilter* patternFilter = new RegExpFilter(); + patternFilter->SetFilterPattern(pattern); + patternFilter->SetFilterPropagation(AssetBrowserEntryFilter::PropagateDirection::Down); + auto patternFilterPtr = FilterConstType(patternFilter); + + selection.SetDisplayFilter(patternFilterPtr); + + CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND); + compFilter->AddFilter(patternFilterPtr); + compFilter->AddFilter(EntryTypeNoFoldersFilter(AssetBrowserEntry::AssetEntryType::Source)); selection.SetSelectionFilter(FilterConstType(compFilter)); selection.SetMultiselect(multiselect); @@ -204,7 +255,7 @@ namespace AzToolsFramework CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::OR); selection.SetDisplayFilter(FilterConstType(compFilter)); - selection.SetSelectionFilter(ProductsNoFoldersFilter()); + selection.SetSelectionFilter(EntryTypeNoFoldersFilter()); selection.SetMultiselect(multiselect); return selection; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.h index 4036c166ac..241c896123 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.h @@ -44,6 +44,10 @@ namespace AzToolsFramework void SetSelectedAssetIds(const AZStd::vector& selectedAssetIds); void SetSelectedAssetId(const AZ::Data::AssetId& selectedAssetId); + const AZStd::vector& GetSelectedFilePaths() const; + void SetSelectedFilePaths(const AZStd::vector& selectedFilePaths); + void SetSelectedFilePath(const AZStd::string& selectedFilePath); + void SetDefaultDirectory(AZStd::string_view defaultDirectory); AZStd::string_view GetDefaultDirectory() const; @@ -60,6 +64,7 @@ namespace AzToolsFramework static AssetSelectionModel AssetTypeSelection(const char* assetTypeName, bool multiselect = false); static AssetSelectionModel AssetTypesSelection(const AZStd::vector& assetTypes, bool multiselect = false); static AssetSelectionModel AssetGroupSelection(const char* group, bool multiselect = false); + static AssetSelectionModel SourceAssetTypeSelection(const QString& pattern, bool multiselect = false); static AssetSelectionModel EverythingSelection(bool multiselect = false); private: @@ -68,8 +73,12 @@ namespace AzToolsFramework // some entries like folder should always be displayed, but not always selectable, thus 2 separate filters FilterConstType m_selectionFilter; FilterConstType m_displayFilter; - + + //! Selection can be based on asset ids (for products), or file paths (for sources) + //! These are mututally exclusive AZStd::vector m_selectedAssetIds; + AZStd::vector m_selectedFilePaths; + AZStd::vector m_results; AZStd::string m_defaultDirectory; From d91d5a079fd115be755abe41ea25aaf875628210 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Fri, 19 Nov 2021 14:48:56 -0600 Subject: [PATCH 029/128] Added method to AssetCompleterModel for specifying a filter directly. Signed-off-by: Chris Galvan --- .../UI/PropertyEditor/Model/AssetCompleterModel.cpp | 7 ++++++- .../UI/PropertyEditor/Model/AssetCompleterModel.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.cpp index 3e5b41ebeb..81f0cb36af 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.cpp @@ -39,7 +39,12 @@ namespace AzToolsFramework typeFilter->SetAssetType(filterType); typeFilter->SetFilterPropagation(AssetBrowserEntryFilter::PropagateDirection::Down); - m_assetBrowserFilterModel->SetFilter(FilterConstType(typeFilter)); + SetFilter(FilterConstType(typeFilter)); + } + + void AssetCompleterModel::SetFilter(FilterConstType filter) + { + m_assetBrowserFilterModel->SetFilter(filter); RefreshAssetList(); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.h index 55a6db8589..03660e8fa9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.h @@ -32,6 +32,7 @@ namespace AzToolsFramework QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; void SetFilter(AZ::Data::AssetType filterType); + void SetFilter(FilterConstType filter); void RefreshAssetList(); void SearchStringHighlight(QString searchString); From 27fbbded4ae82bdd60e1a9c9d331bb738dd5379e Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Fri, 19 Nov 2021 14:49:56 -0600 Subject: [PATCH 030/128] Added logic to AssetPickerDialog to pre-select by file paths. Signed-off-by: Chris Galvan --- .../AssetBrowser/AssetPicker/AssetPickerDialog.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp index 4ebeb03a71..259d0426fe 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp @@ -96,6 +96,18 @@ namespace AzToolsFramework } } + if (selection.GetSelectedAssetIds().empty()) + { + for (auto& filePath : selection.GetSelectedFilePaths()) + { + if (!filePath.empty()) + { + selectedAsset = true; + m_ui->m_assetBrowserTreeViewWidget->SelectFileAtPath(filePath); + } + } + } + if (!selectedAsset) { m_ui->m_assetBrowserTreeViewWidget->SelectFolder(selection.GetDefaultDirectory()); From 06e3fa4bef80dd5bb34b34b75f9f15d715aab2c2 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Fri, 19 Nov 2021 14:51:41 -0600 Subject: [PATCH 031/128] Made PropertyAssetCtrl more extensible. Signed-off-by: Chris Galvan --- .../UI/PropertyEditor/PropertyAssetCtrl.cpp | 11 ++++++++--- .../UI/PropertyEditor/PropertyAssetCtrl.hxx | 5 +++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp index e97be57470..c94bec7cc4 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp @@ -1265,7 +1265,7 @@ namespace AzToolsFramework return newCtrl; } - void AssetPropertyHandlerDefault::ConsumeAttribute(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName) + void AssetPropertyHandlerDefault::ConsumeAttributeInternal(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName) { (void)debugName; @@ -1464,6 +1464,11 @@ namespace AzToolsFramework } } + void AssetPropertyHandlerDefault::ConsumeAttribute(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName) + { + ConsumeAttributeInternal(GUI, attrib, attrValue, debugName); + } + void AssetPropertyHandlerDefault::WriteGUIValuesIntoProperty(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node) { (void)index; @@ -1606,8 +1611,8 @@ namespace AzToolsFramework void RegisterAssetPropertyHandler() { - EBUS_EVENT(PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew AssetPropertyHandlerDefault()); - EBUS_EVENT(PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew SimpleAssetPropertyHandlerDefault()); + PropertyTypeRegistrationMessages::Bus::Broadcast(&PropertyTypeRegistrationMessages::RegisterPropertyType, aznew AssetPropertyHandlerDefault()); + PropertyTypeRegistrationMessages::Bus::Broadcast(&PropertyTypeRegistrationMessages::RegisterPropertyType, aznew SimpleAssetPropertyHandlerDefault()); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx index 0b98278bc5..ec80ef050f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx @@ -233,7 +233,7 @@ namespace AzToolsFramework void SetSelectedAssetID(const AZ::Data::AssetId& newID, const AZ::Data::AssetType& newType); void SetCurrentAssetHint(const AZStd::string& hint); void SetDefaultAssetID(const AZ::Data::AssetId& defaultID); - void PopupAssetPicker(); + virtual void PopupAssetPicker(); void OnClearButtonClicked(); void UpdateAssetDisplay(); void OnLineEditFocus(bool focus); @@ -268,7 +268,8 @@ namespace AzToolsFramework virtual void UpdateWidgetInternalTabbing(PropertyAssetCtrl* widget) override { widget->UpdateTabOrder(); } virtual QWidget* CreateGUI(QWidget* pParent) override; - virtual void ConsumeAttribute(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName) override; + static void ConsumeAttributeInternal(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName); + void ConsumeAttribute(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName) override; virtual void WriteGUIValuesIntoProperty(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node) override; virtual bool ReadValuesIntoGUI(size_t index, PropertyAssetCtrl* GUI, const property_t& instance, InstanceDataNode* node) override; }; From 6e14713ea6f1c6baf6f3244da49139778e974354 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Fri, 19 Nov 2021 14:52:45 -0600 Subject: [PATCH 032/128] Added property handler for SourceHandle type. Signed-off-by: Chris Galvan --- .../Serialization/EditContextConstants.inl | 2 + .../Code/Editor/SystemComponent.cpp | 2 + .../Widgets/SourceHandlePropertyAssetCtrl.cpp | 138 ++++++++++++++++++ .../Widgets/SourceHandlePropertyAssetCtrl.h | 67 +++++++++ .../Code/scriptcanvasgem_editor_files.cmake | 2 + 5 files changed, 211 insertions(+) create mode 100644 Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp create mode 100644 Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.h diff --git a/Code/Framework/AzCore/AzCore/Serialization/EditContextConstants.inl b/Code/Framework/AzCore/AzCore/Serialization/EditContextConstants.inl index 4f8c67f058..27f27dd6dd 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/EditContextConstants.inl +++ b/Code/Framework/AzCore/AzCore/Serialization/EditContextConstants.inl @@ -133,6 +133,8 @@ namespace AZ const static AZ::Crc32 AllowClearAsset = AZ_CRC("AllowClearAsset", 0x24827182); // Show the name of the asset that was produced from the source asset const static AZ::Crc32 ShowProductAssetFileName = AZ_CRC("ShowProductAssetFileName"); + //! Regular expression pattern filter for source files + const static AZ::Crc32 SourceAssetFilterPattern = AZ_CRC_CE("SourceAssetFilterPattern"); //! Component icon attributes const static AZ::Crc32 Icon = AZ_CRC("Icon", 0x659429db); diff --git a/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp b/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp index ab8cd0e61b..3566d8da4b 100644 --- a/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -119,6 +120,7 @@ namespace ScriptCanvasEditor PopulateEditorCreatableTypes(); AzToolsFramework::RegisterGenericComboBoxHandler(); + AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Broadcast(&AzToolsFramework::PropertyTypeRegistrationMessages::RegisterPropertyType, aznew SourceHandlePropertyHandler()); SystemRequestBus::Handler::BusConnect(); ScriptCanvasExecutionBus::Handler::BusConnect(); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp new file mode 100644 index 0000000000..66b9b77bdf --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp @@ -0,0 +1,138 @@ +/* + * 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 + +namespace ScriptCanvasEditor +{ + SourceHandlePropertyAssetCtrl::SourceHandlePropertyAssetCtrl(QWidget* parent) + : AzToolsFramework::PropertyAssetCtrl(parent) + { + } + + AzToolsFramework::AssetBrowser::AssetSelectionModel SourceHandlePropertyAssetCtrl::GetAssetSelectionModel() + { + auto selectionModel = AssetSelectionModel::SourceAssetTypeSelection(m_sourceAssetFilterPattern); + selectionModel.SetTitle(m_title); + return selectionModel; + } + + void SourceHandlePropertyAssetCtrl::PopupAssetPicker() + { + // Request the AssetBrowser Dialog and set a type filter + AssetSelectionModel selection = GetAssetSelectionModel(); + selection.SetSelectedFilePath(m_selectedSourcePath.c_str()); + + AZStd::string defaultDirectory; + if (m_defaultDirectoryCallback) + { + m_defaultDirectoryCallback->Invoke(m_editNotifyTarget, defaultDirectory); + selection.SetDefaultDirectory(defaultDirectory); + } + + AssetBrowserComponentRequestBus::Broadcast(&AssetBrowserComponentRequests::PickAssets, selection, parentWidget()); + if (selection.IsValid()) + { + const auto source = azrtti_cast(selection.GetResult()); + AZ_Assert(source, "Incorrect entry type selected. Expected source."); + if (source) + { + SetSelectedSourcePath(source->GetFullPath()); + } + } + } + + void SourceHandlePropertyAssetCtrl::ClearAssetInternal() + { + SetSelectedSourcePath(""); + + PropertyAssetCtrl::ClearAssetInternal(); + } + + void SourceHandlePropertyAssetCtrl::SetSourceAssetFilterPattern(const QString& filterPattern) + { + m_sourceAssetFilterPattern = filterPattern; + } + + AZ::IO::Path SourceHandlePropertyAssetCtrl::GetSelectedSourcePath() const + { + return m_selectedSourcePath; + } + + void SourceHandlePropertyAssetCtrl::SetSelectedSourcePath(const AZ::IO::Path& sourcePath) + { + m_selectedSourcePath = sourcePath; + + AZStd::string displayText; + if (!sourcePath.empty()) + { + AzFramework::StringFunc::Path::GetFileName(sourcePath.c_str(), displayText); + } + m_browseEdit->setText(displayText.c_str()); + + // The AssetID gets ignored, the only important bit is triggering the change for the RequestWrite + emit OnAssetIDChanged(AZ::Data::AssetId()); + } + + QWidget* SourceHandlePropertyHandler::CreateGUI(QWidget* pParent) + { + SourceHandlePropertyAssetCtrl* newCtrl = aznew SourceHandlePropertyAssetCtrl(pParent); + connect(newCtrl, &SourceHandlePropertyAssetCtrl::OnAssetIDChanged, this, [newCtrl](AZ::Data::AssetId newAssetID) + { + (void)newAssetID; + AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&AzToolsFramework::PropertyEditorGUIMessages::RequestWrite, newCtrl); + AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&AzToolsFramework::PropertyEditorGUIMessages::OnEditingFinished, newCtrl); + }); + return newCtrl; + } + + void SourceHandlePropertyHandler::ConsumeAttribute(SourceHandlePropertyAssetCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) + { + // Let the AssetPropertyHandlerDefault handle all of the common attributes + AzToolsFramework::AssetPropertyHandlerDefault::ConsumeAttributeInternal(GUI, attrib, attrValue, debugName); + + if (attrib == AZ::Edit::Attributes::SourceAssetFilterPattern) + { + AZStd::string filterPattern; + if (attrValue->Read(filterPattern)) + { + GUI->SetSourceAssetFilterPattern(filterPattern.c_str()); + } + } + } + + void SourceHandlePropertyHandler::WriteGUIValuesIntoProperty(size_t index, SourceHandlePropertyAssetCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) + { + (void)index; + (void)node; + + auto sourceHandle = SourceHandle(nullptr, {}, GUI->GetSelectedSourcePath()); + instance = property_t(*CompleteDescription(sourceHandle)); + } + + bool SourceHandlePropertyHandler::ReadValuesIntoGUI(size_t index, SourceHandlePropertyAssetCtrl* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) + { + (void)index; + (void)node; + + GUI->blockSignals(true); + + GUI->SetSelectedSourcePath(instance.Path()); + GUI->SetEditNotifyTarget(node->GetParent()->GetInstance(0)); + + GUI->blockSignals(false); + return false; + } +} diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.h new file mode 100644 index 0000000000..31a62aacfb --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.h @@ -0,0 +1,67 @@ +/* + * 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 + +#if !defined(Q_MOC_RUN) +#include + +#include +#endif + +namespace ScriptCanvasEditor +{ + class SourceHandlePropertyAssetCtrl + : public AzToolsFramework::PropertyAssetCtrl + { + Q_OBJECT + + public: + AZ_CLASS_ALLOCATOR(SourceHandlePropertyAssetCtrl, AZ::SystemAllocator, 0); + + SourceHandlePropertyAssetCtrl(QWidget* parent = nullptr); + + AzToolsFramework::AssetBrowser::AssetSelectionModel GetAssetSelectionModel() override; + void PopupAssetPicker() override; + void ClearAssetInternal() override; + + void SetSourceAssetFilterPattern(const QString& filterPattern); + + AZ::IO::Path GetSelectedSourcePath() const; + void SetSelectedSourcePath(const AZ::IO::Path& sourcePath); + + private: + //! A regular expression pattern for filtering by source assets + //! If this is set, the PropertyAssetCtrl will be dealing with source assets + //! instead of a specific asset type + QString m_sourceAssetFilterPattern; + + AZ::IO::Path m_selectedSourcePath; + }; + + class SourceHandlePropertyHandler + : QObject + , public AzToolsFramework::PropertyHandler + { + Q_OBJECT + + public: + AZ_CLASS_ALLOCATOR(SourceHandlePropertyHandler, AZ::SystemAllocator, 0); + + AZ::u32 GetHandlerName(void) const override { return AZ_CRC_CE("SourceHandle"); } + bool IsDefaultHandler() const override { return true; } + QWidget* GetFirstInTabOrder(SourceHandlePropertyAssetCtrl* widget) override { return widget->GetFirstInTabOrder(); } + QWidget* GetLastInTabOrder(SourceHandlePropertyAssetCtrl* widget) override { return widget->GetLastInTabOrder(); } + void UpdateWidgetInternalTabbing(SourceHandlePropertyAssetCtrl* widget) override { widget->UpdateTabOrder(); } + + QWidget* CreateGUI(QWidget* pParent) override; + void ConsumeAttribute(SourceHandlePropertyAssetCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override; + void WriteGUIValuesIntoProperty(size_t index, SourceHandlePropertyAssetCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) override; + bool ReadValuesIntoGUI(size_t index, SourceHandlePropertyAssetCtrl* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) override; + }; +} diff --git a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake index 49f89d8e48..7f269e2081 100644 --- a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake +++ b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake @@ -182,6 +182,8 @@ set(FILES Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.h Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp Editor/View/Widgets/ScriptCanvasNodePaletteToolbar.ui + Editor/View/Widgets/SourceHandlePropertyAssetCtrl.h + Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp Editor/View/Widgets/WidgetBus.h Editor/View/Widgets/DataTypePalette/DataTypePaletteModel.cpp Editor/View/Widgets/DataTypePalette/DataTypePaletteModel.h From 68344f5a8010e95427ee75b5c4fec20cc0026e63 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Fri, 19 Nov 2021 14:58:01 -0600 Subject: [PATCH 033/128] Updated Script Canvas component to use source handle property. Signed-off-by: Chris Galvan --- .../Components/EditorScriptCanvasComponent.cpp | 9 +++++++-- .../Components/EditorScriptCanvasComponent.h | 2 +- .../Code/Include/ScriptCanvas/Core/Core.cpp | 12 ------------ 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp index 3b495f6822..4d870ebca3 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp @@ -193,7 +193,12 @@ namespace ScriptCanvasEditor ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Level", 0x9aeacc13)) ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/scripting/script-canvas/") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorScriptCanvasComponent::m_sourceHandle, "Script Canvas Source File", "Script Canvas source file associated with this component") - ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ->Attribute("BrowseIcon", ":/stylesheet/img/UI20/browse-edit-select-files.svg") + ->Attribute("EditButton", "") + ->Attribute("EditDescription", "Open in Script Canvas Editor") + ->Attribute("EditCallback", &EditorScriptCanvasComponent::OpenEditor) + ->Attribute(AZ::Edit::Attributes::AssetPickerTitle, "Script Canvas") + ->Attribute(AZ::Edit::Attributes::SourceAssetFilterPattern, "*.scriptcanvas") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorScriptCanvasComponent::m_variableOverrides, "Properties", "Script Canvas Graph Properties") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ; @@ -227,7 +232,7 @@ namespace ScriptCanvasEditor SetName(m_sourceHandle.Path().Filename().Native()); } - void EditorScriptCanvasComponent::OpenEditor() + void EditorScriptCanvasComponent::OpenEditor(const AZ::Data::AssetId&, const AZ::Data::AssetType&) { AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h index 38a84bc75e..c496c91a18 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h @@ -68,7 +68,7 @@ namespace ScriptCanvasEditor ScriptCanvas::GraphIdentifier GetGraphIdentifier() const override; //===================================================================== - void OpenEditor(); + void OpenEditor(const AZ::Data::AssetId&, const AZ::Data::AssetType&); void SetName(AZStd::string_view name) { m_name = name; } const AZStd::string& GetName() const; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp index ae85dbc6a9..ef1feae71a 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp @@ -279,18 +279,6 @@ namespace ScriptCanvasEditor ->Field("id", &SourceHandle::m_id) ->Field("path", &SourceHandle::m_path) ; - - if (AZ::EditContext* editContext = serializeContext->GetEditContext()) - { - editContext->Class("Script Canvas Source Handle", "References a source editor file") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::Category, "Scripting") - ->Attribute(AZ::Edit::Attributes::Icon, "Icons/ScriptCanvas/ScriptCanvas.svg") - ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/ScriptCanvas/Viewport/ScriptCanvas.svg") - ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &SourceHandle::m_path); - ; - } } } From 6af6a9d70a47bfea0989fa70bd6315dba748d02a Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Fri, 19 Nov 2021 15:03:49 -0600 Subject: [PATCH 034/128] Fixed issue when clearing out source handle property. Signed-off-by: Chris Galvan --- .../View/Widgets/SourceHandlePropertyAssetCtrl.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp index 66b9b77bdf..4d5cbd91fc 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp @@ -119,7 +119,15 @@ namespace ScriptCanvasEditor (void)node; auto sourceHandle = SourceHandle(nullptr, {}, GUI->GetSelectedSourcePath()); - instance = property_t(*CompleteDescription(sourceHandle)); + auto completeSourceHandle = CompleteDescription(sourceHandle); + if (completeSourceHandle) + { + instance = property_t(*CompleteDescription(sourceHandle)); + } + else + { + instance = property_t(); + } } bool SourceHandlePropertyHandler::ReadValuesIntoGUI(size_t index, SourceHandlePropertyAssetCtrl* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) From 1937e1ea516d528a074a8753f316acf1543a5dc0 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Fri, 19 Nov 2021 16:20:54 -0600 Subject: [PATCH 035/128] Fixed asset completer model for source handle picker. Signed-off-by: Chris Galvan --- .../Model/AssetCompleterModel.cpp | 21 ++++++++++++++----- .../Model/AssetCompleterModel.h | 5 +++++ .../UI/PropertyEditor/PropertyAssetCtrl.hxx | 6 +++--- .../Widgets/SourceHandlePropertyAssetCtrl.cpp | 20 ++++++++++++++++++ .../Widgets/SourceHandlePropertyAssetCtrl.h | 4 ++++ 5 files changed, 48 insertions(+), 8 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.cpp index 81f0cb36af..40f3b7063e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.cpp @@ -125,9 +125,6 @@ namespace AzToolsFramework int rows = m_assetBrowserFilterModel->rowCount(index); if (rows == 0) { - if (index != QModelIndex()) { - AZ_Error("AssetCompleterModel", false, "No children detected in FetchResources()"); - } return; } @@ -136,7 +133,7 @@ namespace AzToolsFramework QModelIndex childIndex = m_assetBrowserFilterModel->index(i, 0, index); AssetBrowserEntry* childEntry = GetAssetEntry(m_assetBrowserFilterModel->mapToSource(childIndex)); - if (childEntry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Product) + if (childEntry->GetEntryType() == m_entryType) { ProductAssetBrowserEntry* productEntry = static_cast(childEntry); AZStd::string assetName; @@ -172,7 +169,6 @@ namespace AzToolsFramework return m_assets[index.row()].m_displayName; } - const AZ::Data::AssetId AssetCompleterModel::GetAssetIdFromIndex(const QModelIndex& index) { if (!index.isValid()) @@ -182,4 +178,19 @@ namespace AzToolsFramework return m_assets[index.row()].m_assetId; } + + const AZStd::string_view AssetCompleterModel::GetPathFromIndex(const QModelIndex& index) + { + if (!index.isValid()) + { + return ""; + } + + return m_assets[index.row()].m_path; + } + + void AssetCompleterModel::SetFetchEntryType(AssetBrowserEntry::AssetEntryType entryType) + { + m_entryType = entryType; + } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.h index 03660e8fa9..4596d70657 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.h @@ -40,6 +40,9 @@ namespace AzToolsFramework const AZStd::string_view GetNameFromIndex(const QModelIndex& index); const AZ::Data::AssetId GetAssetIdFromIndex(const QModelIndex& index); + const AZStd::string_view GetPathFromIndex(const QModelIndex& index); + + void SetFetchEntryType(AssetBrowserEntry::AssetEntryType entryType); private: struct AssetItem @@ -58,6 +61,8 @@ namespace AzToolsFramework AZStd::vector m_assets; //! String that will be highlighted in the suggestions QString m_highlightString; + + AssetBrowserEntry::AssetEntryType m_entryType = AssetBrowserEntry::AssetEntryType::Product; }; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx index ec80ef050f..2017369b6f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx @@ -173,10 +173,11 @@ namespace AzToolsFramework virtual void SetFolderSelection(const AZStd::string& /* folderPath */) {} virtual void ClearAssetInternal(); - void ConfigureAutocompleter(); + virtual void ConfigureAutocompleter(); void RefreshAutocompleter(); void EnableAutocompleter(); void DisableAutocompleter(); + const QModelIndex GetSourceIndex(const QModelIndex& index); void HandleFieldClear(); AZStd::string AddDefaultSuffix(const AZStd::string& filename); @@ -240,13 +241,12 @@ namespace AzToolsFramework virtual void OnEditButtonClicked(); void OnThumbnailClicked(); void OnCompletionModelReset(); - void OnAutocomplete(const QModelIndex& index); + virtual void OnAutocomplete(const QModelIndex& index); void OnTextChange(const QString& text); void OnReturnPressed(); void ShowContextMenu(const QPoint& pos); private: - const QModelIndex GetSourceIndex(const QModelIndex& index); void UpdateThumbnail(); }; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp index 4d5cbd91fc..04f7d79da5 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp @@ -13,6 +13,7 @@ #include #include +#include #include namespace ScriptCanvasEditor @@ -61,6 +62,20 @@ namespace ScriptCanvasEditor PropertyAssetCtrl::ClearAssetInternal(); } + void SourceHandlePropertyAssetCtrl::ConfigureAutocompleter() + { + if (m_completerIsConfigured) + { + return; + } + + AzToolsFramework::PropertyAssetCtrl::ConfigureAutocompleter(); + + AssetSelectionModel selection = GetAssetSelectionModel(); + m_model->SetFetchEntryType(AssetBrowserEntry::AssetEntryType::Source); + m_model->SetFilter(selection.GetDisplayFilter()); + } + void SourceHandlePropertyAssetCtrl::SetSourceAssetFilterPattern(const QString& filterPattern) { m_sourceAssetFilterPattern = filterPattern; @@ -86,6 +101,11 @@ namespace ScriptCanvasEditor emit OnAssetIDChanged(AZ::Data::AssetId()); } + void SourceHandlePropertyAssetCtrl::OnAutocomplete(const QModelIndex& index) + { + SetSelectedSourcePath(m_model->GetPathFromIndex(GetSourceIndex(index))); + } + QWidget* SourceHandlePropertyHandler::CreateGUI(QWidget* pParent) { SourceHandlePropertyAssetCtrl* newCtrl = aznew SourceHandlePropertyAssetCtrl(pParent); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.h index 31a62aacfb..f54279e59c 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.h @@ -29,12 +29,16 @@ namespace ScriptCanvasEditor AzToolsFramework::AssetBrowser::AssetSelectionModel GetAssetSelectionModel() override; void PopupAssetPicker() override; void ClearAssetInternal() override; + void ConfigureAutocompleter() override; void SetSourceAssetFilterPattern(const QString& filterPattern); AZ::IO::Path GetSelectedSourcePath() const; void SetSelectedSourcePath(const AZ::IO::Path& sourcePath); + public Q_SLOTS: + void OnAutocomplete(const QModelIndex& index) override; + private: //! A regular expression pattern for filtering by source assets //! If this is set, the PropertyAssetCtrl will be dealing with source assets From 04fe1d52435d74d341afdd3d6f738706a25350e3 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Mon, 22 Nov 2021 11:03:37 -0800 Subject: [PATCH 036/128] File state change include external delete detection Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Asset/EditorAssetSystemComponent.cpp | 50 ++-- .../Builder/ScriptCanvasBuilderWorker.cpp | 51 ---- .../Assets/ScriptCanvasAssetTracker.cpp | 44 --- .../Editor/Assets/ScriptCanvasAssetTracker.h | 6 +- .../Assets/ScriptCanvasAssetTrackerBus.h | 1 + .../ScriptCanvasAssetTrackerDefinitions.h | 12 - .../Editor/Assets/ScriptCanvasMemoryAsset.h | 2 + .../EditorScriptCanvasComponent.cpp | 2 +- .../Code/Editor/Components/EditorUtils.cpp | 53 ++-- .../FunctionNodeDescriptorComponent.cpp | 3 +- .../Include/ScriptCanvas/Bus/RequestBus.h | 16 +- .../Components/EditorScriptCanvasComponent.h | 8 +- .../ScriptCanvas/Components/EditorUtils.h | 3 + .../Code/Editor/View/Widgets/GraphTabBar.cpp | 9 +- .../Code/Editor/View/Widgets/GraphTabBar.h | 6 +- .../LoggingPanel/LoggingWindowSession.cpp | 9 +- .../UnitTestPanel/UnitTestDockWidget.cpp | 5 +- .../Code/Editor/View/Windows/MainWindow.cpp | 261 +++++++----------- .../Code/Editor/View/Windows/MainWindow.h | 27 +- .../Tools/UpgradeTool/UpgradeHelper.cpp | 2 +- .../Code/Include/ScriptCanvas/Core/Core.cpp | 8 +- .../Code/Include/ScriptCanvas/Core/Core.h | 2 - 22 files changed, 218 insertions(+), 362 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp b/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp index 3515eaf34f..1f614a5a87 100644 --- a/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp +++ b/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp @@ -107,11 +107,15 @@ namespace ScriptCanvasEditor return ScriptCanvasBuilder::CreateLuaAsset(editAsset, graphPathForRawLuaFile); } - void EditorAssetSystemComponent::AddSourceFileOpeners([[maybe_unused]] const char* fullSourceFileName, [[maybe_unused]] const AZ::Uuid& sourceUuid, [[maybe_unused]] AzToolsFramework::AssetBrowser::SourceFileOpenerList& openers) + void EditorAssetSystemComponent::AddSourceFileOpeners + ( [[maybe_unused]] const char* fullSourceFileName + , const AZ::Uuid& sourceUuid + , AzToolsFramework::AssetBrowser::SourceFileOpenerList& openers) { using namespace AzToolsFramework; using namespace AzToolsFramework::AssetBrowser; - if (const SourceAssetBrowserEntry* source = SourceAssetBrowserEntry::GetSourceByUuid(sourceUuid)) // get the full details of the source file based on its UUID. + // get the full details of the source file based on its UUID. + if (const SourceAssetBrowserEntry* source = SourceAssetBrowserEntry::GetSourceByUuid(sourceUuid)) { if (!HandlesSource(source)) { @@ -123,23 +127,31 @@ namespace ScriptCanvasEditor // has no UUID / Not a source file. return; } - // You can push back any number of "Openers" - choose a unique identifier, and icon, and then a lambda which will be activated if the user chooses to open it with your opener: - // #sc_editor_asset - // openers.push_back({ "ScriptCanvas_Editor_Asset_Edit", "Script Canvas Editor...", QIcon(), -// [](const char*, const AZ::Uuid& scSourceUuid) -// { -// AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); -// AZ::Data::AssetId sourceAssetId(scSourceUuid, 0); -// -// auto& assetManager = AZ::Data::AssetManager::Instance(); -// AZ::Data::Asset scriptCanvasAsset = assetManager.GetAsset(sourceAssetId, azrtti_typeid(), AZ::Data::AssetLoadBehavior::Default); -// AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); -// GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, scriptCanvasAsset.GetId(), -1); -// if (!openOutcome) -// { -// AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data()); -// } -// } }); + // You can push back any number of "Openers" - choose a unique identifier, and icon, + // and then a lambda which will be activated if the user chooses to open it with your opener: + + openers.push_back({ "ScriptCanvas_Editor_Asset_Edit", "Script Canvas Editor..." + , QIcon(ScriptCanvasAssetDescription().GetIconPathImpl()), + [](const char*, const AZ::Uuid& scSourceUuid) + { + AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); + + if (auto sourceHandle = CompleteDescription(SourceHandle(nullptr, scSourceUuid, {}))) + { + AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); + GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset + , *sourceHandle, Tracker::ScriptCanvasFileState::UNMODIFIED, -1); + if (!openOutcome) + { + AZ_Warning("ScriptCanvas", openOutcome, "%s", openOutcome.GetError().data()); + } + } + else + { + AZ_Warning("ScriptCanvas", false + , "Unabled to find full path for Source UUid %s", scSourceUuid.ToString().c_str()); + } + }}); } } diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp index faad1871ac..bf98e62b71 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp @@ -60,57 +60,6 @@ namespace ScriptCanvasBuilder graphData = sourceGraph->GetGraphDataConst(); } -#if defined(EDITOR_ASSET_SUPPORT_ENABLED) - if (graphData == nullptr) - { - if (!m_editorAssetHandler) - { - AZ_Error(s_scriptCanvasBuilder, false, R"(CreateJobs for %s failed because the ScriptCanvas Editor Asset handler is missing.)", fullPath.data()); - } - - AZStd::shared_ptr assetDataStream = AZStd::make_shared(); - - AZ::IO::FileIOStream stream(fullPath.c_str(), AZ::IO::OpenMode::ModeRead); - if (!AZ::IO::RetryOpenStream(stream)) - { - AZ_Warning(s_scriptCanvasBuilder, false, "CreateJobs for \"%s\" failed because the source file could not be opened.", fullPath.data()); - return; - } - - // Read the asset into a memory buffer, then hand ownership of the buffer to assetDataStream - { - AZ::IO::FileIOStream ioStream; - if (!ioStream.Open(fullPath.data(), AZ::IO::OpenMode::ModeRead)) - { - AZ_Warning(s_scriptCanvasBuilder, false, "CreateJobs for \"%s\" failed because the source file could not be opened.", fullPath.data()); - return; - } - - AZStd::vector fileBuffer(ioStream.GetLength()); - size_t bytesRead = ioStream.Read(fileBuffer.size(), fileBuffer.data()); - if (bytesRead != ioStream.GetLength()) - { - AZ_Warning(s_scriptCanvasBuilder, false, AZStd::string::format("File failed to read completely: %s", fullPath.data()).c_str()); - return; - } - - assetDataStream->Open(AZStd::move(fileBuffer)); - } - - m_processEditorAssetDependencies.clear(); - - asset.Create(AZ::Data::AssetId(AZ::Uuid::CreateRandom())); - if (m_editorAssetHandler->LoadAssetDataFromStream(asset, assetDataStream, {}) != AZ::Data::AssetHandler::LoadResult::LoadComplete) - { - AZ_Warning(s_scriptCanvasBuilder, false, "CreateJobs for \"%s\" failed because the asset data could not be loaded from the file", fullPath.data()); - return; - } - - sourceGraph = AZ::EntityUtils::FindFirstDerivedComponent(asset.Get()->GetScriptCanvasEntity()); - graphData = sourceGraph->GetGraphDataConst(); - } -#endif - AZ_Assert(sourceGraph, "Graph component is missing from entity."); AZ_Assert(graphData, "GraphData is missing from entity"); diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.cpp index 513dc6afe5..5ec620a907 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.cpp @@ -541,48 +541,4 @@ namespace ScriptCanvasEditor return AZ::EntityId(); } - void AssetTracker::OnAssetReady(const ScriptCanvasMemoryAsset* asset) - { - AZ::Data::AssetId assetId = CheckAssetId(asset->GetId()); - - auto assetInUseIter = m_assetsInUse.find(assetId); - if (assetInUseIter != m_assetsInUse.end()) - { - AssetTrackerNotificationBus::Broadcast(&AssetTrackerNotifications::OnAssetReady, assetInUseIter->second); - } - } - - void AssetTracker::OnAssetReloaded(const ScriptCanvasMemoryAsset* asset) - { - AZ::Data::AssetId assetId = CheckAssetId(asset->GetId()); - - auto assetInUseIter = m_assetsInUse.find(assetId); - if (assetInUseIter != m_assetsInUse.end()) - { - AssetTrackerNotificationBus::Broadcast(&AssetTrackerNotifications::OnAssetReloaded, assetInUseIter->second); - } - } - - void AssetTracker::OnAssetSaved(const ScriptCanvasMemoryAsset* asset, bool isSuccessful) - { - AZ::Data::AssetId assetId = CheckAssetId(asset->GetId()); - - auto assetInUseIter = m_assetsInUse.find(assetId); - if (assetInUseIter != m_assetsInUse.end()) - { - AssetTrackerNotificationBus::Broadcast(&AssetTrackerNotifications::OnAssetSaved, assetInUseIter->second, isSuccessful); - } - } - - void AssetTracker::OnAssetError(const ScriptCanvasMemoryAsset* asset) - { - AZ::Data::AssetId assetId = CheckAssetId(asset->GetId()); - - auto assetInUseIter = m_assetsInUse.find(assetId); - if (assetInUseIter != m_assetsInUse.end()) - { - AssetTrackerNotificationBus::Broadcast(&AssetTrackerNotifications::OnAssetError, assetInUseIter->second); - } - } - } diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.h b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.h index b55e5c06c8..247aba3b94 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.h +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.h @@ -16,6 +16,7 @@ #include #include +#include namespace ScriptCanvasEditor @@ -122,10 +123,5 @@ namespace ScriptCanvasEditor // Invoked when an asset is loaded from file and becomes ready Callbacks::OnAssetReadyCallback m_onAssetReadyCallback; - // Internal::MemoryAssetNotificationBus - void OnAssetReady(const ScriptCanvasMemoryAsset* asset) override; - void OnAssetReloaded(const ScriptCanvasMemoryAsset* asset) override; - void OnAssetSaved(const ScriptCanvasMemoryAsset* asset, bool isSuccessful) override; - void OnAssetError(const ScriptCanvasMemoryAsset* asset) override; }; } diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerBus.h b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerBus.h index 3fecb0aac9..fd50b40768 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerBus.h +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerBus.h @@ -17,6 +17,7 @@ #include #include +#include class QWidget; diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerDefinitions.h b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerDefinitions.h index 29f88b33c8..73507112c2 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerDefinitions.h +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerDefinitions.h @@ -24,17 +24,5 @@ namespace ScriptCanvasEditor using OnAssetCreatedCallback = OnAssetReadyCallback; } - namespace Tracker - { - enum class ScriptCanvasFileState : AZ::s32 - { - NEW, - MODIFIED, - UNMODIFIED, - // #sc_editor_asset restore this - SOURCE_REMOVED, - INVALID = -1 - }; - } } diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.h b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.h index d7f6ae87b6..6eecc5e04f 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.h +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.h @@ -29,6 +29,8 @@ #include #include +#include + namespace ScriptCanvasEditor { diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp index 27b03874ae..b4d8593a87 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp @@ -235,7 +235,7 @@ namespace ScriptCanvasEditor if (m_sourceHandle.IsValid()) { - GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, m_sourceHandle, -1); + GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, m_sourceHandle, Tracker::ScriptCanvasFileState::UNMODIFIED, -1); if (!openOutcome) { diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp index 9b83acefa5..adf5035dbd 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp @@ -35,36 +35,45 @@ namespace ScriptCanvasEditor { if (source.IsValidDescription()) { - return source.Describe(); + return source; } - AZStd::string watchFolder; - AZ::Data::AssetInfo assetInfo; - bool sourceInfoFound{}; - - if (!source.Id().IsNull()) + AzToolsFramework::AssetSystemRequestBus::Events* assetSystem = AzToolsFramework::AssetSystemRequestBus::FindFirstHandler(); + if (assetSystem) { - AzToolsFramework::AssetSystemRequestBus::BroadcastResult - ( sourceInfoFound - , &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourceUUID, source.Id(), assetInfo, watchFolder); + AZStd::string watchFolder; + AZ::Data::AssetInfo assetInfo; - if (sourceInfoFound && !assetInfo.m_relativePath.empty()) + if (!source.Id().IsNull()) { - return SourceHandle(nullptr, assetInfo.m_assetId.m_guid, assetInfo.m_relativePath); + if (assetSystem->GetSourceInfoBySourceUUID(source.Id(), assetInfo, watchFolder)) + { + AZ::IO::Path watchPath(watchFolder); + AZ::IO::Path assetInfoPath(assetInfo.m_relativePath); + SourceHandle fullPathHandle(nullptr, assetInfo.m_assetId.m_guid, watchPath / assetInfoPath); + + if (assetSystem->GetSourceInfoBySourcePath(fullPathHandle.Path().c_str(), assetInfo, watchFolder) && assetInfo.m_assetId.IsValid()) + { + if (assetInfo.m_assetId.m_guid != source.Id()) + { + AZ_TracePrintf("ScriptCanvas", "This is what I don't get"); + } + + auto path = fullPathHandle.Path(); + return SourceHandle(source, assetInfo.m_assetId.m_guid, path.MakePreferred()); + } + } + } + + if (!source.Path().empty()) + { + if (assetSystem->GetSourceInfoBySourcePath(source.Path().c_str(), assetInfo, watchFolder) && assetInfo.m_assetId.IsValid()) + { + return SourceHandle(source, assetInfo.m_assetId.m_guid, source.Path()); + } } } - if (!source.Path().empty()) - { - AzToolsFramework::AssetSystemRequestBus::BroadcastResult - ( sourceInfoFound - , &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, source.Path().c_str(), assetInfo, watchFolder); - - if (sourceInfoFound && assetInfo.m_assetId.IsValid()) - { - return SourceHandle(nullptr, assetInfo.m_assetId.m_guid, assetInfo.m_relativePath); - } - } return AZStd::nullopt; } diff --git a/Gems/ScriptCanvas/Code/Editor/GraphCanvas/Components/NodeDescriptors/FunctionNodeDescriptorComponent.cpp b/Gems/ScriptCanvas/Code/Editor/GraphCanvas/Components/NodeDescriptors/FunctionNodeDescriptorComponent.cpp index f649bb9f7d..f80c6dde21 100644 --- a/Gems/ScriptCanvas/Code/Editor/GraphCanvas/Components/NodeDescriptors/FunctionNodeDescriptorComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/GraphCanvas/Components/NodeDescriptors/FunctionNodeDescriptorComponent.cpp @@ -97,7 +97,8 @@ namespace ScriptCanvasEditor } AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); - GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, SourceHandle( nullptr, assetInfo.m_assetId.m_guid, {} ), -1); + GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset + , SourceHandle( nullptr, assetInfo.m_assetId.m_guid, {} ), Tracker::ScriptCanvasFileState::UNMODIFIED, -1); return openOutcome.IsSuccess(); } diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h index 90468f5d8c..15600c2b88 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h @@ -47,6 +47,18 @@ namespace ScriptCanvasEditor struct CategoryInformation; struct NodePaletteModelInformation; + namespace Tracker + { + enum class ScriptCanvasFileState : AZ::s32 + { + NEW, + MODIFIED, + UNMODIFIED, + // #sc_editor_asset restore this + SOURCE_REMOVED, + INVALID = -1 + }; + } namespace Widget { @@ -68,8 +80,8 @@ namespace ScriptCanvasEditor //! Opens an existing graph and returns the tab index in which it was open in. //! \param File AssetId //! \return index of open tab if the asset was able to be open successfully or error message of why the open failed - virtual AZ::Outcome OpenScriptCanvasAsset(SourceHandle scriptCanvasAssetId, int tabIndex = -1) = 0; - virtual AZ::Outcome OpenScriptCanvasAssetId(const SourceHandle& scriptCanvasAsset) = 0; + virtual AZ::Outcome OpenScriptCanvasAsset(SourceHandle scriptCanvasAssetId, Tracker::ScriptCanvasFileState fileState, int tabIndex = -1) = 0; + virtual AZ::Outcome OpenScriptCanvasAssetId(const SourceHandle& scriptCanvasAsset, Tracker::ScriptCanvasFileState fileState) = 0; virtual int CloseScriptCanvasAsset(const SourceHandle&) = 0; diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h index f9ea8b08e5..ddd83d06ba 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h @@ -85,12 +85,7 @@ namespace ScriptCanvasEditor AZ::Data::AssetId GetAssetId() const override; //===================================================================== - //===================================================================== - // AssetTrackerNotificationBus - void OnAssetReady(const ScriptCanvasMemoryAsset::pointer asset) ; - void OnAssetSaved(const ScriptCanvasMemoryAsset::pointer asset, bool isSuccessful) ; - void OnAssetReloaded(const ScriptCanvasMemoryAsset::pointer asset) ; - //===================================================================== + //===================================================================== @@ -119,7 +114,6 @@ namespace ScriptCanvasEditor // complete the id, load call OnScriptCanvasAssetChanged void SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid fileAssetId) override; - // update the display icon for failure, save the values in the graph void SourceFileRemoved(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid fileAssetId) override; void SourceFileFailed(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid fileAssetId) override; diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorUtils.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorUtils.h index 7685133ca4..0d27d255af 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorUtils.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorUtils.h @@ -21,6 +21,9 @@ namespace GraphCanvas namespace ScriptCanvasEditor { + // If only the Path or the Id is valid, attempts to fill in the missing piece. + // If both Path and Id is valid, including after correction, returns the handle including source Data, + // otherwise, returns null AZStd::optional CompleteDescription(const SourceHandle& source); class Graph; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp index cc43098ad4..2e0ace4768 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp @@ -46,9 +46,9 @@ namespace ScriptCanvasEditor connect(this, &QTabBar::customContextMenuRequested, this, &GraphTabBar::OnContextMenu); } - void GraphTabBar::AddGraphTab(ScriptCanvasEditor::SourceHandle assetId) + void GraphTabBar::AddGraphTab(ScriptCanvasEditor::SourceHandle assetId, Tracker::ScriptCanvasFileState fileState) { - InsertGraphTab(count(), assetId); + InsertGraphTab(count(), assetId, fileState); } void GraphTabBar::ClearTabView(int tabIndex) @@ -143,7 +143,7 @@ namespace ScriptCanvasEditor } } - int GraphTabBar::InsertGraphTab(int tabIndex, ScriptCanvasEditor::SourceHandle assetId) + int GraphTabBar::InsertGraphTab(int tabIndex, ScriptCanvasEditor::SourceHandle assetId, Tracker::ScriptCanvasFileState fileState) { if (!SelectTab(assetId)) { @@ -159,9 +159,6 @@ namespace ScriptCanvasEditor AzFramework::StringFunc::Path::GetFileName(assetId.Path().c_str(), tabName); metaData.m_name = tabName.c_str(); - // #sc_editor_asset filestate - Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::INVALID; - // AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, fileAssetId); SetTabText(tabIndex, tabName.c_str(), fileState); setTabData(tabIndex, QVariant::fromValue(metaData)); return tabIndex; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h index 48f327b244..9d86583f76 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h @@ -18,6 +18,8 @@ #include #include +#include + #endif class QGraphicsView; @@ -54,11 +56,11 @@ namespace ScriptCanvasEditor void SetTabData(const GraphTabMetadata& data, int index); void SetTabData(const GraphTabMetadata& data, ScriptCanvasEditor::SourceHandle assetId); - void AddGraphTab(ScriptCanvasEditor::SourceHandle assetId); + void AddGraphTab(ScriptCanvasEditor::SourceHandle assetId, Tracker::ScriptCanvasFileState fileState); void CloseTab(int index); void CloseAllTabs(); - int InsertGraphTab(int tabIndex, ScriptCanvasEditor::SourceHandle assetId); + int InsertGraphTab(int tabIndex, ScriptCanvasEditor::SourceHandle assetId, Tracker::ScriptCanvasFileState fileState); bool SelectTab(ScriptCanvasEditor::SourceHandle assetId); // void ConfigureTab(int tabIndex, ScriptCanvasEditor::SourceHandle fileAssetId, const AZStd::string& tabName); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowSession.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowSession.cpp index 2e712cef08..963be52edc 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowSession.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowSession.cpp @@ -256,7 +256,8 @@ namespace ScriptCanvasEditor const AZ::Data::AssetId& assetId = executionItem->GetAssetId(); - GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId, SourceHandle(nullptr, assetId.m_guid, {})); + GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId + , SourceHandle(nullptr, assetId.m_guid, {}), Tracker::ScriptCanvasFileState::UNMODIFIED); } } } @@ -272,10 +273,12 @@ namespace ScriptCanvasEditor bool isAssetOpen = false; GeneralRequestBus::BroadcastResult(isAssetOpen, &GeneralRequests::IsScriptCanvasAssetOpen, SourceHandle(nullptr, assetId.m_guid, {})); - GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId, SourceHandle(nullptr, assetId.m_guid, {})); + GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId + , SourceHandle(nullptr, assetId.m_guid, {}), Tracker::ScriptCanvasFileState::UNMODIFIED); AZ::EntityId graphCanvasGraphId; - GeneralRequestBus::BroadcastResult(graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, SourceHandle(nullptr, assetId.m_guid, {})); + GeneralRequestBus::BroadcastResult(graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId + , SourceHandle(nullptr, assetId.m_guid, {})); if (isAssetOpen) { diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/UnitTestPanel/UnitTestDockWidget.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/UnitTestPanel/UnitTestDockWidget.cpp index a60c59ad7e..f319a166df 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/UnitTestPanel/UnitTestDockWidget.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/UnitTestPanel/UnitTestDockWidget.cpp @@ -433,7 +433,10 @@ namespace ScriptCanvasEditor AZ::Data::AssetId sourceAssetId(sourceUuid, 0); AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); - GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAssetId, ScriptCanvasEditor::SourceHandle(nullptr, sourceUuid, {})); + GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAssetId + , ScriptCanvasEditor::SourceHandle(nullptr, sourceUuid, {}) + , Tracker::ScriptCanvasFileState::UNMODIFIED); + if (!openOutcome) { AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data()); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index d5182351fd..8da7ac1570 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -664,6 +664,7 @@ namespace ScriptCanvasEditor AzToolsFramework::ToolsApplicationNotificationBus::Handler::BusConnect(); AzToolsFramework::AssetSystemBus::Handler::BusConnect(); ScriptCanvas::ScriptCanvasSettingsRequestBus::Handler::BusConnect(); + AZ::SystemTickBus::Handler::BusConnect(); UINotificationBus::Broadcast(&UINotifications::MainWindowCreationEvent, this); @@ -1110,13 +1111,47 @@ namespace ScriptCanvasEditor RestartAutoTimerSave(forceTimer); } + void MainWindow::SourceFileChanged + ( [[maybe_unused]] AZStd::string relativePath + , AZStd::string scanFolder + , [[maybe_unused]] AZ::Uuid fileAssetId) + { + auto handle = CompleteDescription(SourceHandle(nullptr, fileAssetId, {})); + if (handle) + { + if (!IsRecentSave(*handle)) + { + UpdateFileState(*handle, Tracker::ScriptCanvasFileState::MODIFIED); + } + else + { + AZ_TracePrintf + ( "ScriptCanvas" + , "Ignoring source file modification notification (possibly external), as a it was recently saved by the editor: %s" + , relativePath.c_str()); + } + } + } + void MainWindow::SourceFileRemoved ( AZStd::string relativePath , [[maybe_unused]] AZStd::string scanFolder - , [[maybe_unused]] AZ::Uuid fileAssetId) + , AZ::Uuid fileAssetId) { - ScriptCanvasEditor::SourceHandle handle(nullptr, fileAssetId, relativePath); - UpdateFileState(handle, Tracker::ScriptCanvasFileState::SOURCE_REMOVED); + SourceHandle handle(nullptr, fileAssetId, relativePath); + { + if (!IsRecentSave(handle)) + { + UpdateFileState(handle, Tracker::ScriptCanvasFileState::SOURCE_REMOVED); + } + else + { + AZ_TracePrintf + ( "ScriptCanvas" + , "Ignoring source file removed notification (possibly external), as a it was recently saved by the editor: %s" + , relativePath.c_str()); + } + } } void MainWindow::SignalSceneDirty(ScriptCanvasEditor::SourceHandle assetId) @@ -1147,21 +1182,7 @@ namespace ScriptCanvasEditor m_tabBar->UpdateFileState(assetId, fileState); } - void MainWindow::RefreshScriptCanvasAsset(const AZ::Data::Asset& /*asset*/) - { - // #sc_editor_asset - /* - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, asset.GetId()); - - if (memoryAsset && asset.IsReady()) - { - - } - */ - } - - AZ::Outcome MainWindow::OpenScriptCanvasAssetId(const ScriptCanvasEditor::SourceHandle& fileAssetId) + AZ::Outcome MainWindow::OpenScriptCanvasAssetId(const ScriptCanvasEditor::SourceHandle& fileAssetId, Tracker::ScriptCanvasFileState fileState) { if (fileAssetId.Id().IsNull()) { @@ -1176,7 +1197,7 @@ namespace ScriptCanvasEditor return AZ::Success(outTabIndex); } - outTabIndex = CreateAssetTab(fileAssetId); + outTabIndex = CreateAssetTab(fileAssetId, fileState); if (!m_isRestoringWorkspace) { @@ -1186,7 +1207,7 @@ namespace ScriptCanvasEditor if (outTabIndex >= 0) { AddRecentFile(fileAssetId.Path().c_str()); - OpenScriptCanvasAssetImplementation(fileAssetId); + OpenScriptCanvasAssetImplementation(fileAssetId, fileState); return AZ::Success(outTabIndex); } else @@ -1195,7 +1216,7 @@ namespace ScriptCanvasEditor } } - AZ::Outcome MainWindow::OpenScriptCanvasAssetImplementation(const SourceHandle& scriptCanvasAsset, int tabIndex) + AZ::Outcome MainWindow::OpenScriptCanvasAssetImplementation(const SourceHandle& scriptCanvasAsset, Tracker::ScriptCanvasFileState fileState, int tabIndex) { const ScriptCanvasEditor::SourceHandle& fileAssetId = scriptCanvasAsset; if (!fileAssetId.IsValid()) @@ -1237,7 +1258,7 @@ namespace ScriptCanvasEditor return AZ::Success(outTabIndex); } - outTabIndex = CreateAssetTab(fileAssetId, tabIndex); + outTabIndex = CreateAssetTab(fileAssetId, fileState, tabIndex); if (outTabIndex == -1) { @@ -1257,21 +1278,21 @@ namespace ScriptCanvasEditor return AZ::Success(outTabIndex); } - AZ::Outcome MainWindow::OpenScriptCanvasAsset(ScriptCanvasEditor::SourceHandle scriptCanvasAssetId, int tabIndex) + AZ::Outcome MainWindow::OpenScriptCanvasAsset(ScriptCanvasEditor::SourceHandle scriptCanvasAssetId, Tracker::ScriptCanvasFileState fileState, int tabIndex) { if (scriptCanvasAssetId.IsValid()) { - return OpenScriptCanvasAssetImplementation(scriptCanvasAssetId, tabIndex); + return OpenScriptCanvasAssetImplementation(scriptCanvasAssetId, fileState, tabIndex); } else { - return OpenScriptCanvasAssetId(scriptCanvasAssetId); + return OpenScriptCanvasAssetId(scriptCanvasAssetId, fileState); } } - int MainWindow::CreateAssetTab(const ScriptCanvasEditor::SourceHandle& assetId, int tabIndex) + int MainWindow::CreateAssetTab(const ScriptCanvasEditor::SourceHandle& assetId, Tracker::ScriptCanvasFileState fileState, int tabIndex) { - return m_tabBar->InsertGraphTab(tabIndex, assetId); + return m_tabBar->InsertGraphTab(tabIndex, assetId, fileState); } void MainWindow::RemoveScriptCanvasAsset(const ScriptCanvasEditor::SourceHandle& assetId) @@ -1314,7 +1335,7 @@ namespace ScriptCanvasEditor { if (createdAssetPair.second == requestingEntityId) { - return OpenScriptCanvasAssetId(createdAssetPair.first).IsSuccess(); + return OpenScriptCanvasAssetId(createdAssetPair.first, Tracker::ScriptCanvasFileState::NEW).IsSuccess(); } } @@ -1353,33 +1374,6 @@ namespace ScriptCanvasEditor return m_nodePaletteModel.FindNodePaletteInformation(nodeType); } - void MainWindow::GetSuggestedFullFilenameToSaveAs(const ScriptCanvasEditor::SourceHandle& /*assetId*/, AZStd::string& /*filePath*/, AZStd::string& /*fileFilter*/) - { - // #sc_editor_asset -// -// ScriptCanvasMemoryAsset::pointer memoryAsset; -// AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); -// -// AZStd::string assetPath; -// if (memoryAsset) -// { -// assetPath = memoryAsset->GetAbsolutePath(); -// fileFilter = ScriptCanvasAssetDescription().GetFileFilterImpl(); -// -// AZStd::string tabName; -// AssetTrackerRequestBus::BroadcastResult(tabName, &AssetTrackerRequests::GetTabName, assetId); -// -// assetPath = AZStd::string::format("%s/%s%s" -// , ScriptCanvasAssetDescription().GetSuggestedSavePathImpl() -// , tabName.c_str() -// , ScriptCanvasAssetDescription().GetExtensionImpl()); -// } -// -// AZStd::array resolvedPath; -// AZ::IO::FileIOBase::GetInstance()->ResolvePath(assetPath.data(), resolvedPath.data(), resolvedPath.size()); -// filePath = resolvedPath.data(); - } - void MainWindow::OpenFile(const char* fullPath) { auto tabIndex = m_tabBar->FindTabByPath(fullPath); @@ -1416,7 +1410,7 @@ namespace ScriptCanvasEditor m_errorFilePath.clear(); auto activeGraph = ScriptCanvasEditor::SourceHandle(outcome.TakeValue(), assetInfo.m_assetId.m_guid, fullPath); - auto openOutcome = OpenScriptCanvasAsset(activeGraph); + auto openOutcome = OpenScriptCanvasAsset(activeGraph, Tracker::ScriptCanvasFileState::UNMODIFIED); if (openOutcome) { RunGraphValidation(false); @@ -1427,66 +1421,10 @@ namespace ScriptCanvasEditor { AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data()); } - -#if defined(EDITOR_ASSET_SUPPORT_ENABLED) - /* - m_errorFilePath = fullPath; - - // Let's find the source file on disk - AZStd::string watchFolder; - AZ::Data::AssetInfo assetInfo; - bool sourceInfoFound{}; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, fullPath, assetInfo, watchFolder); - - if (sourceInfoFound) - { - const Tracker::ScriptCanvasFileState& fileState = GetAssetFileState(assetInfo.m_assetId); - if (fileState != Tracker::ScriptCanvasFileState::NEW && fileState != Tracker::ScriptCanvasFileState::INVALID) - { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetInfo.m_assetId); - - if (m_tabBar->FindTab(assetInfo.m_assetId) < 0) - { - CreateAssetTab(assetInfo.m_assetId); - } - - SetActiveAsset(memoryAsset->GetFileAssetId()); - OpenNextFile(); - return; - } - - Callbacks::OnAssetReadyCallback onAssetReady = [this, assetInfo](ScriptCanvasMemoryAsset&) - { - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetInfo.m_assetId); - - auto openOutcome = OpenScriptCanvasAsset(*memoryAsset); - if (openOutcome) - { - RunGraphValidation(false); - SetRecentAssetId(assetInfo.m_assetId); - } - else - { - AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data()); - } - - OpenNextFile(); - }; - - // TODO-LS the assetInfo.m_assetType is always null for some reason, I know in this case we want default assets so it's ok to hardcode it - AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::Load, assetInfo.m_assetId, assetInfo.m_assetType, azrtti_typeid(), onAssetReady); - } - else - { - QMessageBox::warning(this, "Invalid Source Asset", QString("'%1' is not a valid asset path.").arg(fullPath), QMessageBox::Ok); - } - */ -#endif } - GraphCanvas::Endpoint MainWindow::HandleProposedConnection(const GraphCanvas::GraphId&, const GraphCanvas::ConnectionId&, const GraphCanvas::Endpoint& endpoint, const GraphCanvas::NodeId& nodeId, const QPoint& screenPoint) + GraphCanvas::Endpoint MainWindow::HandleProposedConnection(const GraphCanvas::GraphId&, const GraphCanvas::ConnectionId& + , const GraphCanvas::Endpoint& endpoint, const GraphCanvas::NodeId& nodeId, const QPoint& screenPoint) { GraphCanvas::Endpoint retVal; @@ -1631,7 +1569,7 @@ namespace ScriptCanvasEditor // Insert tab block AZStd::string tabName; AzFramework::StringFunc::Path::GetFileName(assetPath.data(), tabName); - m_tabBar->InsertGraphTab(tabIndex, assetId); + m_tabBar->InsertGraphTab(tabIndex, assetId, Tracker::ScriptCanvasFileState::NEW); if (!IsTabOpen(assetId, outTabIndex)) { @@ -1664,17 +1602,13 @@ namespace ScriptCanvasEditor ScriptCanvasEditor::SourceHandle handle = ScriptCanvasEditor::SourceHandle(graph, assetId, assetPath); outTabIndex = InsertTabForAsset(assetPath, handle, tabIndex); - m_tabBar->UpdateFileState(handle, Tracker::ScriptCanvasFileState::NEW); - + if (outTabIndex == -1) { return AZ::Failure(AZStd::string::format("Script Canvas Asset %.*s is not open in a tab", assetPath.data())); } SetActiveAsset(handle); - - // #sc_editor_asset delete candidate - PushPreventUndoStateUpdate(); AZ::EntityId scriptCanvasEntityId = graph->GetGraph()->GetScriptCanvasId(); @@ -1788,7 +1722,6 @@ namespace ScriptCanvasEditor } else { - // replaces GetSuggestedFullFilenameToSaveAs suggestedFileFilter = ScriptCanvasAssetDescription().GetExtensionImpl(); if (inMemoryAssetId.Path().empty()) @@ -1878,7 +1811,8 @@ namespace ScriptCanvasEditor void MainWindow::OnSaveCallBack(const VersionExplorer::FileSaveResult& result) { const bool saveSuccess = result.fileSaveError.empty(); - auto memoryAsset = m_fileSaver->GetSource(); + auto completeDescription = CompleteDescription(m_fileSaver->GetSource()); + auto memoryAsset = completeDescription ? *completeDescription : m_fileSaver->GetSource(); int saveTabIndex = m_tabBar->FindTab(memoryAsset); AZStd::string tabName = saveTabIndex >= 0 ? m_tabBar->tabText(saveTabIndex).toUtf8().data() : ""; @@ -2000,18 +1934,11 @@ namespace ScriptCanvasEditor const bool displayAsNotification = true; RunGraphValidation(displayAsNotification); - // This is called during saving, so the is saving flag is always true Need to update the state after this callback is complete. So schedule for next system tick. - AddSystemTickAction(SystemTickActionFlag::UpdateSaveMenuState); - - if (saveSuccess && m_closeCurrentGraphAfterSave) - { - AddSystemTickAction(SystemTickActionFlag::CloseCurrentGraph); - } - m_closeCurrentGraphAfterSave = false; EnableAssetView(memoryAsset); + UpdateSaveState(true); UnblockCloseRequests(); m_fileSaver.reset(); } @@ -2025,15 +1952,15 @@ namespace ScriptCanvasEditor void MainWindow::SaveAs(AZStd::string_view path, ScriptCanvasEditor::SourceHandle inMemoryAssetId) { DisableAssetView(inMemoryAssetId); - + UpdateSaveState(false); m_fileSaver = AZStd::make_unique ( nullptr , [this](const VersionExplorer::FileSaveResult& fileSaveResult) { OnSaveCallBack(fileSaveResult); }); - ScriptCanvasEditor::SourceHandle newLocation(inMemoryAssetId, {}, path); + ScriptCanvasEditor::SourceHandle newLocation(inMemoryAssetId, AZ::Uuid::CreateNull(), path); + MarkRecentSave(newLocation); m_fileSaver->Save(newLocation); - UpdateSaveState(); BlockCloseRequests(); } @@ -2825,7 +2752,6 @@ namespace ScriptCanvasEditor void MainWindow::OnActiveFileStateChanged() { - UpdateSaveState(); UpdateAssignToSelectionState(); } @@ -3455,7 +3381,6 @@ namespace ScriptCanvasEditor UpdateAssignToSelectionState(); UpdateUndoRedoState(); - UpdateSaveState(); } void MainWindow::OnWorkspaceRestoreStart() @@ -3533,25 +3458,10 @@ namespace ScriptCanvasEditor ui->action_Redo->setEnabled(isEnabled); } - void MainWindow::UpdateSaveState() + void MainWindow::UpdateSaveState(bool enabled) { - // #sc_editor_asset todo, consider making blocking -// bool enabled = m_activeGraph.IsValid(); -// bool isSaving = false; -// bool hasModifications = false; -// -// if (enabled) -// { -// Tracker::ScriptCanvasFileState fileState = GetAssetFileState(m_activeGraph); -// hasModifications = ( fileState == Tracker::ScriptCanvasFileState::MODIFIED -// || fileState == Tracker::ScriptCanvasFileState::NEW -// || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED); -// -// AssetTrackerRequestBus::BroadcastResult(isSaving, &AssetTrackerRequests::IsSaving, m_activeGraph); -// } -// -// ui->action_Save->setEnabled(enabled && !isSaving && hasModifications); -// ui->action_Save_As->setEnabled(enabled && !isSaving); + ui->action_Save->setEnabled(enabled); + ui->action_Save_As->setEnabled(enabled); } void MainWindow::CreateFunctionInput() @@ -4141,12 +4051,6 @@ namespace ScriptCanvasEditor qobject_cast(parent())->close(); } - if (HasSystemTickAction(SystemTickActionFlag::UpdateSaveMenuState)) - { - RemoveSystemTickAction(SystemTickActionFlag::UpdateSaveMenuState); - UpdateSaveState(); - } - if (HasSystemTickAction(SystemTickActionFlag::CloseCurrentGraph)) { RemoveSystemTickAction(SystemTickActionFlag::CloseCurrentGraph); @@ -4163,10 +4067,7 @@ namespace ScriptCanvasEditor CloseNextTab(); } - if (m_systemTickActions == 0) - { - AZ::SystemTickBus::Handler::BusDisconnect(); - } + ClearStaleSaves(); } void MainWindow::OnCommandStarted(AZ::Crc32) @@ -4393,11 +4294,6 @@ namespace ScriptCanvasEditor void MainWindow::AddSystemTickAction(SystemTickActionFlag action) { - if (!AZ::SystemTickBus::Handler::BusIsConnected()) - { - AZ::SystemTickBus::Handler::BusConnect(); - } - m_systemTickActions |= action; } @@ -4747,5 +4643,34 @@ namespace ScriptCanvasEditor UpdateUndoRedoState(); } + + void MainWindow::ClearStaleSaves() + { + AZStd::lock_guard lock(m_mutex); + auto timeNow = AZStd::chrono::system_clock::now(); + AZStd::erase_if(m_saves, [&timeNow](const auto& item) + { + AZStd::sys_time_t delta = AZStd::chrono::seconds(timeNow - item.second).count(); + return delta > 2.0f; + }); + } + + bool MainWindow::IsRecentSave(const SourceHandle& handle) const + { + AZStd::lock_guard lock(const_cast(this)->m_mutex); + AZStd::string key = handle.Path().Native(); + AZStd::to_lower(key.begin(), key.end()); + auto iter = m_saves.find(key); + return iter != m_saves.end(); + } + + void MainWindow::MarkRecentSave(const SourceHandle& handle) + { + AZStd::lock_guard lock(m_mutex); + AZStd::string key = handle.Path().Native(); + AZStd::to_lower(key.begin(), key.end()); + m_saves[key] = AZStd::chrono::system_clock::now(); + } + #include } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h index dfe5d9fa13..68488238ec 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h @@ -425,9 +425,9 @@ namespace ScriptCanvasEditor QVariant GetTabData(const SourceHandle& assetId); //! GeneralRequestBus - AZ::Outcome OpenScriptCanvasAssetId(const SourceHandle& assetId) override; - AZ::Outcome OpenScriptCanvasAsset(SourceHandle scriptCanvasAssetId, int tabIndex = -1) override; - AZ::Outcome OpenScriptCanvasAssetImplementation(const SourceHandle& sourceHandle, int tabIndex = -1); + AZ::Outcome OpenScriptCanvasAssetId(const SourceHandle& assetId, Tracker::ScriptCanvasFileState fileState) override; + AZ::Outcome OpenScriptCanvasAsset(SourceHandle scriptCanvasAssetId, Tracker::ScriptCanvasFileState fileState, int tabIndex = -1) override; + AZ::Outcome OpenScriptCanvasAssetImplementation(const SourceHandle& sourceHandle, Tracker::ScriptCanvasFileState fileState, int tabIndex = -1); int CloseScriptCanvasAsset(const SourceHandle& assetId) override; bool CreateScriptCanvasAssetFor(const TypeDefs::EntityComponentId& requestingEntityId) override; @@ -438,8 +438,7 @@ namespace ScriptCanvasEditor //// AZ::Outcome CreateScriptCanvasAsset(AZStd::string_view assetPath, int tabIndex = -1); - void RefreshScriptCanvasAsset(const AZ::Data::Asset& scriptCanvasAsset); - + //! Removes the assetId -> ScriptCanvasAsset mapping and disconnects from the asset tracker void RemoveScriptCanvasAsset(const ScriptCanvasEditor::SourceHandle& assetId); void OnChangeActiveGraphTab(ScriptCanvasEditor::SourceHandle) override; @@ -525,8 +524,9 @@ namespace ScriptCanvasEditor AZ::EntityId FindAssetNodeIdByEditorNodeId(const ScriptCanvasEditor::SourceHandle& assetId, AZ::EntityId editorNodeId) const override; private: + void SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid fileAssetId) override; void SourceFileRemoved(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid fileAssetId) override; - + void DeleteNodes(const AZ::EntityId& sceneId, const AZStd::vector& nodes) override; void DeleteConnections(const AZ::EntityId& sceneId, const AZStd::vector& connections) override; void DisconnectEndpoints(const AZ::EntityId& sceneId, const AZStd::vector& endpoints) override; @@ -549,11 +549,6 @@ namespace ScriptCanvasEditor void OnAutoSave(); - //! Helper function which serializes a file to disk - //! \param filename name of file to serialize the Entity - //! \param asset asset to save - void GetSuggestedFullFilenameToSaveAs(const ScriptCanvasEditor::SourceHandle& assetId, AZStd::string& filePath, AZStd::string& fileFilter); - void UpdateFileState(const ScriptCanvasEditor::SourceHandle& assetId, Tracker::ScriptCanvasFileState fileState); // QMainWindow @@ -599,14 +594,14 @@ namespace ScriptCanvasEditor void UpdateAssignToSelectionState(); void UpdateUndoRedoState(); - void UpdateSaveState(); + void UpdateSaveState(bool enabled); void CreateFunctionInput(); void CreateFunctionOutput(); void CreateFunctionDefinitionNode(int positionOffset); - int CreateAssetTab(const ScriptCanvasEditor::SourceHandle& assetId, int tabIndex = -1); + int CreateAssetTab(const ScriptCanvasEditor::SourceHandle& assetId, Tracker::ScriptCanvasFileState fileState, int tabIndex = -1); //! \param asset The AssetId of the ScriptCanvas Asset. void SetActiveAsset(const ScriptCanvasEditor::SourceHandle& assetId); @@ -767,5 +762,11 @@ namespace ScriptCanvasEditor AZStd::unique_ptr m_fileSaver; VersionExplorer::FileSaveResult m_fileSaveResult; void OnSaveCallBack(const VersionExplorer::FileSaveResult& result); + + void ClearStaleSaves(); + bool IsRecentSave(const SourceHandle& handle) const; + void MarkRecentSave(const SourceHandle& handle); + AZStd::recursive_mutex m_mutex; + AZStd::unordered_map m_saves; }; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp index 3522f3cfa2..c557a83f0c 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp @@ -98,7 +98,7 @@ namespace ScriptCanvasEditor if (!asset.Path().empty()) { - GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, asset, -1); + GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, asset, Tracker::ScriptCanvasFileState::UNMODIFIED, -1); } if (!openOutcome) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp index ae85dbc6a9..1b24d2d12a 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp @@ -194,14 +194,18 @@ namespace ScriptCanvasEditor , m_id(id) , m_path(path) { - + m_path.MakePreferred(); + m_id = id; } SourceHandle::SourceHandle(ScriptCanvas::DataPtr graph, const AZ::Uuid& id, const AZ::IO::Path& path) : m_data(graph) , m_id(id) , m_path(path) - {} + { + m_path.MakePreferred(); + m_id = id; + } bool SourceHandle::AnyEquals(const SourceHandle& other) const { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h index d514683b55..8671197f7b 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h @@ -27,8 +27,6 @@ #define OBJECT_STREAM_EDITOR_ASSET_LOADING_SUPPORT_ENABLED -// #define EDITOR_ASSET_SUPPORT_ENABLED - namespace AZ { class Entity; From 205b2c27ee521f6dbd5fa4ae40088586b7c15cf4 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Mon, 22 Nov 2021 16:04:49 -0800 Subject: [PATCH 037/128] SC Editor serialization update in JSON Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Serialization/Json/BaseJsonSerializer.cpp | 16 +++++ .../Serialization/Json/BaseJsonSerializer.h | 7 +- .../Assets/ScriptCanvasFileHandling.cpp | 2 +- .../EditorScriptCanvasComponent.cpp | 33 ++++++--- .../Code/Editor/Components/EditorUtils.cpp | 2 +- .../Components/EditorScriptCanvasComponent.h | 3 + .../EditorScriptCanvasComponentSerializer.cpp | 55 +++++++++++++++ .../EditorScriptCanvasComponentSerializer.h | 31 +++++++++ .../Code/Editor/View/Widgets/GraphTabBar.cpp | 2 +- .../Code/Editor/View/Windows/MainWindow.cpp | 68 ++++++++++--------- .../Windows/Tools/UpgradeTool/Modifier.cpp | 4 +- .../Windows/Tools/UpgradeTool/Scanner.cpp | 2 +- .../Code/Include/ScriptCanvas/Core/Core.cpp | 14 ++-- .../Code/Include/ScriptCanvas/Core/Core.h | 4 +- .../Code/scriptcanvasgem_editor_files.cmake | 2 + 15 files changed, 187 insertions(+), 58 deletions(-) create mode 100644 Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponentSerializer.cpp create mode 100644 Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponentSerializer.h diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.cpp index 7309955a1c..4f5657a328 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.cpp @@ -204,6 +204,22 @@ namespace AZ // BaseJsonSerializer // + JsonSerializationResult::Result BaseJsonSerializer::Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, + JsonDeserializerContext& context) + { + JsonSerializationResult::ResultCode result(JsonSerializationResult::Tasks::ReadField); + result.Combine(ContinueLoading(outputValue, outputValueTypeId, inputValue, context, ContinuationFlags::IgnoreTypeSerializer)); + return context.Report(result, "Ignoring custom serialization during load"); + } + + JsonSerializationResult::Result BaseJsonSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, + const Uuid& valueTypeId, JsonSerializerContext& context) + { + JsonSerializationResult::ResultCode result(JsonSerializationResult::Tasks::WriteValue); + result.Combine(ContinueStoring(outputValue, inputValue, defaultValue, valueTypeId, context, ContinuationFlags::IgnoreTypeSerializer)); + return context.Report(result, "Ignoring custom serialization during store"); + } + BaseJsonSerializer::OperationFlags BaseJsonSerializer::GetOperationsFlags() const { return OperationFlags::None; diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.h b/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.h index 7d2af01c16..4e8f545367 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.h +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.h @@ -180,13 +180,16 @@ namespace AZ //! Transforms the data from the rapidjson Value to outputValue, if the conversion is possible and supported. //! The serializer is responsible for casting to the proper type and safely writing to the outputValue memory. + //! \note The default implementation is to load the object ignoring a custom serializers for the type, which allows for custom serializers + //! to modify the object after all default loading has occurred. virtual JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, - JsonDeserializerContext& context) = 0; + JsonDeserializerContext& context); //! Write the input value to a rapidjson value if the default value is not null and doesn't match the input value, otherwise //! an error is returned and sets the rapidjson value to a null value. + //! \note The default implementation is to store the object ignoring custom serializers. virtual JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, - const Uuid& valueTypeId, JsonSerializerContext& context) = 0; + const Uuid& valueTypeId, JsonSerializerContext& context); //! Returns the operation flags which tells the Json Serialization how this custom json serializer can be used. virtual OperationFlags GetOperationsFlags() const; diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp index 68648a71f3..d806eb7e24 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp @@ -144,7 +144,7 @@ namespace ScriptCanvasEditor { namespace JSRU = AZ::JsonSerializationUtils; - if (!source.IsValid()) + if (!source.IsGraphValid()) { return AZ::Failure(AZStd::string("no source graph to save")); } diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp index 34a79b2543..e059ff555b 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp @@ -6,7 +6,6 @@ * */ - #include #include #include @@ -14,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -21,24 +21,26 @@ #include #include #include +#include #include #include #include +#include #include #include -#include #include #include +#include +#include #include #include -#include -#include namespace EditorScriptCanvasComponentCpp { enum Version { PrefabIntegration = 10, + InternalDev, AddSourceHandle, // add description above Current @@ -49,6 +51,8 @@ namespace ScriptCanvasEditor { static bool EditorScriptCanvasComponentVersionConverter(AZ::SerializeContext& serializeContext, AZ::SerializeContext::DataElementNode& rootElement) { + AZ_TracePrintf("ScriptCanvas", "EditorScriptCanvasComponentVersionConverter called!"); + if (rootElement.GetVersion() <= 4) { int assetElementIndex = rootElement.FindElement(AZ::Crc32("m_asset")); @@ -204,6 +208,11 @@ namespace ScriptCanvasEditor ; } } + + if (AZ::JsonRegistrationContext* jsonContext = azrtti_cast(context)) + { + jsonContext->Serializer()->HandlesType(); + } } EditorScriptCanvasComponent::EditorScriptCanvasComponent() @@ -238,7 +247,7 @@ namespace ScriptCanvasEditor AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); - if (m_sourceHandle.IsValid()) + if (m_sourceHandle.IsDescriptionValid()) { GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, m_sourceHandle, Tracker::ScriptCanvasFileState::UNMODIFIED, -1); @@ -265,7 +274,11 @@ namespace ScriptCanvasEditor EditorComponentBase::Init(); AzFramework::AssetCatalogEventBus::Handler::BusConnect(); AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusConnect(); - // m_scriptCanvasAssetHolder.Init(GetEntityId(), GetId()); + } + + void EditorScriptCanvasComponent::InitializeSource(const SourceHandle& sourceHandle) + { + m_sourceHandle = sourceHandle; } //========================================================================= @@ -389,13 +402,13 @@ namespace ScriptCanvasEditor // or when the asset was explicitly set to empty. // // i.e. do not clear variables when we lose the catalog asset. - if ((assetId.IsValidDescription() && assetId.Describe() != m_removedHandle.Describe()) - || (!assetId.IsValidDescription() && !m_removedHandle.IsValidDescription())) + if ((assetId.IsDescriptionValid() && assetId.Describe() != m_removedHandle.Describe()) + || (!assetId.IsDescriptionValid() && !m_removedHandle.IsDescriptionValid())) { ClearVariables(); } - if (assetId.IsValidDescription()) + if (assetId.IsDescriptionValid()) { if (auto loaded = LoadFromFile(assetId.Path().c_str()); loaded.IsSuccess()) { @@ -473,7 +486,7 @@ namespace ScriptCanvasEditor void EditorScriptCanvasComponent::UpdatePropertyDisplay(const SourceHandle& sourceHandle) { - if (sourceHandle.IsValid()) + if (sourceHandle.IsGraphValid()) { BuildGameEntityData(); UpdateName(); diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp index adf5035dbd..dccc50f732 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp @@ -33,7 +33,7 @@ namespace ScriptCanvasEditor { AZStd::optional CompleteDescription(const SourceHandle& source) { - if (source.IsValidDescription()) + if (source.IsDescriptionValid()) { return source; } diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h index c9cb472808..31ef111b7b 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h @@ -48,6 +48,9 @@ namespace ScriptCanvasEditor EditorScriptCanvasComponent(const SourceHandle& sourceHandle); ~EditorScriptCanvasComponent() override; + // sets the soure but does not attempt to load anything; + void InitializeSource(const SourceHandle& sourceHandle); + //===================================================================== // AZ::Component void Init() override; diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponentSerializer.cpp b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponentSerializer.cpp new file mode 100644 index 0000000000..dfda030403 --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponentSerializer.cpp @@ -0,0 +1,55 @@ +/* + * 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 + +namespace AZ +{ + AZ_CLASS_ALLOCATOR_IMPL(EditorScriptCanvasComponentSerializer, SystemAllocator, 0); + + JsonSerializationResult::Result EditorScriptCanvasComponentSerializer::Load + ( void* outputValue + , const Uuid& outputValueTypeId + , const rapidjson::Value& inputValue + , JsonDeserializerContext& context) + { + namespace JSR = JsonSerializationResult; + + AZ_Assert(outputValueTypeId == azrtti_typeid() + , "EditorScriptCanvasComponentSerializer Load against output typeID that was not EditorScriptCanvasComponent"); + AZ_Assert(outputValue, "EditorScriptCanvasComponentSerializer Load against null output"); + + auto outputComponent = reinterpret_cast(outputValue); + JsonSerializationResult::ResultCode result = BaseJsonSerializer::Load(outputValue, outputValueTypeId, inputValue, context); + + if (result.GetProcessing() != JSR::Processing::Halted) + { + auto assetHolderMember = inputValue.FindMember("m_assetHolder"); + if (assetHolderMember != inputValue.MemberEnd()) + { + ScriptCanvasEditor::ScriptCanvasAssetHolder assetHolder; + result.Combine + ( ContinueLoading(&assetHolder + , azrtti_typeid(), assetHolderMember->value, context)); + + if (result.GetProcessing() != JSR::Processing::Halted) + { + outputComponent->InitializeSource + ( ScriptCanvasEditor::SourceHandle(nullptr, assetHolder.GetAssetId().m_guid, assetHolder.GetAssetHint())); + } + } + } + + return context.Report(result, result.GetProcessing() != JSR::Processing::Halted + ? "EditorScriptCanvasComponentSerializer Load finished loading EditorScriptCanvasComponent" + : "EditorScriptCanvasComponentSerializer Load failed to load EditorScriptCanvasComponent"); + } +} diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponentSerializer.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponentSerializer.h new file mode 100644 index 0000000000..68ad370997 --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponentSerializer.h @@ -0,0 +1,31 @@ +/* + * 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 EditorScriptCanvasComponentSerializer + : public BaseJsonSerializer + { + public: + AZ_RTTI(EditorScriptCanvasComponentSerializer, "{80B497B3-ABC1-4991-A3C4-047A8CB2C26C}", BaseJsonSerializer); + AZ_CLASS_ALLOCATOR_DECL; + + private: + JsonSerializationResult::Result Load + ( void* outputValue + , const Uuid& outputValueTypeId + , const rapidjson::Value& inputValue + , JsonDeserializerContext& context) override; + }; +} diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp index 2e0ace4768..6ea8f3a75d 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp @@ -235,7 +235,7 @@ namespace ScriptCanvasEditor if (tabdata.isValid()) { auto tabAssetId = tabdata.value(); - if (tabAssetId.m_assetId.IsValid() + if (tabAssetId.m_assetId.IsGraphValid() && tabAssetId.m_assetId.Get()->GetGraphCanvasGraphId() == graphCanvasGraphId) { return tabAssetId.m_assetId.Get()->GetScriptCanvasId(); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index 8da7ac1570..d6efe246a0 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -251,7 +251,7 @@ namespace ScriptCanvasEditor if (fileState == Tracker::ScriptCanvasFileState::MODIFIED || fileState == Tracker::ScriptCanvasFileState::UNMODIFIED) { ScriptCanvasEditor::SourceHandle sourceId = GetSourceAssetId(assetId); - if (sourceId.IsValid()) + if (sourceId.IsGraphValid()) { EditorSettings::EditorWorkspace::WorkspaceAssetSaveData assetSaveData; assetSaveData.m_assetId = sourceId; @@ -267,13 +267,13 @@ namespace ScriptCanvasEditor } // The assetId needs to be the file AssetId to restore the workspace - if (focusedAssetId.IsValid()) + if (focusedAssetId.IsGraphValid()) { focusedAssetId = GetSourceAssetId(focusedAssetId); } // If our currently focused asset won't be restored, just show the first element. - if (!focusedAssetId.IsValid()) + if (!focusedAssetId.IsGraphValid()) { if (!activeAssets.empty()) { @@ -641,7 +641,7 @@ namespace ScriptCanvasEditor QTimer::singleShot(0, [this]() { SetDefaultLayout(); - if (m_activeGraph.IsValid()) + if (m_activeGraph.IsGraphValid()) { m_queuedFocusOverride = m_activeGraph; } @@ -822,7 +822,7 @@ namespace ScriptCanvasEditor void MainWindow::SignalActiveSceneChanged(ScriptCanvasEditor::SourceHandle assetId) { AZ::EntityId graphId; - if (assetId.IsValid()) + if (assetId.IsGraphValid()) { EditorGraphRequestBus::EventResult(graphId, assetId.Get()->GetScriptCanvasId(), &EditorGraphRequests::GetGraphCanvasGraphId); } @@ -1197,17 +1197,23 @@ namespace ScriptCanvasEditor return AZ::Success(outTabIndex); } - outTabIndex = CreateAssetTab(fileAssetId, fileState); + auto loadedGraph = LoadFromFile(fileAssetId.Path().c_str()); + if (!loadedGraph.IsSuccess()) + { + return AZ::Failure(AZStd::string("Failed to load graph at %s", fileAssetId.Path().c_str())); + } + + outTabIndex = CreateAssetTab(loadedGraph.GetValue(), fileState); if (!m_isRestoringWorkspace) { - SetActiveAsset(fileAssetId); + SetActiveAsset(loadedGraph.GetValue()); } if (outTabIndex >= 0) { - AddRecentFile(fileAssetId.Path().c_str()); - OpenScriptCanvasAssetImplementation(fileAssetId, fileState); + AddRecentFile(loadedGraph.GetValue().Path().c_str()); + OpenScriptCanvasAssetImplementation(loadedGraph.GetValue(), fileState); return AZ::Success(outTabIndex); } else @@ -1219,12 +1225,12 @@ namespace ScriptCanvasEditor AZ::Outcome MainWindow::OpenScriptCanvasAssetImplementation(const SourceHandle& scriptCanvasAsset, Tracker::ScriptCanvasFileState fileState, int tabIndex) { const ScriptCanvasEditor::SourceHandle& fileAssetId = scriptCanvasAsset; - if (!fileAssetId.IsValid()) + if (!fileAssetId.IsDescriptionValid()) { return AZ::Failure(AZStd::string("Unable to open asset with invalid asset id")); } - if (!scriptCanvasAsset.IsValid()) + if (!scriptCanvasAsset.IsDescriptionValid()) { if (!m_isRestoringWorkspace) { @@ -1280,7 +1286,7 @@ namespace ScriptCanvasEditor AZ::Outcome MainWindow::OpenScriptCanvasAsset(ScriptCanvasEditor::SourceHandle scriptCanvasAssetId, Tracker::ScriptCanvasFileState fileState, int tabIndex) { - if (scriptCanvasAssetId.IsValid()) + if (scriptCanvasAssetId.IsGraphValid()) { return OpenScriptCanvasAssetImplementation(scriptCanvasAssetId, fileState, tabIndex); } @@ -1301,7 +1307,7 @@ namespace ScriptCanvasEditor m_assetCreationRequests.erase(assetId); GeneralAssetNotificationBus::Event(assetId, &GeneralAssetNotifications::OnAssetUnloaded); - if (assetId.IsValid()) + if (assetId.IsGraphValid()) { // Disconnect scene and asset editor buses GraphCanvas::SceneNotificationBus::MultiHandler::BusDisconnect(assetId.Get()->GetScriptCanvasId()); @@ -1377,7 +1383,7 @@ namespace ScriptCanvasEditor void MainWindow::OpenFile(const char* fullPath) { auto tabIndex = m_tabBar->FindTabByPath(fullPath); - if (tabIndex.IsValid()) + if (tabIndex.IsGraphValid()) { SetActiveAsset(tabIndex); return; @@ -1697,7 +1703,7 @@ namespace ScriptCanvasEditor bool MainWindow::SaveAssetImpl(const ScriptCanvasEditor::SourceHandle& inMemoryAssetId, Save save) { - if (!inMemoryAssetId.IsValid()) + if (!inMemoryAssetId.IsGraphValid()) { return false; } @@ -2444,7 +2450,7 @@ namespace ScriptCanvasEditor { AZ::EntityId graphId{}; - if (m_activeGraph.IsValid()) + if (m_activeGraph.IsGraphValid()) { EditorGraphRequestBus::EventResult ( graphId, m_activeGraph.Get()->GetScriptCanvasId(), &EditorGraphRequests::GetGraphCanvasGraphId); @@ -2469,7 +2475,7 @@ namespace ScriptCanvasEditor { AZ::EntityId graphId{}; - if (assetId.IsValid()) + if (assetId.IsGraphValid()) { EditorGraphRequestBus::EventResult ( graphId, assetId.Get()->GetScriptCanvasId(), &EditorGraphRequests::GetGraphCanvasGraphId); @@ -2480,7 +2486,7 @@ namespace ScriptCanvasEditor ScriptCanvas::ScriptCanvasId MainWindow::FindScriptCanvasIdByAssetId(const ScriptCanvasEditor::SourceHandle& assetId) const { - return assetId.IsValid() ? assetId.Get()->GetScriptCanvasId() : ScriptCanvas::ScriptCanvasId{}; + return assetId.IsGraphValid() ? assetId.Get()->GetScriptCanvasId() : ScriptCanvas::ScriptCanvasId{}; } ScriptCanvas::ScriptCanvasId MainWindow::GetScriptCanvasId(const GraphCanvas::GraphId& graphCanvasGraphId) const @@ -2546,14 +2552,14 @@ namespace ScriptCanvasEditor { // Disconnect previous asset AZ::EntityId previousScriptCanvasSceneId; - if (previousAsset.IsValid()) + if (previousAsset.IsGraphValid()) { previousScriptCanvasSceneId = previousAsset.Get()->GetScriptCanvasId(); GraphCanvas::SceneNotificationBus::MultiHandler::BusDisconnect(previousScriptCanvasSceneId); } AZ::EntityId nextAssetGraphCanvasId; - if (nextAsset.IsValid()) + if (nextAsset.IsGraphValid()) { // Connect the next asset EditorGraphRequestBus::EventResult(nextAssetGraphCanvasId, nextAsset.Get()->GetScriptCanvasId(), &EditorGraphRequests::GetGraphCanvasGraphId); @@ -2581,7 +2587,7 @@ namespace ScriptCanvasEditor AssetHelpers::PrintInfo("SetActiveAsset : from: %s to %s", m_activeGraph.ToString().c_str(), fileAssetId.ToString().c_str()); - if (fileAssetId.IsValid()) + if (fileAssetId.IsGraphValid()) { if (m_tabBar->FindTab(fileAssetId) >= 0) { @@ -2594,7 +2600,7 @@ namespace ScriptCanvasEditor } } - if (m_activeGraph.IsValid()) + if (m_activeGraph.IsGraphValid()) { // If we are saving the asset, the Id may have changed from the in-memory to the file asset Id, in that case, // there's no need to hide the view or remove the widget @@ -2607,7 +2613,7 @@ namespace ScriptCanvasEditor } } - if (fileAssetId.IsValid()) + if (fileAssetId.IsGraphValid()) { ScriptCanvasEditor::SourceHandle previousAssetId = m_activeGraph; m_activeGraph = fileAssetId; @@ -2629,7 +2635,7 @@ namespace ScriptCanvasEditor void MainWindow::RefreshActiveAsset() { - if (m_activeGraph.IsValid()) + if (m_activeGraph.IsGraphValid()) { AssetHelpers::PrintInfo("RefreshActiveAsset : m_activeGraph (%s)", m_activeGraph.ToString().c_str()); if (auto view = m_tabBar->ModOrCreateTabView(m_tabBar->FindTab(m_activeGraph))) @@ -2760,7 +2766,7 @@ namespace ScriptCanvasEditor if (m_isClosingTabs) { if (m_tabBar->count() == 0 - || (m_tabBar->count() == 1 && m_skipTabOnClose.IsValid())) + || (m_tabBar->count() == 1 && m_skipTabOnClose.IsGraphValid())) { m_isClosingTabs = false; m_skipTabOnClose.Clear(); @@ -3001,7 +3007,7 @@ namespace ScriptCanvasEditor bool hasCopiableSelection = false; bool hasSelection = false; - if (m_activeGraph.IsValid()) + if (m_activeGraph.IsGraphValid()) { if (graphCanvasGraphId.IsValid()) { @@ -3394,17 +3400,17 @@ namespace ScriptCanvasEditor { m_isRestoringWorkspace = false; - if (m_queuedFocusOverride.IsValid()) + if (m_queuedFocusOverride.IsGraphValid()) { SetActiveAsset(m_queuedFocusOverride); m_queuedFocusOverride.Clear(); } - else if (lastFocusAsset.IsValid()) + else if (lastFocusAsset.IsGraphValid()) { SetActiveAsset(lastFocusAsset); } - if (!m_activeGraph.IsValid()) + if (!m_activeGraph.IsGraphValid()) { if (m_tabBar->count() > 0) { @@ -3427,7 +3433,7 @@ namespace ScriptCanvasEditor void MainWindow::UpdateAssignToSelectionState() { - bool buttonEnabled = m_activeGraph.IsValid(); + bool buttonEnabled = m_activeGraph.IsGraphValid(); if (buttonEnabled) { @@ -3787,7 +3793,7 @@ namespace ScriptCanvasEditor OnFileNew(); - if (m_activeGraph.IsValid()) + if (m_activeGraph.IsGraphValid()) { graphId = GetActiveGraphCanvasGraphId(); } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp index 830d09c7dd..71aeb1dbb9 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp @@ -118,7 +118,7 @@ namespace ScriptCanvasEditor SourceHandle Modifier::LoadAsset() { auto& handle = ModCurrentAsset(); - if (!handle.IsValid()) + if (!handle.IsGraphValid()) { auto outcome = LoadFromFile(handle.Path().c_str()); if (outcome.IsSuccess()) @@ -158,7 +158,7 @@ namespace ScriptCanvasEditor ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeModificationBegin, m_config, ModCurrentAsset()); - if (auto asset = LoadAsset(); asset.IsValid()) + if (auto asset = LoadAsset(); asset.IsGraphValid()) { ModificationNotificationsBus::Handler::BusConnect(); m_modifyState = ModifyState::InProgress; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp index f9fc6e497d..816ded8a7b 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp @@ -132,7 +132,7 @@ namespace ScriptCanvasEditor } else { - if (auto asset = LoadAsset(); asset.IsValid()) + if (auto asset = LoadAsset(); asset.IsGraphValid()) { VE_LOG("Scanner: Loaded: %s ", ModCurrentAsset().Path().c_str()); FilterAsset(asset); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp index 8e3d5c53e8..fd9d2ccd57 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp @@ -237,16 +237,16 @@ namespace ScriptCanvasEditor return m_id; } - bool SourceHandle::IsValid() const - { - return m_data != nullptr; - } - - bool SourceHandle::IsValidDescription() const + bool SourceHandle::IsDescriptionValid() const { return !m_id.IsNull() && !m_path.empty(); } + bool SourceHandle::IsGraphValid() const + { + return m_data != nullptr; + } + GraphPtr SourceHandle::Mod() const { return m_data ? m_data->ModEditorGraph() : nullptr; @@ -290,7 +290,7 @@ namespace ScriptCanvasEditor { return AZStd::string::format ( "%s, %s, %s" - , IsValid() ? "O" : "X" + , IsGraphValid() ? "O" : "X" , m_path.empty() ? m_path.c_str() : "" , m_id.IsNull() ? "" : m_id.ToString().c_str()); } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h index 8671197f7b..b5cf9c22b3 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h @@ -342,9 +342,9 @@ namespace ScriptCanvasEditor const AZ::Uuid& Id() const; - bool IsValid() const; + bool IsDescriptionValid() const; - bool IsValidDescription() const; + bool IsGraphValid() const; GraphPtr Mod() const; diff --git a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake index 7f269e2081..449298097f 100644 --- a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake +++ b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake @@ -59,6 +59,8 @@ set(FILES Editor/Components/EditorGraphVariableManagerComponent.cpp Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h Editor/Components/EditorScriptCanvasComponent.cpp + Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponentSerializer.h + Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponentSerializer.cpp Editor/Components/IconComponent.h Editor/Components/IconComponent.cpp Editor/Include/ScriptCanvas/GraphCanvas/DynamicSlotBus.h From 24b3167d4862c7231e5c7136cb7d3d37b52c44f5 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Mon, 22 Nov 2021 20:34:11 -0800 Subject: [PATCH 038/128] EditorCOmponent build pipeline WIP Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Builder/ScriptCanvasBuilder.cpp | 127 ++--------------- .../Code/Builder/ScriptCanvasBuilder.h | 27 +--- .../Assets/ScriptCanvasFileHandling.cpp | 132 +++++++++++++++++- .../EditorScriptCanvasComponent.cpp | 43 ++++-- .../Code/Editor/Components/EditorUtils.cpp | 13 ++ .../Assets/ScriptCanvasFileHandling.h | 18 +++ .../Components/EditorScriptCanvasComponent.h | 2 + .../ScriptCanvas/Components/EditorUtils.h | 2 + .../Code/Editor/View/Widgets/GraphTabBar.cpp | 1 + .../Widgets/SourceHandlePropertyAssetCtrl.cpp | 2 +- .../Code/Include/ScriptCanvas/Core/Core.cpp | 20 +++ .../Code/Include/ScriptCanvas/Core/Core.h | 6 +- 12 files changed, 233 insertions(+), 160 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp index a75b68b518..bb2b94bb50 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp @@ -13,23 +13,14 @@ #include #include #include - -namespace ScriptCanvasBuilderCpp -{ - void AppendTabs(AZStd::string& result, size_t depth) - { - for (size_t i = 0; i < depth; ++i) - { - result += "\t"; - } - } -} +#include +#include namespace ScriptCanvasBuilder { void BuildVariableOverrides::Clear() { - m_source.Reset(); + m_source = {}; m_variables.clear(); m_overrides.clear(); m_overridesUnused.clear(); @@ -104,6 +95,7 @@ namespace ScriptCanvasBuilder return m_variables.empty() && m_entityIds.empty() && m_dependencies.empty(); } + // #sc_editor_asset THIS MUST GET VERSIONED! void BuildVariableOverrides::Reflect(AZ::ReflectContext* reflectContext) { if (auto serializeContext = azrtti_cast(reflectContext)) @@ -203,45 +195,12 @@ namespace ScriptCanvasBuilder } } - EditorAssetTree* EditorAssetTree::ModRoot() - { - if (!m_parent) - { - return this; - } - - return m_parent->ModRoot(); - } - - void EditorAssetTree::SetParent(EditorAssetTree& parent) - { - m_parent = &parent; - } - - AZStd::string EditorAssetTree::ToString(size_t depth) const - { - AZStd::string result; - ScriptCanvasBuilderCpp::AppendTabs(result, depth); - result += m_asset.GetId().ToString(); - result += m_asset.GetHint(); - depth += m_dependencies.empty() ? 0 : 1; - - for (const auto& dependency : m_dependencies) - { - result += "\n"; - ScriptCanvasBuilderCpp::AppendTabs(result, depth); - result += dependency.ToString(depth); - } - - return result; - } - ScriptCanvas::RuntimeDataOverrides ConvertToRuntime(const BuildVariableOverrides& buildOverrides) { ScriptCanvas::RuntimeDataOverrides runtimeOverrides; runtimeOverrides.m_runtimeAsset = AZ::Data::Asset - (AZ::Data::AssetId(buildOverrides.m_source.GetId().m_guid, AZ_CRC("RuntimeData", 0x163310ae)), azrtti_typeid(), {}); + (AZ::Data::AssetId(buildOverrides.m_source.Id(), AZ_CRC("RuntimeData", 0x163310ae)), azrtti_typeid(), {}); runtimeOverrides.m_runtimeAsset.SetAutoLoadBehavior(AZ::Data::AssetLoadBehavior::PreLoad); runtimeOverrides.m_variableIndices.resize(buildOverrides.m_variables.size()); @@ -304,76 +263,9 @@ namespace ScriptCanvasBuilder return runtimeOverrides; } - AZ::Outcome LoadEditorAssetTree(AZ::Data::AssetId editorAssetId, AZStd::string_view assetHint, EditorAssetTree* parent) + AZ::Outcome ParseEditorAssetTree(const ScriptCanvasEditor::EditorAssetTree& editorAssetTree) { - EditorAssetTree result; - AZ::Data::AssetInfo assetInfo; - AZStd::string watchFolder; - bool resultFound = false; - - if (!AzToolsFramework::AssetSystemRequestBus::FindFirstHandler()) - { - return AZ::Failure(AZStd::string("LoadEditorAssetTree found no handler for AzToolsFramework::AssetSystemRequestBus.")); - } - - AzToolsFramework::AssetSystemRequestBus::BroadcastResult - ( resultFound - , &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourceUUID - , editorAssetId.m_guid - , assetInfo - , watchFolder); - - if (!resultFound) - { - return AZ::Failure(AZStd::string::format("LoadEditorAssetTree failed to get engine relative path from %s-%.*s.", editorAssetId.ToString().c_str(), aznumeric_cast(assetHint.size()), assetHint.data())); - } - - AZStd::vector dependentAssets; - - auto filterCB = [&dependentAssets](const AZ::Data::AssetFilterInfo& filterInfo)->bool - { - if (filterInfo.m_assetType == azrtti_typeid()) - { - dependentAssets.push_back(AZ::Data::AssetId(filterInfo.m_assetId.m_guid, 0)); - } - else if (filterInfo.m_assetType == azrtti_typeid()) - { - dependentAssets.push_back(filterInfo.m_assetId); - } - - return true; - }; - - auto loadAssetOutcome = ScriptCanvasBuilder::LoadEditorAsset(assetInfo.m_relativePath, editorAssetId, filterCB); - if (!loadAssetOutcome.IsSuccess()) - { - return AZ::Failure(AZStd::string::format("LoadEditorAssetTree failed to load graph from %s-%s: %s", editorAssetId.ToString().c_str(), assetHint.data(), loadAssetOutcome.GetError().c_str())); - } - - for (auto& dependentAsset : dependentAssets) - { - auto loadDependentOutcome = LoadEditorAssetTree(dependentAsset, "", &result); - if (!loadDependentOutcome.IsSuccess()) - { - return AZ::Failure(AZStd::string::format("LoadEditorAssetTree failed to load dependent graph from %s-%s: %s", editorAssetId.ToString().c_str(), assetHint.data(), loadDependentOutcome.GetError().c_str())); - } - - result.m_dependencies.push_back(loadDependentOutcome.TakeValue()); - } - - if (parent) - { - result.SetParent(*parent); - } - - result.m_asset = loadAssetOutcome.TakeValue(); - - return AZ::Success(result); - } - - AZ::Outcome ParseEditorAssetTree(const EditorAssetTree& editorAssetTree) - { - auto buildEntity = editorAssetTree.m_asset->GetScriptCanvasEntity(); + auto buildEntity = editorAssetTree.m_asset.Get()->GetEntity(); if (!buildEntity) { return AZ::Failure(AZStd::string("No entity from source asset")); @@ -409,9 +301,8 @@ namespace ScriptCanvasBuilder if (!parseDependentOutcome.IsSuccess()) { return AZ::Failure(AZStd::string::format - ( "ParseEditorAssetTree failed to parse dependent graph from %s-%s: %s" - , dependentAsset.m_asset.GetId().ToString().c_str() - , dependentAsset.m_asset.GetHint().c_str() + ( "ParseEditorAssetTree failed to parse dependent graph from %s: %s" + , dependentAsset.m_asset.ToString().c_str() , parseDependentOutcome.GetError().c_str())); } diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.h b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.h index f03e78bc3e..0dedd67847 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.h +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.h @@ -16,6 +16,7 @@ namespace ScriptCanvasEditor { class ScriptCanvasAsset; + class EditorAssetTree; } namespace ScriptCanvasBuilder @@ -39,8 +40,8 @@ namespace ScriptCanvasBuilder void PopulateFromParsedResults(ScriptCanvas::Grammar::AbstractCodeModelConstPtr abstractCodeModel, const ScriptCanvas::VariableData& variables); // #functions2 provide an identifier for the node/variable in the source that caused the dependency. the root will not have one. - AZ::Data::Asset m_source; - + ScriptCanvasEditor::SourceHandle m_source; + // all of the variables here are overrides AZStd::vector m_variables; // the values here may or may not be overrides @@ -48,30 +49,12 @@ namespace ScriptCanvasBuilder // these two variable lists are all that gets exposed to the edit context AZStd::vector m_overrides; AZStd::vector m_overridesUnused; - // AZStd::vector m_entityIdRuntimeInputIndices; since all of the entity ids need to go in, they may not need indices + // AZStd::vector m_entityIdRuntimeInputIndices; since all oSf the entity ids need to go in, they may not need indices AZStd::vector m_dependencies; }; - class EditorAssetTree - { - public: - AZ_CLASS_ALLOCATOR(EditorAssetTree, AZ::SystemAllocator, 0); - - EditorAssetTree* m_parent = nullptr; - AZStd::vector m_dependencies; - AZ::Data::Asset m_asset; - - EditorAssetTree* ModRoot(); - - void SetParent(EditorAssetTree& parent); - - AZStd::string ToString(size_t depth = 0) const; - }; - // copy the variables overridden during editor / prefab build time back to runtime data ScriptCanvas::RuntimeDataOverrides ConvertToRuntime(const BuildVariableOverrides& overrides); - AZ::Outcome LoadEditorAssetTree(AZ::Data::AssetId editorAssetId, AZStd::string_view assetHint, EditorAssetTree* parent = nullptr); - - AZ::Outcome ParseEditorAssetTree(const EditorAssetTree& editorAssetTree); + AZ::Outcome ParseEditorAssetTree(const ScriptCanvasEditor::EditorAssetTree& editorAssetTree); } diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp index d806eb7e24..e5d9e86fbe 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp @@ -22,18 +22,26 @@ #include #include #include - +#include + namespace ScriptCanvasFileHandlingCpp { - using namespace ScriptCanvas; + void AppendTabs(AZStd::string& result, size_t depth) + { + for (size_t i = 0; i < depth; ++i) + { + result += "\t"; + } + } - void CollectNodes(const GraphData::NodeContainer& container, SerializationListeners& listeners) + void CollectNodes(const ScriptCanvas::GraphData::NodeContainer& container, ScriptCanvas::SerializationListeners& listeners) { for (auto& nodeEntity : container) { if (nodeEntity) { - if (auto listener = azrtti_cast(AZ::EntityUtils::FindFirstDerivedComponent(nodeEntity))) + if (auto listener = azrtti_cast + ( AZ::EntityUtils::FindFirstDerivedComponent(nodeEntity))) { listeners.push_back(listener); } @@ -44,6 +52,38 @@ namespace ScriptCanvasFileHandlingCpp namespace ScriptCanvasEditor { + EditorAssetTree* EditorAssetTree::ModRoot() + { + if (!m_parent) + { + return this; + } + + return m_parent->ModRoot(); + } + + void EditorAssetTree::SetParent(EditorAssetTree& parent) + { + m_parent = &parent; + } + + AZStd::string EditorAssetTree::ToString(size_t depth) const + { + AZStd::string result; + ScriptCanvasFileHandlingCpp::AppendTabs(result, depth); + result += m_asset.ToString(); + depth += m_dependencies.empty() ? 0 : 1; + + for (const auto& dependency : m_dependencies) + { + result += "\n"; + ScriptCanvasFileHandlingCpp::AppendTabs(result, depth); + result += dependency.ToString(depth); + } + + return result; + } + AZ::Outcome LoadDataFromJson ( ScriptCanvas::ScriptCanvasData& dataTarget , AZStd::string_view source @@ -87,6 +127,88 @@ namespace ScriptCanvasEditor return AZ::Success(); } + + AZ::Outcome LoadEditorAssetTree(SourceHandle handle, EditorAssetTree* parent) + { + if (!CompleteDescriptionInPlace(handle)) + { + return AZ::Failure(AZStd::string::format("LoadEditorAssetTree failed to describe graph from %s", handle.ToString().c_str())); + } + + auto loadAssetOutcome = LoadFromFile(handle.Path().c_str()); + if (!loadAssetOutcome.IsSuccess()) + { + return AZ::Failure(AZStd::string::format("LoadEditorAssetTree failed to load graph from %s: %s" + , handle.ToString().c_str(), loadAssetOutcome.GetError().c_str())); + } + + AZStd::vector dependentAssets; + + auto filterCB = [&dependentAssets](const AZ::Data::AssetFilterInfo& filterInfo)->bool + { + if (filterInfo.m_assetType == azrtti_typeid() + || filterInfo.m_assetType == azrtti_typeid()) + { + dependentAssets.push_back(SourceHandle(nullptr, filterInfo.m_assetId.m_guid, {})); + } + + return true; + }; + + const auto subgraphInterfaceAssetTypeID = azrtti_typeid>(); + + auto beginElementCB = [&subgraphInterfaceAssetTypeID, &dependentAssets] + ( void* instance + , const AZ::SerializeContext::ClassData* classData + , const AZ::SerializeContext::ClassElement* classElement) -> bool + { + if (classElement) + { + // if we are a pointer, then we may be pointing to a derived type. + if (classElement->m_flags & AZ::SerializeContext::ClassElement::FLG_POINTER) + { + // if ptr is a pointer-to-pointer, cast its value to a void* (or const void*) and dereference to get to the actual object pointer. + instance = *(void**)(instance); + } + + if (classData->m_typeId == subgraphInterfaceAssetTypeID) + { + auto id = reinterpret_cast*>(instance)->GetId(); + dependentAssets.push_back(SourceHandle(nullptr, id.m_guid, {})); + } + } + + return true; + }; + + AZ::SerializeContext* serializeContext = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext); + serializeContext->EnumerateObject( handle.Get(), beginElementCB, nullptr, AZ::SerializeContext::ENUM_ACCESS_FOR_READ); + + EditorAssetTree result; + + for (auto& dependentAsset : dependentAssets) + { + auto loadDependentOutcome = LoadEditorAssetTree(dependentAsset, &result); + if (!loadDependentOutcome.IsSuccess()) + { + return AZ::Failure(AZStd::string::format("LoadEditorAssetTree failed to load graph from %s: %s" + , dependentAsset.ToString().c_str(), loadDependentOutcome.GetError().c_str())); + } + + result.m_dependencies.push_back(loadDependentOutcome.TakeValue()); + } + + if (parent) + { + result.SetParent(*parent); + } + + result.m_asset = loadAssetOutcome.TakeValue(); + + return AZ::Success(result); + } + AZ::Outcome LoadFromFile(AZStd::string_view path) { namespace JSRU = AZ::JsonSerializationUtils; @@ -137,7 +259,7 @@ namespace ScriptCanvasEditor graph->MarkOwnership(*scriptCanvasData); } - return AZ::Success(ScriptCanvasEditor::SourceHandle(scriptCanvasData, {}, path)); + return AZ::Success(ScriptCanvasEditor::SourceHandle(scriptCanvasData, path)); } AZ::Outcome SaveToStream(const SourceHandle& source, AZ::IO::GenericStream& stream) diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp index e059ff555b..fd2aa3e884 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp @@ -134,7 +134,7 @@ namespace ScriptCanvasEditor } ScriptCanvasBuilder::BuildVariableOverrides overrides; - overrides.m_source = AZ::Data::Asset(assetHolder.GetAssetId(), assetHolder.GetAssetType(), assetHolder.GetAssetHint());; + overrides.m_source = SourceHandle(nullptr, assetHolder.GetAssetId().m_guid, {}); for (auto& variable : editableData.GetVariables()) { @@ -197,14 +197,15 @@ namespace ScriptCanvasEditor ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Level", 0x9aeacc13)) ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/scripting/script-canvas/") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorScriptCanvasComponent::m_sourceHandle, "Script Canvas Source File", "Script Canvas source file associated with this component") - ->Attribute("BrowseIcon", ":/stylesheet/img/UI20/browse-edit-select-files.svg") - ->Attribute("EditButton", "") - ->Attribute("EditDescription", "Open in Script Canvas Editor") - ->Attribute("EditCallback", &EditorScriptCanvasComponent::OpenEditor) - ->Attribute(AZ::Edit::Attributes::AssetPickerTitle, "Script Canvas") - ->Attribute(AZ::Edit::Attributes::SourceAssetFilterPattern, "*.scriptcanvas") + ->Attribute("BrowseIcon", ":/stylesheet/img/UI20/browse-edit-select-files.svg") + ->Attribute("EditButton", "") + ->Attribute("EditDescription", "Open in Script Canvas Editor") + ->Attribute("EditCallback", &EditorScriptCanvasComponent::OpenEditor) + ->Attribute(AZ::Edit::Attributes::AssetPickerTitle, "Script Canvas") + ->Attribute(AZ::Edit::Attributes::SourceAssetFilterPattern, "*.scriptcanvas") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorScriptCanvasComponent::OnFileSelectionChanged) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorScriptCanvasComponent::m_variableOverrides, "Properties", "Script Canvas Graph Properties") - ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ; } } @@ -319,7 +320,7 @@ namespace ScriptCanvasEditor m_runtimeDataIsValid = false; - auto assetTreeOutcome = LoadEditorAssetTree(m_sourceHandle.Id(), m_sourceHandle.Path().c_str()); + auto assetTreeOutcome = LoadEditorAssetTree(m_sourceHandle); if (!assetTreeOutcome.IsSuccess()) { AZ_Warning("ScriptCanvas", false, "EditorScriptCanvasComponent::BuildGameEntityData failed: %s", assetTreeOutcome.GetError().c_str()); @@ -386,6 +387,26 @@ namespace ScriptCanvasEditor return m_sourceHandle.Id(); } + AZ::u32 EditorScriptCanvasComponent::OnFileSelectionChanged() + { + m_sourceHandle = SourceHandle(nullptr, m_sourceHandle.Path()); + CompleteDescriptionInPlace(m_sourceHandle); + + m_previousHandle = {}; + m_removedHandle = {}; + + if (m_sourceHandle.IsDescriptionValid()) + { + OnScriptCanvasAssetChanged(m_sourceHandle); + } + else + { + ClearVariables(); + } + + return AZ::Edit::PropertyRefreshLevels::EntireTree; + } + void EditorScriptCanvasComponent::OnScriptCanvasAssetChanged(const SourceHandle& assetId) { ScriptCanvas::GraphIdentifier newIdentifier = GetGraphIdentifier(); @@ -492,10 +513,6 @@ namespace ScriptCanvasEditor UpdateName(); AzToolsFramework::ToolsApplicationNotificationBus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree_NewContent); } - else - { - // #sc_editor_asset clear or disable something - } } void EditorScriptCanvasComponent::ClearVariables() diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp index dccc50f732..d21b3d004c 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp @@ -78,6 +78,19 @@ namespace ScriptCanvasEditor return AZStd::nullopt; } + bool CompleteDescriptionInPlace(SourceHandle& source) + { + if (auto completed = CompleteDescription(source)) + { + source = *completed; + return true; + } + else + { + return false; + } + } + ////////////////////////// // NodeIdentifierFactory ////////////////////////// diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h index c88a7df28b..dd0e7aeb62 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h @@ -26,6 +26,22 @@ namespace ScriptCanvas namespace ScriptCanvasEditor { + class EditorAssetTree + { + public: + AZ_CLASS_ALLOCATOR(EditorAssetTree, AZ::SystemAllocator, 0); + + EditorAssetTree* m_parent = nullptr; + AZStd::vector m_dependencies; + SourceHandle m_asset; + + EditorAssetTree* ModRoot(); + + void SetParent(EditorAssetTree& parent); + + AZStd::string ToString(size_t depth = 0) const; + }; + AZ::Outcome LoadFromFile(AZStd::string_view path); AZ::Outcome LoadDataFromJson @@ -33,5 +49,7 @@ namespace ScriptCanvasEditor , AZStd::string_view source , AZ::SerializeContext& serializeContext); + AZ::Outcome LoadEditorAssetTree(SourceHandle handle, EditorAssetTree* parent = nullptr); + AZ::Outcome SaveToStream(const SourceHandle& source, AZ::IO::GenericStream& stream); } diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h index 31ef111b7b..19347e25eb 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h @@ -121,6 +121,8 @@ namespace ScriptCanvasEditor void SourceFileRemoved(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid fileAssetId) override; void SourceFileFailed(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid fileAssetId) override; + AZ::u32 OnFileSelectionChanged(); + void OnScriptCanvasAssetChanged(const SourceHandle& sourceHandle); void UpdateName(); diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorUtils.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorUtils.h index 0d27d255af..a4522198b7 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorUtils.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorUtils.h @@ -25,6 +25,8 @@ namespace ScriptCanvasEditor // If both Path and Id is valid, including after correction, returns the handle including source Data, // otherwise, returns null AZStd::optional CompleteDescription(const SourceHandle& source); + // if CompleteDescription() succeeds, sets the handle to the result, else does nothing + bool CompleteDescriptionInPlace(SourceHandle& source); class Graph; class NodePaletteModel; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp index 6ea8f3a75d..17228565da 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp @@ -154,6 +154,7 @@ namespace ScriptCanvasEditor canvasWidget->SetDefaultBorderColor(ScriptCanvasAssetDescription().GetDisplayColorImpl()); metaData.m_canvasWidget = canvasWidget; metaData.m_assetId = assetId; + metaData.m_fileState = fileState; AZStd::string tabName; AzFramework::StringFunc::Path::GetFileName(assetId.Path().c_str(), tabName); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp index 04f7d79da5..3e4cb7cd49 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/SourceHandlePropertyAssetCtrl.cpp @@ -138,7 +138,7 @@ namespace ScriptCanvasEditor (void)index; (void)node; - auto sourceHandle = SourceHandle(nullptr, {}, GUI->GetSelectedSourcePath()); + auto sourceHandle = SourceHandle(nullptr, GUI->GetSelectedSourcePath()); auto completeSourceHandle = CompleteDescription(sourceHandle); if (completeSourceHandle) { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp index fd9d2ccd57..1ac7a33821 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.cpp @@ -189,6 +189,10 @@ namespace ScriptCanvas namespace ScriptCanvasEditor { + SourceHandle::SourceHandle() + : m_id(AZ::Uuid::CreateNull()) + {} + SourceHandle::SourceHandle(const SourceHandle& data, const AZ::Uuid& id, const AZ::IO::Path& path) : m_data(data.m_data) , m_id(id) @@ -207,6 +211,22 @@ namespace ScriptCanvasEditor m_id = id; } + SourceHandle::SourceHandle(const SourceHandle& data, const AZ::IO::Path& path) + : m_data(data.m_data) + , m_id(AZ::Uuid::CreateNull()) + , m_path(path) + { + m_path.MakePreferred(); + } + + SourceHandle::SourceHandle(ScriptCanvas::DataPtr graph, const AZ::IO::Path& path) + : m_data(graph) + , m_id(AZ::Uuid::CreateNull()) + , m_path(path) + { + m_path.MakePreferred(); + } + bool SourceHandle::AnyEquals(const SourceHandle& other) const { return m_data && m_data == other.m_data diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h index b5cf9c22b3..297ee70500 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h @@ -325,12 +325,16 @@ namespace ScriptCanvasEditor static void Reflect(AZ::ReflectContext* context); - SourceHandle() = default; + SourceHandle(); SourceHandle(const SourceHandle& data, const AZ::Uuid& id, const AZ::IO::Path& path); SourceHandle(ScriptCanvas::DataPtr graph, const AZ::Uuid& id, const AZ::IO::Path& path); + SourceHandle(const SourceHandle& data, const AZ::IO::Path& path); + + SourceHandle(ScriptCanvas::DataPtr graph, const AZ::IO::Path& path); + bool AnyEquals(const SourceHandle& other) const; void Clear(); From cdb858e8af8b621e3809442775392904dde89b0b Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Tue, 23 Nov 2021 10:31:26 -0800 Subject: [PATCH 039/128] Editor Script Component simplified and working Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Builder/ScriptCanvasBuilder.cpp | 18 +++++-- .../Assets/ScriptCanvasFileHandling.cpp | 49 ++++++++++--------- .../EditorScriptCanvasComponent.cpp | 46 ++++++++--------- .../Components/EditorScriptCanvasComponent.h | 10 +++- .../ScriptCanvas/Variable/GraphVariable.cpp | 5 ++ .../ScriptCanvas/Variable/GraphVariable.h | 2 + 6 files changed, 74 insertions(+), 56 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp index bb2b94bb50..fe89c57009 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp @@ -30,11 +30,10 @@ namespace ScriptCanvasBuilder void BuildVariableOverrides::CopyPreviousOverriddenValues(const BuildVariableOverrides& source) { - auto isEqual = [](const ScriptCanvas::GraphVariable& overrideValue, const ScriptCanvas::GraphVariable& candidate) + auto isEqual = [](const ScriptCanvas::GraphVariable& lhs, const ScriptCanvas::GraphVariable& rhs) { - return candidate.GetVariableId() == overrideValue.GetVariableId() - || (candidate.GetVariableName() == overrideValue.GetVariableName() - && candidate.GetDataType() == overrideValue.GetDataType()); + return (lhs.GetVariableId() == rhs.GetVariableId() && lhs.GetDataType() == rhs.GetDataType()) + || (lhs.GetVariableName() == rhs.GetVariableName() && lhs.GetDataType() == rhs.GetDataType()); }; auto copyPreviousIfFound = [isEqual](ScriptCanvas::GraphVariable& overriddenValue, const AZStd::vector& source) @@ -44,7 +43,7 @@ namespace ScriptCanvasBuilder if (iter != source.end()) { - overriddenValue.DeepCopy(*iter); + overriddenValue.ModDatum().DeepCopyDatum(*iter->GetDatum()); overriddenValue.SetScriptInputControlVisibility(AZ::Edit::PropertyVisibility::Hide); overriddenValue.SetAllowSignalOnChange(false); return true; @@ -64,6 +63,15 @@ namespace ScriptCanvasBuilder } } + for (auto& overriddenValue : m_overridesUnused) + { + if (!copyPreviousIfFound(overriddenValue, source.m_overridesUnused)) + { + // the variable in question may have been previously used, and is now unused, so copy the previous value over + copyPreviousIfFound(overriddenValue, source.m_overrides); + } + } + ////////////////////////////////////////////////////////////////////////// // #functions2 provide an identifier for the node/variable in the source that caused the dependency. the root will not have one. // the above will provide the data to handle the cases where only certain dependency nodes were removed diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp index e5d9e86fbe..8cecdc86d9 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp @@ -23,7 +23,8 @@ #include #include #include - +#include + namespace ScriptCanvasFileHandlingCpp { void AppendTabs(AZStd::string& result, size_t depth) @@ -135,26 +136,19 @@ namespace ScriptCanvasEditor return AZ::Failure(AZStd::string::format("LoadEditorAssetTree failed to describe graph from %s", handle.ToString().c_str())); } - auto loadAssetOutcome = LoadFromFile(handle.Path().c_str()); - if (!loadAssetOutcome.IsSuccess()) + if (!handle.Get()) { - return AZ::Failure(AZStd::string::format("LoadEditorAssetTree failed to load graph from %s: %s" - , handle.ToString().c_str(), loadAssetOutcome.GetError().c_str())); - } - - AZStd::vector dependentAssets; - - auto filterCB = [&dependentAssets](const AZ::Data::AssetFilterInfo& filterInfo)->bool - { - if (filterInfo.m_assetType == azrtti_typeid() - || filterInfo.m_assetType == azrtti_typeid()) + auto loadAssetOutcome = LoadFromFile(handle.Path().c_str()); + if (!loadAssetOutcome.IsSuccess()) { - dependentAssets.push_back(SourceHandle(nullptr, filterInfo.m_assetId.m_guid, {})); + return AZ::Failure(AZStd::string::format("LoadEditorAssetTree failed to load graph from %s: %s" + , handle.ToString().c_str(), loadAssetOutcome.GetError().c_str())); } - return true; - }; + handle = SourceHandle(loadAssetOutcome.GetValue(), handle.Id(), handle.Path().c_str()); + } + AZStd::vector dependentAssets; const auto subgraphInterfaceAssetTypeID = azrtti_typeid>(); auto beginElementCB = [&subgraphInterfaceAssetTypeID, &dependentAssets] @@ -170,12 +164,13 @@ namespace ScriptCanvasEditor // if ptr is a pointer-to-pointer, cast its value to a void* (or const void*) and dereference to get to the actual object pointer. instance = *(void**)(instance); } + } - if (classData->m_typeId == subgraphInterfaceAssetTypeID) - { - auto id = reinterpret_cast*>(instance)->GetId(); - dependentAssets.push_back(SourceHandle(nullptr, id.m_guid, {})); - } + if (classData->m_typeId == subgraphInterfaceAssetTypeID) + { + auto asset = reinterpret_cast*>(instance); + auto id = asset->GetId(); + dependentAssets.push_back(SourceHandle(nullptr, id.m_guid, {})); } return true; @@ -183,7 +178,10 @@ namespace ScriptCanvasEditor AZ::SerializeContext* serializeContext = nullptr; AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext); - serializeContext->EnumerateObject( handle.Get(), beginElementCB, nullptr, AZ::SerializeContext::ENUM_ACCESS_FOR_READ); + AZ_Assert(serializeContext, "LoadEditorAssetTree() ailed to retrieve serialize context!"); + + const ScriptCanvasEditor::Graph* graph = handle.Get(); + serializeContext->EnumerateObject(graph, beginElementCB, nullptr, AZ::SerializeContext::ENUM_ACCESS_FOR_READ); EditorAssetTree result; @@ -204,8 +202,7 @@ namespace ScriptCanvasEditor result.SetParent(*parent); } - result.m_asset = loadAssetOutcome.TakeValue(); - + result.m_asset = AZStd::move(handle); return AZ::Success(result); } @@ -252,6 +249,10 @@ namespace ScriptCanvasEditor if (auto entity = scriptCanvasData->GetScriptCanvasEntity()) { + AZ_Assert(entity->GetState() == AZ::Entity::State::Constructed, "Entity loaded in bad state"); + AZ::u64 entityId = + aznumeric_caster(ScriptCanvas::MathNodeUtilities::GetRandomIntegral(1, std::numeric_limits::max())); + entity->SetId(AZ::EntityId(entityId)); entity->Init(); entity->Activate(); diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp index fd2aa3e884..26fbf85a82 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp @@ -377,7 +377,7 @@ namespace ScriptCanvasEditor m_sourceHandle = *completeAsset; } - OnScriptCanvasAssetChanged(m_sourceHandle); + OnScriptCanvasAssetChanged(SourceChangeDescription::SelectionChanged); SetName(m_sourceHandle.Path().Filename().Native()); AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues); } @@ -391,26 +391,16 @@ namespace ScriptCanvasEditor { m_sourceHandle = SourceHandle(nullptr, m_sourceHandle.Path()); CompleteDescriptionInPlace(m_sourceHandle); - m_previousHandle = {}; m_removedHandle = {}; - - if (m_sourceHandle.IsDescriptionValid()) - { - OnScriptCanvasAssetChanged(m_sourceHandle); - } - else - { - ClearVariables(); - } - + OnScriptCanvasAssetChanged(SourceChangeDescription::SelectionChanged); return AZ::Edit::PropertyRefreshLevels::EntireTree; } - void EditorScriptCanvasComponent::OnScriptCanvasAssetChanged(const SourceHandle& assetId) + void EditorScriptCanvasComponent::OnScriptCanvasAssetChanged(SourceChangeDescription changeDescription) { ScriptCanvas::GraphIdentifier newIdentifier = GetGraphIdentifier(); - newIdentifier.m_assetId = assetId.Id(); + newIdentifier.m_assetId = m_sourceHandle.Id(); ScriptCanvas::GraphIdentifier oldIdentifier = GetGraphIdentifier(); oldIdentifier.m_assetId = m_previousHandle.Id(); @@ -419,21 +409,24 @@ namespace ScriptCanvasEditor m_previousHandle = m_sourceHandle.Describe(); - // Only clear our variables when we are given a new asset id - // or when the asset was explicitly set to empty. - // - // i.e. do not clear variables when we lose the catalog asset. - if ((assetId.IsDescriptionValid() && assetId.Describe() != m_removedHandle.Describe()) - || (!assetId.IsDescriptionValid() && !m_removedHandle.IsDescriptionValid())) + if (changeDescription == SourceChangeDescription::SelectionChanged) { ClearVariables(); } - if (assetId.IsDescriptionValid()) + if (m_sourceHandle.IsDescriptionValid()) { - if (auto loaded = LoadFromFile(assetId.Path().c_str()); loaded.IsSuccess()) + if (!m_sourceHandle.Get()) { - UpdatePropertyDisplay(loaded.GetValue()); + if (auto loaded = LoadFromFile(m_sourceHandle.Path().c_str()); loaded.IsSuccess()) + { + m_sourceHandle = SourceHandle(loaded.TakeValue(), m_sourceHandle.Id(), m_sourceHandle.Path().c_str()); + } + } + + if (m_sourceHandle.Get()) + { + UpdatePropertyDisplay(m_sourceHandle); } } @@ -467,8 +460,9 @@ namespace ScriptCanvasEditor { if (auto handle = CompleteDescription(SourceHandle(nullptr, fileAssetId, {}))) { + m_sourceHandle = *handle; // consider queueing on tick bus - OnScriptCanvasAssetChanged(*handle); + OnScriptCanvasAssetChanged(SourceChangeDescription::Modified); } } } @@ -479,7 +473,7 @@ namespace ScriptCanvasEditor if (fileAssetId == m_sourceHandle.Id()) { m_removedHandle = m_sourceHandle; - OnScriptCanvasAssetChanged(m_removedHandle); + OnScriptCanvasAssetChanged(SourceChangeDescription::Removed); } } @@ -489,7 +483,7 @@ namespace ScriptCanvasEditor if (fileAssetId == m_sourceHandle.Id()) { m_removedHandle = m_sourceHandle; - OnScriptCanvasAssetChanged(m_removedHandle); + OnScriptCanvasAssetChanged(SourceChangeDescription::Error); } } diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h index 19347e25eb..52cf49070b 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorScriptCanvasComponent.h @@ -98,6 +98,14 @@ namespace ScriptCanvasEditor void OnStopPlayInEditor() override; protected: + enum class SourceChangeDescription : AZ::u8 + { + Error, + Modified, + Removed, + SelectionChanged, + }; + static void Reflect(AZ::ReflectContext* context); static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) @@ -123,7 +131,7 @@ namespace ScriptCanvasEditor AZ::u32 OnFileSelectionChanged(); - void OnScriptCanvasAssetChanged(const SourceHandle& sourceHandle); + void OnScriptCanvasAssetChanged(SourceChangeDescription changeDescription); void UpdateName(); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.cpp index 8b8dfdc3fc..59b924196b 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.cpp @@ -335,6 +335,11 @@ namespace ScriptCanvas return &m_datum; } + Datum& GraphVariable::ModDatum() + { + return m_datum; + } + void GraphVariable::ConfigureDatumView(ModifiableDatumView& datumView) { datumView.ConfigureView((*this)); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.h index e7829ca6c1..db83076f67 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.h @@ -127,6 +127,8 @@ namespace ScriptCanvas const Datum* GetDatum() const; + Datum& ModDatum(); + bool IsComponentProperty() const; void ConfigureDatumView(ModifiableDatumView& accessController); From 93d6a0ef24e695a1eee14a9345bec923b71da9f4 Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Tue, 23 Nov 2021 22:53:51 +0000 Subject: [PATCH 040/128] Move to development and add review fixes. Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- .../Assets/Prefabs/PinkFlower.prefab | 131 +++++++++++ ...ystem_VegetationSpawnsOnTerrainSurfaces.py | 211 ++++++++++++++++++ .../Gem/PythonTests/Terrain/TestSuite_Main.py | 4 + .../TerrainSurfaceGradientListComponent.cpp | 12 + 4 files changed, 358 insertions(+) create mode 100644 AutomatedTesting/Assets/Prefabs/PinkFlower.prefab create mode 100644 AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainSystem_VegetationSpawnsOnTerrainSurfaces.py diff --git a/AutomatedTesting/Assets/Prefabs/PinkFlower.prefab b/AutomatedTesting/Assets/Prefabs/PinkFlower.prefab new file mode 100644 index 0000000000..47dd6bc8d3 --- /dev/null +++ b/AutomatedTesting/Assets/Prefabs/PinkFlower.prefab @@ -0,0 +1,131 @@ +{ + "ContainerEntity": { + "Id": "ContainerEntity", + "Name": "PinkFlower", + "Components": { + "Component_[10444337162843472597]": { + "$type": "EditorLockComponent", + "Id": 10444337162843472597 + }, + "Component_[14431042590323756177]": { + "$type": "EditorEntitySortComponent", + "Id": 14431042590323756177, + "ChildEntityOrderEntryArray": [ + { + "EntityId": "Entity_[491002114939]" + } + ] + }, + "Component_[14577735453176806353]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 14577735453176806353 + }, + "Component_[15674021346798629563]": { + "$type": "EditorInspectorComponent", + "Id": 15674021346798629563 + }, + "Component_[16784074985702513600]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 16784074985702513600, + "Parent Entity": "" + }, + "Component_[3351614541100572773]": { + "$type": "EditorOnlyEntityComponent", + "Id": 3351614541100572773 + }, + "Component_[3600658560328167663]": { + "$type": "EditorPrefabComponent", + "Id": 3600658560328167663 + }, + "Component_[6155673728651558934]": { + "$type": "EditorEntityIconComponent", + "Id": 6155673728651558934 + }, + "Component_[8458684662170321289]": { + "$type": "EditorVisibilityComponent", + "Id": 8458684662170321289 + }, + "Component_[8705192117416252351]": { + "$type": "SelectionComponent", + "Id": 8705192117416252351 + }, + "Component_[8801280051488695852]": { + "$type": "EditorPendingCompositionComponent", + "Id": 8801280051488695852 + } + } + }, + "Entities": { + "Entity_[491002114939]": { + "Id": "Entity_[491002114939]", + "Name": "PinkFlower", + "Components": { + "Component_[11083205340162142682]": { + "$type": "EditorLockComponent", + "Id": 11083205340162142682 + }, + "Component_[11327363779873517]": { + "$type": "EditorOnlyEntityComponent", + "Id": 11327363779873517 + }, + "Component_[12717389211269537921]": { + "$type": "EditorEntitySortComponent", + "Id": 12717389211269537921 + }, + "Component_[12826285685970138542]": { + "$type": "AZ::Render::EditorMeshComponent", + "Id": 12826285685970138542, + "Controller": { + "Configuration": { + "ModelAsset": { + "assetId": { + "guid": "{549F4C4D-A7D9-5F2A-A6BD-F24C8BC43BBF}", + "subId": 280086017 + }, + "assetHint": "assets/objects/foliage/grass_flower_pink.azmodel" + } + } + } + }, + "Component_[14101419970865342875]": { + "$type": "EditorPendingCompositionComponent", + "Id": 14101419970865342875 + }, + "Component_[14770464075286403207]": { + "$type": "EditorVisibilityComponent", + "Id": 14770464075286403207 + }, + "Component_[15205142653091190082]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 15205142653091190082, + "Parent Entity": "ContainerEntity" + }, + "Component_[15510898811147803772]": { + "$type": "EditorInspectorComponent", + "Id": 15510898811147803772, + "ComponentOrderEntryArray": [ + { + "ComponentId": 15205142653091190082 + }, + { + "ComponentId": 12826285685970138542, + "SortIndex": 1 + } + ] + }, + "Component_[15988401742428977134]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 15988401742428977134 + }, + "Component_[4300550837037679336]": { + "$type": "EditorEntityIconComponent", + "Id": 4300550837037679336 + }, + "Component_[996914988793716659]": { + "$type": "SelectionComponent", + "Id": 996914988793716659 + } + } + } + } +} \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainSystem_VegetationSpawnsOnTerrainSurfaces.py b/AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainSystem_VegetationSpawnsOnTerrainSurfaces.py new file mode 100644 index 0000000000..694535f20d --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainSystem_VegetationSpawnsOnTerrainSurfaces.py @@ -0,0 +1,211 @@ +""" +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 +""" + +class VegetationTests: + vegetation_on_gradient_1 = ( + "Vegetation detected at correct position on Gradient1", + "Vegetation not detected at correct position on Gradient1" + ) + vegetation_on_gradient_2 = ( + "Vegetation detected at correct position on Gradient2", + "Vegetation not detected at correct position on Gradient2" + ) + unfiltered_vegetation_count_correct = ( + "Unfiltered vegetation spawn count correct", + "Unfiltered vegetation spawn count incorrect" + ) + + testTag2_excluded_vegetation_count_correct = ( + "TestTag2 filtered vegetation count correct", + "TestTag2 filtered vegetation count incorrect" + ) + testTag2_excluded_vegetation_z_correct = ( + "TestTag2 filtered vegetation spawned in correct position", + "TestTag2 filtered vegetation failed to spawn in correct position" + ) + + testTag3_excluded_vegetation_count_correct = ( + "TestTag3 filtered vegetation count correct", + "TestTag3 filtered vegetation count incorrect" + ) + testTag3_excluded_vegetation_z_correct = ( + "TestTag3 filtered vegetation spawned in correct position", + "TestTag3 filtered vegetation failed to spawn in correct position" + ) + + cleared_exclusion_vegetation_count_correct = ( + "Cleared filter vegetation count correct", + "Cleared filter vegetation count incorrect" + ) + +def TerrainSystem_VegetationSpawnsOnTerrainSurfaces(): + """ + Summary: + Load an empty level, + Create two entities with constant gradient components with different values. + Create two entities with TerrainLayerSpawners + Create an entity to spawn vegetation + Ensure that vegetation spawns at the correct heights + Add a VegetationSurfaceMaskFilter and ensure it responds correctly to surface changes. + :return: None + """ + + import os + import sys + import math as sys_math + + import azlmbr.legacy.general as general + import azlmbr.bus as bus + import azlmbr.math as math + + import azlmbr.areasystem as areasystem + import azlmbr.editor as editor + import azlmbr.vegetation as vegetation + import azlmbr.terrain as terrain + import azlmbr.entity as EntityId + import azlmbr.surface_data as surface_data + + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + + def create_entity_at(entity_name, components_to_add, x, y, z): + entity = hydra.Entity(entity_name) + entity.create_entity(math.Vector3(x, y, z), components_to_add) + + return entity + + def FindHighestAndLowestZValuesInArea(aabb): + vegetation_items = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', aabb) + + lowest_z = min([item.position.z for item in vegetation_items]) + highest_z = max([item.position.z for item in vegetation_items]) + + return highest_z, lowest_z + + helper.init_idle() + + # Open an empty level. + helper.open_level("Physics", "Base") + helper.wait_for_condition(lambda: general.get_current_level_name() == "Base", 2.0) + + general.idle_wait_frames(1) + + box_height = 20.0 + box_y_position = 10.0 + box_dimensions = math.Vector3(20.0, 20.0, box_height) + + # Add Terrain Rendering + hydra.add_level_component("Terrain World") + hydra.add_level_component("Terrain World Renderer") + + # Create two terrain entities at adjoining positions + terrain_entity_1 = create_entity_at("Terrain1", ["Terrain Layer Spawner", "Axis Aligned Box Shape", "Terrain Height Gradient List", "Terrain Surface Gradient List"], 0.0, box_y_position, box_height/2.0) + terrain_entity_1.get_set_test(1, "Axis Aligned Box Shape|Box Configuration|Dimensions", box_dimensions) + + terrain_entity_2 = create_entity_at("Terrain2", ["Terrain Layer Spawner", "Axis Aligned Box Shape", "Terrain Height Gradient List", "Terrain Surface Gradient List"], 20.0, box_y_position, box_height/2.0) + terrain_entity_2.get_set_test(1, "Axis Aligned Box Shape|Box Configuration|Dimensions", box_dimensions) + + # Create two gradient entities. + gradient_value_1 = 0.25 + gradient_value_2 = 0.5 + + gradient_entity_1 = create_entity_at("Gradient1", ["Constant Gradient"], 0.0, 0.0, 0.0) + gradient_entity_1.get_set_test(0, "Configuration|Value", gradient_value_1) + + gradient_entity_2 = create_entity_at("Gradient2", ["Constant Gradient"], 0.0, 0.0, 0.0) + gradient_entity_2.get_set_test(0, "Configuration|Value", gradient_value_2) + + mapping = terrain.TerrainSurfaceGradientMapping() + mapping.gradientEntityId = gradient_entity_1.id + pte = hydra.get_property_tree(terrain_entity_1.components[3]) + pte.add_container_item("Configuration|Gradient to Surface Mappings", 0, mapping) + + mapping = terrain.TerrainSurfaceGradientMapping() + mapping.gradientEntityId = gradient_entity_2.id + pte = hydra.get_property_tree(terrain_entity_2.components[3]) + pte.add_container_item("Configuration|Gradient to Surface Mappings", 0, mapping) + + # create a vegetation entity that overlaps both terrain entities. + vegetation_entity = create_entity_at("Vegetation", ["Vegetation Layer Spawner", "Axis Aligned Box Shape", "Vegetation Asset List", "Vegetation Surface Mask Filter"], 10.0, box_y_position, box_height/2.0) + vegetation_entity.get_set_test(1, "Axis Aligned Box Shape|Box Configuration|Dimensions", box_dimensions) + + # Set the vegetation area to a PrefabInstanceSpawner with a specific prefab asset selected. + prefab_spawner = vegetation.PrefabInstanceSpawner() + prefab_spawner.SetPrefabAssetPath(os.path.join("Prefabs", "PinkFlower.spawnable")) + descriptor = hydra.get_component_property_value(vegetation_entity.components[2], 'Configuration|Embedded Assets|[0]') + descriptor.spawner = prefab_spawner + vegetation_entity.get_set_test(2, "Configuration|Embedded Assets|[0]", descriptor) + + # Assign gradients to layer spawners. + terrain_entity_1.get_set_test(2, "Configuration|Gradient Entities", [gradient_entity_1.id]) + terrain_entity_2.get_set_test(2, "Configuration|Gradient Entities", [gradient_entity_2.id]) + + # Move view so that the entities are visible. + general.set_current_view_position(17.0, -66.0, 41.0) + general.set_current_view_rotation(-15, 0, 0) + + # Expected item counts under conditions to be tested + expected_surface_tag_excluded_item_count = 338 + expected_no_exclusions_item_count = 676 + + # Wait for the vegetation to spawn + helper.wait_for_condition(lambda: vegetation.VegetationSpawnerRequestBus(bus.Event, "GetAreaProductCount", vegetation_entity.id) == expected_no_exclusions_item_count, 5.0) + + # Check the spawn count is correct. + item_count = vegetation.VegetationSpawnerRequestBus(bus.Event, "GetAreaProductCount", vegetation_entity.id) + Report.result(VegetationTests.unfiltered_vegetation_count_correct, item_count == expected_no_exclusions_item_count) + + test_aabb = math.Aabb_CreateFromMinMax(math.Vector3(-10.0, -10.0, 0.0), math.Vector3(30.0, 10.0, box_height)) + + # Find the z positions of the items with the lowest and highest x values, this will avoid the overlap area where z values are blended between the surface heights. + highest_z, lowest_z = FindHighestAndLowestZValuesInArea(test_aabb) + + # Check that the z values are as expected. + Report.result(VegetationTests.vegetation_on_gradient_1, sys_math.isclose(lowest_z, box_height * gradient_value_1, abs_tol=0.01)) + Report.result(VegetationTests.vegetation_on_gradient_2, sys_math.isclose(highest_z, box_height * gradient_value_2, abs_tol=0.01)) + + # Assign SurfaceTags to the SurfaceGradientLists + terrain_entity_1.get_set_test(3, "Configuration|Gradient to Surface Mappings|[0]|Surface Tag", surface_data.SurfaceTag("test_tag2")) + terrain_entity_2.get_set_test(3, "Configuration|Gradient to Surface Mappings|[0]|Surface Tag", surface_data.SurfaceTag("test_tag3")) + + # Give the VegetationSurfaceFilter an exclusion list, set it to excude test_tag2 which should remove all the lower items which are in terrain_entity_1. + vegetation_entity.get_set_test(3, "Configuration|Exclusion|Surface Tags", [surface_data.SurfaceTag()]) + vegetation_entity.get_set_test(3, "Configuration|Exclusion|Surface Tags|[0]", surface_data.SurfaceTag("test_tag2")) + + # Wait for the vegetation to respawn and check z values. + helper.wait_for_condition(lambda: vegetation.VegetationSpawnerRequestBus(bus.Event, "GetAreaProductCount", vegetation_entity.id) == expected_surface_tag_excluded_item_count, 5.0) + + item_count = vegetation.VegetationSpawnerRequestBus(bus.Event, "GetAreaProductCount", vegetation_entity.id) + Report.result(VegetationTests.testTag2_excluded_vegetation_count_correct, item_count == expected_surface_tag_excluded_item_count) + + highest_z, lowest_z = FindHighestAndLowestZValuesInArea(test_aabb) + + Report.result(VegetationTests.testTag2_excluded_vegetation_z_correct, lowest_z > box_height * gradient_value_1) + + # Clear the filter and ensure vegetation respawns. + vegetation_entity.get_set_test(3, "Configuration|Exclusion|Surface Tags|[0]", surface_data.SurfaceTag("invalid")) + helper.wait_for_condition(lambda: vegetation.VegetationSpawnerRequestBus(bus.Event, "GetAreaProductCount", vegetation_entity.id) == expected_no_exclusions_item_count, 5.0) + + item_count = vegetation.VegetationSpawnerRequestBus(bus.Event, "GetAreaProductCount", vegetation_entity.id) + Report.result(VegetationTests.cleared_exclusion_vegetation_count_correct, item_count == expected_no_exclusions_item_count) + + # Exclude test_tag3 to exclude the higher items in terrain_entity_2 and recheck. + vegetation_entity.get_set_test(3, "Configuration|Exclusion|Surface Tags|[0]", surface_data.SurfaceTag("test_tag3")) + + helper.wait_for_condition(lambda: vegetation.VegetationSpawnerRequestBus(bus.Event, "GetAreaProductCount", vegetation_entity.id) == expected_surface_tag_excluded_item_count, 5.0) + + item_count = vegetation.VegetationSpawnerRequestBus(bus.Event, "GetAreaProductCount", vegetation_entity.id) + Report.result(VegetationTests.testTag3_excluded_vegetation_count_correct, item_count == expected_surface_tag_excluded_item_count) + + highest_z, lowest_z = FindHighestAndLowestZValuesInArea(test_aabb) + + Report.result(VegetationTests.testTag3_excluded_vegetation_z_correct, highest_z < box_height * gradient_value_2) + +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(TerrainSystem_VegetationSpawnsOnTerrainSurfaces) \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/Terrain/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Terrain/TestSuite_Main.py index 786651713c..ba8feaf24a 100644 --- a/AutomatedTesting/Gem/PythonTests/Terrain/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/Terrain/TestSuite_Main.py @@ -27,3 +27,7 @@ class TestAutomation(EditorTestSuite): class test_Terrain_SupportsPhysics(EditorSharedTest): from .EditorScripts import Terrain_SupportsPhysics as test_module + + class test_TerrainSystem_VegetationSpawnsOnTerrainSurfaces(EditorSharedTest): + from .EditorScripts import TerrainSystem_VegetationSpawnsOnTerrainSurfaces as test_module + diff --git a/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp index 748221d69e..4d93842654 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp @@ -8,6 +8,7 @@ #include +#include #include #include @@ -46,6 +47,17 @@ namespace Terrain ; } } + + if (auto behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Category, "Terrain") + ->Attribute(AZ::Script::Attributes::Module, "terrain") + ->Constructor() + ->Property("gradientEntityId", BehaviorValueProperty(&TerrainSurfaceGradientMapping::m_gradientEntityId)) + ->Property("surfaceTag", BehaviorValueProperty(&TerrainSurfaceGradientMapping::m_surfaceTag)); + } } void TerrainSurfaceGradientListConfig::Reflect(AZ::ReflectContext* context) From 30bcddc694dd24178057869fb2f5fba94296bfe1 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Tue, 23 Nov 2021 23:57:03 -0800 Subject: [PATCH 041/128] fixed unit testing code Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../AzCore/AzCore/Script/ScriptContext.cpp | 13 ++++ .../AzCore/Script/ScriptContextAttributes.h | 1 + .../ScriptCanvasBuilderWorkerUtility.cpp | 15 +---- .../Framework/ScriptCanvasGraphUtilities.inl | 17 ++++- .../Framework/ScriptCanvasTraceUtilities.h | 8 +-- .../Code/Editor/SystemComponent.cpp | 5 +- .../Include/ScriptCanvas/Core/Nodeable.cpp | 9 ++- .../Interpreted/ExecutionInterpretedAPI.cpp | 46 ++++++++++++++ .../Interpreted/ExecutionStateInterpreted.cpp | 2 + ...ExecutionStateInterpretedPerActivation.cpp | 62 +++++++++++++++++++ 10 files changed, 155 insertions(+), 23 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Script/ScriptContext.cpp b/Code/Framework/AzCore/AzCore/Script/ScriptContext.cpp index 45f7876993..841387f14d 100644 --- a/Code/Framework/AzCore/AzCore/Script/ScriptContext.cpp +++ b/Code/Framework/AzCore/AzCore/Script/ScriptContext.cpp @@ -5073,13 +5073,26 @@ LUA_API const Node* lua_getDummyNode() // Check all constructors if they have use ScriptDataContext and if so choose this one if (!customConstructorMethod) { + int overrideIndex = -1; + AZ::AttributeReader(nullptr, FindAttribute + ( Script::Attributes::DefaultConstructorOverrideIndex, behaviorClass->m_attributes)).Read(overrideIndex); + + int methodIndex = 0; for (BehaviorMethod* method : behaviorClass->m_constructors) { + if (methodIndex == overrideIndex) + { + customConstructorMethod = method; + break; + } + if (method->GetNumArguments() && method->GetArgument(method->GetNumArguments() - 1)->m_typeId == AZ::AzTypeInfo::Uuid()) { customConstructorMethod = method; break; } + + ++methodIndex; } } diff --git a/Code/Framework/AzCore/AzCore/Script/ScriptContextAttributes.h b/Code/Framework/AzCore/AzCore/Script/ScriptContextAttributes.h index 9807f0af39..e238289ef5 100644 --- a/Code/Framework/AzCore/AzCore/Script/ScriptContextAttributes.h +++ b/Code/Framework/AzCore/AzCore/Script/ScriptContextAttributes.h @@ -21,6 +21,7 @@ namespace AZ static constexpr AZ::Crc32 ClassNameOverride = AZ_CRC_CE("ScriptClassNameOverride"); ///< Provide a custom name for script reflection, that doesn't match the behavior Context name static constexpr AZ::Crc32 MethodOverride = AZ_CRC_CE("ScriptFunctionOverride"); ///< Use a custom function in the attribute instead of the function static constexpr AZ::Crc32 ConstructorOverride = AZ_CRC_CE("ConstructorOverride"); ///< You can provide a custom constructor to be called when created from Lua script + static constexpr AZ::Crc32 DefaultConstructorOverrideIndex = AZ_CRC_CE("DefaultConstructorOverrideIndex"); ///< Use a different class constructor as the default constructor in Lua static constexpr AZ::Crc32 EventHandlerCreationFunction = AZ_CRC_CE("EventHandlerCreationFunction"); ///< helps create a handler for any script target so that script functions can be used for AZ::Event signals static constexpr AZ::Crc32 GenericConstructorOverride = AZ_CRC_CE("GenericConstructorOverride"); ///< You can provide a custom constructor to be called when creating a script static constexpr AZ::Crc32 ReaderWriterOverride = AZ_CRC_CE("ReaderWriterOverride"); ///< paired with \ref ScriptContext::CustomReaderWriter allows you to customize read/write to Lua VM diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp index a68aeae5e9..fb7b5e7a4a 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp @@ -30,6 +30,8 @@ #include #include #include +#include + namespace ScriptCanvasBuilder { @@ -93,19 +95,6 @@ namespace ScriptCanvasBuilder request.printModelToConsole = ScriptCanvas::Grammar::g_printAbstractCodeModel; request.path = fullPath; - bool pathFound = false; - AZStd::string relativePath; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult - ( pathFound - , &AzToolsFramework::AssetSystem::AssetSystemRequest::GetRelativeProductPathFromFullSourceOrProductPath - , fullPath.c_str(), relativePath); - - if (!pathFound) - { - AZ::Failure(AZStd::string::format("Failed to get engine relative path from %s", fullPath.c_str())); - } - - request.namespacePath = relativePath; const ScriptCanvas::Translation::Result translationResult = TranslateToLua(request); auto isSuccessOutcome = translationResult.IsSuccess(ScriptCanvas::Translation::TargetFlags::Lua); diff --git a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl index b1bc7321e6..74d0f76dce 100644 --- a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl +++ b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl @@ -114,12 +114,17 @@ namespace ScriptCanvasEditor { if (auto loadFileOutcome = LoadFromFile(graphPath); loadFileOutcome.IsSuccess()) { - AZ::Outcome< AZ::Data::Asset, AZStd::string> assetOutcome = AZ::Failure(AZStd::string("asset creation failed")); - ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(assetOutcome, &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateRuntimeAsset, loadFileOutcome.GetValue()); + auto& source = loadFileOutcome.GetValue(); + auto testableSource = SourceHandle(source, AZ::Uuid::CreateRandom(), source.Path().c_str()); + + AZ::Outcome, AZStd::string> assetOutcome(AZ::Failure(AZStd::string("asset create failed"))); + ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(assetOutcome + , &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateRuntimeAsset, testableSource); + if (assetOutcome.IsSuccess()) { LoadTestGraphResult result; - result.m_editorAsset = loadFileOutcome.TakeValue(); + result.m_editorAsset = AZStd::move(testableSource); result.m_runtimeAsset = assetOutcome.GetValue(); result.m_entity = AZStd::make_unique("Loaded Graph"); return result; @@ -216,6 +221,8 @@ namespace ScriptCanvasEditor { RuntimeDataOverrides runtimeDataOverrides; runtimeDataOverrides.m_runtimeAsset = loadResult.m_runtimeAsset; + runtimeDataOverrides.m_runtimeAsset.SetHint("original"); + runtimeDataOverrides.m_runtimeAsset.Get()->m_runtimeData.m_script.SetHint("original"); #if defined(LINUX) ////////////////////////////////////////////////////////////////////////// // Temporarily disable testing on the Linux build until the file name casing discrepancy @@ -261,6 +268,10 @@ namespace ScriptCanvasEditor RuntimeDataOverrides dependencyRuntimeDataOverrides; dependencyRuntimeDataOverrides.m_runtimeAsset = dependency.runtimeAsset; + AZStd::string dependencyHint = AZStd::string::format("dependency_%d", index); + dependencyRuntimeDataOverrides.m_runtimeAsset.SetHint(dependencyHint); + dependencyRuntimeDataOverrides.m_runtimeAsset.Get()->m_runtimeData.m_script.SetHint(dependencyHint); + runtimeDataOverrides.m_dependencies.push_back(dependencyRuntimeDataOverrides); RuntimeData& dependencyData = dependencyDataBuffer[index]; diff --git a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasTraceUtilities.h b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasTraceUtilities.h index 033eed3efd..dfcb0d2643 100644 --- a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasTraceUtilities.h +++ b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasTraceUtilities.h @@ -161,15 +161,15 @@ namespace ScriptCanvasEditor struct ScopedOutputSuppression { - ScopedOutputSuppression(bool suppressState = true) + ScopedOutputSuppression([[maybe_unused]] bool suppressState = true) { - AZ::Debug::TraceMessageBus::BroadcastResult(m_oldSuppression, &AZ::Debug::TraceMessageEvents::OnOutput, "", ""); - TraceSuppressionBus::Broadcast(&TraceSuppressionRequests::SuppressAllOutput, suppressState); + // AZ::Debug::TraceMessageBus::BroadcastResult(m_oldSuppression, &AZ::Debug::TraceMessageEvents::OnOutput, "", ""); + // TraceSuppressionBus::Broadcast(&TraceSuppressionRequests::SuppressAllOutput, suppressState); } ~ScopedOutputSuppression() { - TraceSuppressionBus::Broadcast(&TraceSuppressionRequests::SuppressAllOutput, m_oldSuppression); + // TraceSuppressionBus::Broadcast(&TraceSuppressionRequests::SuppressAllOutput, m_oldSuppression); } private: bool m_oldSuppression = false; diff --git a/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp b/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp index 3566d8da4b..88ef93a4c4 100644 --- a/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp @@ -120,7 +120,10 @@ namespace ScriptCanvasEditor PopulateEditorCreatableTypes(); AzToolsFramework::RegisterGenericComboBoxHandler(); - AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Broadcast(&AzToolsFramework::PropertyTypeRegistrationMessages::RegisterPropertyType, aznew SourceHandlePropertyHandler()); + if (AzToolsFramework::PropertyTypeRegistrationMessages::Bus::FindFirstHandler()) + { + AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Broadcast(&AzToolsFramework::PropertyTypeRegistrationMessages::RegisterPropertyType, aznew SourceHandlePropertyHandler()); + } SystemRequestBus::Handler::BusConnect(); ScriptCanvasExecutionBus::Handler::BusConnect(); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp index 093f87e1f7..023d46097d 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp @@ -22,12 +22,16 @@ namespace ScriptCanvas Nodeable::Nodeable() : m_noOpFunctor(&NodeableOutCpp::NoOp) - {} + { + AZ_TracePrintf("SCDB", "How many times does this get called? Because it should....NOT GET CALLED!"); + } Nodeable::Nodeable(ExecutionStateWeakPtr executionState) : m_noOpFunctor(&NodeableOutCpp::NoOp) , m_executionState(executionState) - {} + { + AZ_TracePrintf("SCDB", "How many times does this get called 2?"); + } #if !defined(RELEASE) void Nodeable::CallOut(size_t index, AZ::BehaviorValueParameter* resultBVP, AZ::BehaviorValueParameter* argsBVPs, int numArguments) const @@ -80,6 +84,7 @@ namespace ScriptCanvas ->Attribute(AZ::ScriptCanvasAttributes::VariableCreationForbidden, AZ::AttributeIsValid::IfPresent) ->Attribute(AZ::Script::Attributes::UseClassIndexAllowNil, AZ::AttributeIsValid::IfPresent) ->Constructor() + ->Attribute(AZ::Script::Attributes::DefaultConstructorOverrideIndex, 0) ->Method("Deactivate", &Nodeable::Deactivate) ->Method("InitializeExecutionState", &Nodeable::InitializeExecutionState) ->Method("InitializeExecutionOuts", &Nodeable::InitializeExecutionOuts) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp index 4d7c8a2cda..c43214eeea 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp @@ -68,6 +68,8 @@ namespace ExecutionInterpretedAPICpp { if (lua_isstring(lua, -1)) { + AZStd::string errorResult = lua_tostring(lua, -1); + AZ_TracePrintf("ScriptCanvas", errorResult.c_str()); AZ::ScriptContext::FromNativeContext(lua)->Error(AZ::ScriptContext::ErrorType::Error, true, "%s", lua_tostring(lua, -1)); } else @@ -402,6 +404,50 @@ namespace ScriptCanvas AZ_Assert(lua_isuserdata(lua, -2) && !lua_islightuserdata(lua, -2), "Error in compiled lua file, 1st argument to OverrideNodeableMetatable is not userdata (Nodeable)"); AZ_Assert(lua_istable(lua, -1), "Error in compiled lua file, 2nd argument to OverrideNodeableMetatable is not a Lua table"); + /* table is in the stack at index 't' */ + if (lua_istable(lua, -1)) + { + lua_getfield(lua, -1, "__index"); + + if (lua_istable(lua, -1)) + { + int t = -2; + AZStd::string tableGuts; + lua_pushnil(lua); + /* first key */ + while (lua_next(lua, t) != 0) + { + /* uses 'key' (at index -2) and 'value' (at index -1) */ + if (lua_type(lua, -2) == LUA_TSTRING) + { + size_t len; + tableGuts += AZStd::string::format("%s - %s\n", + lua_tolstring(lua, -2, &len), + lua_typename(lua, lua_type(lua, -1))); + } + else if (lua_type(lua, -2) == LUA_TNUMBER) + { + tableGuts += AZStd::string::format("%f - %s\n", + lua_tonumber(lua, -2), + lua_typename(lua, lua_type(lua, -1))); + } + else + { + tableGuts += AZStd::string::format("%s - %s\n", + lua_typename(lua, lua_type(lua, -2)), + lua_typename(lua, lua_type(lua, -1))); + } + + /* removes 'value'; keeps 'key' for next iteration */ + lua_pop(lua, 1); + } + + AZ_TracePrintf("SCDB", tableGuts.c_str()); + } + + lua_pop(lua, 1); + } + [[maybe_unused]] auto userData = reinterpret_cast(lua_touserdata(lua, -2)); AZ_Assert(userData && userData->magicData == AZ_CRC_CE("AZLuaUserData"), "this isn't user data"); // Lua: LuaUserData::nodeable, class_mt diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpreted.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpreted.cpp index 9224d4f9a4..05c5d6f857 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpreted.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpreted.cpp @@ -126,6 +126,8 @@ namespace ScriptCanvas AZ_Assert(m_luaRegistryIndex == LUA_NOREF, "ExecutionStateInterpreted already in the Lua registry and risks double deletion"); // Lua: instance m_luaRegistryIndex = luaL_ref(m_luaState, LUA_REGISTRYINDEX); + AZ_Assert(m_luaRegistryIndex != LUA_REFNIL, "ExecutionStateInterpreted was nil when trying to gain a reference"); + AZ_Assert(m_luaRegistryIndex != LUA_NOREF, "ExecutionStateInterpreted failed to gain a reference"); } void ExecutionStateInterpreted::Reflect(AZ::ReflectContext* reflectContext) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpretedPerActivation.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpretedPerActivation.cpp index 44b1364682..7ef1e22fbf 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpretedPerActivation.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpretedPerActivation.cpp @@ -111,10 +111,72 @@ namespace ScriptCanvas auto& lua = m_luaState; // Lua: lua_rawgeti(lua, LUA_REGISTRYINDEX, registryIndex); + if (!lua_isuserdata(lua, -1)) + { + AZ_TracePrintf("SCDB", "No light userdata"); + } + // Lua: instance + + lua_getmetatable(lua, -1); + if (!lua_istable(lua, -1)) + { + AZ_TracePrintf("SCDB", "no metatable"); + } + + + /* table is in the stack at index 't' */ + if (lua_istable(lua, -1)) + { + int t = -2; + AZStd::string tableGuts; + lua_pushnil(lua); + /* first key */ + while (lua_next(lua, t) != 0) + { + /* uses 'key' (at index -2) and 'value' (at index -1) */ + if (lua_type(lua, -2) == LUA_TSTRING) + { + size_t len; + tableGuts += AZStd::string::format("%s - %s\n", + lua_tolstring(lua, -2, &len), + lua_typename(lua, lua_type(lua, -1))); + } + else if (lua_type(lua, -2) == LUA_TNUMBER) + { + tableGuts += AZStd::string::format("%f - %s\n", + lua_tonumber(lua, -2), + lua_typename(lua, lua_type(lua, -1))); + } + else + { + tableGuts += AZStd::string::format("%s - %s\n", + lua_typename(lua, lua_type(lua, -2)), + lua_typename(lua, lua_type(lua, -1))); + } + + /* removes 'value'; keeps 'key' for next iteration */ + lua_pop(lua, 1); + } + + AZ_TracePrintf("SCDB", tableGuts.c_str()); + } + + // Lua: instance, instance_mt + lua_pop (lua, 1); + + // Lua: instance lua_getfield(lua, -1, Grammar::k_OnGraphStartFunctionName); // Lua: instance, graph_VM.k_OnGraphStartFunctionName + if (!lua_isfunction(lua, -1)) + { + AZ_TracePrintf("SCDB", "No function"); + } lua_pushvalue(lua, -2); + if (!lua_isuserdata(lua, -1)) + { + AZ_TracePrintf("SCDB", "No light userdata"); + } // Lua: instance, graph_VM.k_OnGraphStartFunctionName, instance const int result = Execution::InterpretedSafeCall(lua, 1, 0); // Lua: instance ? From e2dc1ed17bca318bcb36045ceec9d7a947caab81 Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Wed, 24 Nov 2021 17:22:35 +0000 Subject: [PATCH 042/128] review changes Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- .../TerrainSystem_VegetationSpawnsOnTerrainSurfaces.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainSystem_VegetationSpawnsOnTerrainSurfaces.py b/AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainSystem_VegetationSpawnsOnTerrainSurfaces.py index 694535f20d..f1769ae3d9 100644 --- a/AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainSystem_VegetationSpawnsOnTerrainSurfaces.py +++ b/AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainSystem_VegetationSpawnsOnTerrainSurfaces.py @@ -148,7 +148,10 @@ def TerrainSystem_VegetationSpawnsOnTerrainSurfaces(): general.set_current_view_position(17.0, -66.0, 41.0) general.set_current_view_rotation(-15, 0, 0) - # Expected item counts under conditions to be tested + # Expected item counts under conditions to be tested. + # By default, vegetation spawns at a density of 20 items per 16 meters, + # so in a 20m square, there should be around 25 ^ 2 items depending on whether area edges are included. + # In this case there are 26 ^ 2 items. expected_surface_tag_excluded_item_count = 338 expected_no_exclusions_item_count = 676 @@ -172,7 +175,7 @@ def TerrainSystem_VegetationSpawnsOnTerrainSurfaces(): terrain_entity_1.get_set_test(3, "Configuration|Gradient to Surface Mappings|[0]|Surface Tag", surface_data.SurfaceTag("test_tag2")) terrain_entity_2.get_set_test(3, "Configuration|Gradient to Surface Mappings|[0]|Surface Tag", surface_data.SurfaceTag("test_tag3")) - # Give the VegetationSurfaceFilter an exclusion list, set it to excude test_tag2 which should remove all the lower items which are in terrain_entity_1. + # Give the VegetationSurfaceFilter an exclusion list, set it to exclude test_tag2 which should remove all the lower items which are in terrain_entity_1. vegetation_entity.get_set_test(3, "Configuration|Exclusion|Surface Tags", [surface_data.SurfaceTag()]) vegetation_entity.get_set_test(3, "Configuration|Exclusion|Surface Tags|[0]", surface_data.SurfaceTag("test_tag2")) From ddd8dc65688732ac4a05540601abe4dd39c49e23 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Wed, 24 Nov 2021 15:49:34 -0800 Subject: [PATCH 043/128] remove the optimized GPU test file and replace the existing GPU test file with the optimized tests, update atom_constants.py for the new Light component properties, add area light test script, still need to add spot light test script to fully finish this task Signed-off-by: jromnoa <80134229+jromnoa@users.noreply.github.com> --- .../PythonTests/Atom/TestSuite_Main_GPU.py | 142 ++++----- .../Atom/TestSuite_Main_GPU_Optimized.py | 81 ----- .../Atom/atom_utils/atom_component_helper.py | 280 ++++++++---------- .../Atom/atom_utils/atom_constants.py | 3 + .../hydra_AtomGPU_AreaLightScreenshotTest.py | 217 ++++++++++++++ .../tests/hydra_AtomGPU_BasicLevelSetup.py | 23 +- ..._AtomGPU_LightComponentScreenshotsMatch.py | 0 .../hydra_AtomGPU_SpotLightScreenshotTest.py | 71 +++++ 8 files changed, 485 insertions(+), 332 deletions(-) delete mode 100644 AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU_Optimized.py create mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_AreaLightScreenshotTest.py delete mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_LightComponentScreenshotsMatch.py create mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py index a9b49b8107..14d850245c 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py @@ -4,83 +4,82 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ - import logging import os import pytest +import editor_python_test_tools.hydra_test_utils as hydra import ly_test_tools.environment.file_system as file_system from ly_test_tools.benchmark.data_aggregator import BenchmarkDataAggregator +from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite +from Atom.atom_utils.atom_component_helper import compare_screenshot_to_golden_image, golden_images_directory -import editor_python_test_tools.hydra_test_utils as hydra -from .atom_utils.atom_component_helper import compare_screenshot_similarity, ImageComparisonTestFailure - -logger = logging.getLogger(__name__) DEFAULT_SUBFOLDER_PATH = 'user/PythonTests/Automated/Screenshots' -TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests") +logger = logging.getLogger(__name__) @pytest.mark.parametrize("project", ["AutomatedTesting"]) -@pytest.mark.parametrize("launcher_platform", ["windows_editor"]) -@pytest.mark.parametrize("level", ["Base"]) -class TestAllComponentsIndepthTests(object): +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +class TestAutomation(EditorTestSuite): + # Remove -autotest_mode from global_extra_cmdline_args since we need rendering for these tests. + global_extra_cmdline_args = ["-BatchMode"] # Default is ["-BatchMode", "-autotest_mode"] + + enable_prefab_system = False - @pytest.mark.parametrize("screenshot_name", ["AtomBasicLevelSetup.ppm"]) @pytest.mark.test_case_id("C34603773") - def test_BasicLevelSetup_SetsUpLevel( - self, request, editor, workspace, project, launcher_platform, level, screenshot_name): - """ - Please review the hydra script run by this test for more specific test info. - Tests that a basic rendering level setup can be created (lighting, meshes, materials, etc.). - """ + class AtomGPU_BasicLevelSetup_SetsUpLevel(EditorSharedTest): + use_null_renderer = False # Default is True + screenshot_name = "AtomBasicLevelSetup.ppm" + test_screenshots = [] # Gets set by setup() + screenshot_directory = "" # Gets set by setup() + # Clear existing test screenshots before starting test. - screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH) - test_screenshots = [os.path.join(screenshot_directory, screenshot_name)] - file_system.delete(test_screenshots, True, True) + def setup(self, workspace): + screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH) + test_screenshots = [os.path.join(screenshot_directory, self.screenshot_name)] + file_system.delete(test_screenshots, True, True) golden_images = [os.path.join(golden_images_directory(), screenshot_name)] - level_creation_expected_lines = [ - "Viewport is set to the expected size: True", - "Exited game mode" - ] - unexpected_lines = ["Traceback (most recent call last):"] + from Atom.tests import hydra_AtomGPU_BasicLevelSetup as test_module - hydra.launch_and_validate_results( - request, - TEST_DIRECTORY, - editor, - "hydra_GPUTest_BasicLevelSetup.py", - timeout=180, - expected_lines=level_creation_expected_lines, - unexpected_lines=unexpected_lines, - halt_on_unexpected=True, - cfg_args=[level], - null_renderer=False, - enable_prefab_system=False, - ) - - similarity_threshold = 0.99 - for test_screenshot, golden_image in zip(test_screenshots, golden_images): - screenshot_comparison_result = compare_screenshot_similarity( - test_screenshot, golden_image, similarity_threshold, True, screenshot_directory) - if screenshot_comparison_result != "Screenshots match": - raise Exception(f"Screenshot test failed: {screenshot_comparison_result}") + assert compare_screenshot_to_golden_image(screenshot_directory, test_screenshots, golden_images, 0.99) is True @pytest.mark.test_case_id("C34525095") - def test_LightComponent_ScreenshotMatchesGoldenImage( - self, request, editor, workspace, project, launcher_platform, level): - """ - Please review the hydra script run by this test for more specific test info. - Tests that the Light component screenshots in a rendered level appear the same as the golden images. - """ + class AtomGPU_LightComponent_AreaLightScreenshotsMatchGoldenImages(EditorSharedTest): + use_null_renderer = False # Default is True screenshot_names = [ "AreaLight_1.ppm", "AreaLight_2.ppm", "AreaLight_3.ppm", "AreaLight_4.ppm", "AreaLight_5.ppm", + ] + test_screenshots = [] # Gets set by setup() + screenshot_directory = "" # Gets set by setup() + + # Clear existing test screenshots before starting test. + def setup(self, workspace): + screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH) + for screenshot in self.screenshot_names: + screenshot_path = os.path.join(screenshot_directory, screenshot) + self.test_screenshots.append(screenshot_path) + file_system.delete(self.test_screenshots, True, True) + + golden_images = [] + for golden_image in screenshot_names: + golden_image_path = os.path.join(golden_images_directory(), golden_image) + golden_images.append(golden_image_path) + + from Atom.tests import hydra_AtomGPU_AreaLightScreenshotTest as test_module + + assert compare_screenshot_to_golden_image(screenshot_directory, test_screenshots, golden_images, 0.99) is True + + @pytest.mark.test_case_id("C34525110") + class AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages(EditorSharedTest): + use_null_renderer = False # Default is True + screenshot_names = [ "SpotLight_1.ppm", "SpotLight_2.ppm", "SpotLight_3.ppm", @@ -88,40 +87,25 @@ class TestAllComponentsIndepthTests(object): "SpotLight_5.ppm", "SpotLight_6.ppm", ] - screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH) - test_screenshots = [] - for screenshot in screenshot_names: - screenshot_path = os.path.join(screenshot_directory, screenshot) - test_screenshots.append(screenshot_path) - file_system.delete(test_screenshots, True, True) + test_screenshots = [] # Gets set by setup() + screenshot_directory = "" # Gets set by setup() + + # Clear existing test screenshots before starting test. + def setup(self, workspace): + screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH) + for screenshot in self.screenshot_names: + screenshot_path = os.path.join(screenshot_directory, screenshot) + self.test_screenshots.append(screenshot_path) + file_system.delete(self.test_screenshots, True, True) golden_images = [] for golden_image in screenshot_names: golden_image_path = os.path.join(golden_images_directory(), golden_image) golden_images.append(golden_image_path) - expected_lines = ["spot_light Controller|Configuration|Shadows|Shadowmap size: SUCCESS"] - unexpected_lines = ["Traceback (most recent call last):"] - hydra.launch_and_validate_results( - request, - TEST_DIRECTORY, - editor, - "hydra_GPUTest_LightComponent.py", - timeout=180, - expected_lines=expected_lines, - unexpected_lines=unexpected_lines, - halt_on_unexpected=True, - cfg_args=[level], - null_renderer=False, - enable_prefab_system=False, - ) + from Atom.tests import hydra_AtomGPU_SpotLightScreenshotTest as test_module - similarity_threshold = 0.99 - for test_screenshot, golden_image in zip(test_screenshots, golden_images): - screenshot_comparison_result = compare_screenshot_similarity( - test_screenshot, golden_image, similarity_threshold, True, screenshot_directory) - if screenshot_comparison_result != "Screenshots match": - raise ImageComparisonTestFailure(f"Screenshot test failed: {screenshot_comparison_result}") + assert compare_screenshot_to_golden_image(screenshot_directory, test_screenshots, golden_images, 0.99) is True @pytest.mark.parametrize('rhi', ['dx12', 'vulkan']) @@ -152,7 +136,7 @@ class TestPerformanceBenchmarkSuite(object): hydra.launch_and_validate_results( request, - TEST_DIRECTORY, + os.path.join(os.path.dirname(__file__), "tests"), editor, "hydra_GPUTest_AtomFeatureIntegrationBenchmark.py", timeout=600, @@ -189,7 +173,7 @@ class TestMaterialEditor(object): hydra.launch_and_validate_results( request, - TEST_DIRECTORY, + os.path.join(os.path.dirname(__file__), "tests"), generic_launcher, editor_script="", run_python="--runpython", diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU_Optimized.py deleted file mode 100644 index afd181b849..0000000000 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU_Optimized.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -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 -""" -import os - -import pytest - -import ly_test_tools.environment.file_system as file_system -from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite -from ly_test_tools.image.screenshot_compare_qssim import qssim as compare_screenshots -from .atom_utils.atom_component_helper import ( - create_screenshots_archive, compare_screenshot_to_golden_image, golden_images_directory) - -DEFAULT_SUBFOLDER_PATH = 'user/PythonTests/Automated/Screenshots' - - -@pytest.mark.parametrize("project", ["AutomatedTesting"]) -@pytest.mark.parametrize("launcher_platform", ['windows_editor']) -class TestAutomation(EditorTestSuite): - # Remove -autotest_mode from global_extra_cmdline_args since we need rendering for these tests. - global_extra_cmdline_args = ["-BatchMode"] # Default is ["-BatchMode", "-autotest_mode"] - - enable_prefab_system = False - - @pytest.mark.test_case_id("C34603773") - class AtomGPU_BasicLevelSetup_SetsUpLevel(EditorSharedTest): - use_null_renderer = False # Default is True - screenshot_name = "AtomBasicLevelSetup.ppm" - test_screenshots = [] # Gets set by setup() - screenshot_directory = "" # Gets set by setup() - - # Clear existing test screenshots before starting test. - def setup(self, workspace): - screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH) - test_screenshots = [os.path.join(screenshot_directory, self.screenshot_name)] - file_system.delete(test_screenshots, True, True) - - golden_images = [os.path.join(golden_images_directory(), screenshot_name)] - - from Atom.tests import hydra_AtomGPU_BasicLevelSetup as test_module - - assert compare_screenshot_to_golden_image(screenshot_directory, test_screenshots, golden_images, 0.99) is True - - @pytest.mark.test_case_id("C34525095") - class AtomGPU_LightComponent_ScreenshotMatchesGoldenImage(EditorSharedTest): - use_null_renderer = False # Default is True - screenshot_names = [ - "AreaLight_1.ppm", - "AreaLight_2.ppm", - "AreaLight_3.ppm", - "AreaLight_4.ppm", - "AreaLight_5.ppm", - "SpotLight_1.ppm", - "SpotLight_2.ppm", - "SpotLight_3.ppm", - "SpotLight_4.ppm", - "SpotLight_5.ppm", - "SpotLight_6.ppm", - ] - test_screenshots = [] # Gets set by setup() - screenshot_directory = "" # Gets set by setup() - - # Clear existing test screenshots before starting test. - def setup(self, workspace): - screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH) - for screenshot in self.screenshot_names: - screenshot_path = os.path.join(screenshot_directory, screenshot) - self.test_screenshots.append(screenshot_path) - file_system.delete(self.test_screenshots, True, True) - - golden_images = [] - for golden_image in screenshot_names: - golden_image_path = os.path.join(golden_images_directory(), golden_image) - golden_images.append(golden_image_path) - - from Atom.tests import hydra_AtomGPU_LightComponentScreenshotsMatch as test_module - - assert compare_screenshot_to_golden_image(screenshot_directory, test_screenshots, golden_images, 0.99) is True diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py index 28ae72c2b3..6212ba4314 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py @@ -111,161 +111,125 @@ def compare_screenshot_to_golden_image( return True -# def create_basic_atom_level(level_name): -# """ -# Creates a new level inside the Editor matching level_name & adds the following: -# 1. "default_level" entity to hold all other entities. -# 2. Adds Grid, Global Skylight (IBL), ground Mesh, Directional Light, Sphere w/ material+mesh, & Camera components. -# 3. Each of these components has its settings tweaked slightly to match the ideal scene to test Atom rendering. -# :param level_name: name of the level to create and apply this basic setup to. -# :return: None -# """ -# import azlmbr.asset as asset -# import azlmbr.bus as bus -# import azlmbr.camera as camera -# import azlmbr.editor as editor -# import azlmbr.entity as entity -# import azlmbr.legacy.general as general -# import azlmbr.math as math -# import azlmbr.object -# -# import editor_python_test_tools.hydra_editor_utils as hydra -# from editor_python_test_tools.editor_test_helper import EditorTestHelper -# -# helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper") -# -# # Wait for Editor idle loop before executing Python hydra scripts. -# general.idle_enable(True) -# -# # Basic setup for opened level. -# helper.open_level(level_name="Base") -# general.idle_wait(1.0) -# general.update_viewport() -# general.idle_wait(0.5) # half a second is more than enough for updating the viewport. -# -# # Close out problematic windows, FPS meters, and anti-aliasing. -# if general.is_helpers_shown(): # Turn off the helper gizmos if visible -# general.toggle_helpers() -# general.idle_wait(1.0) -# if general.is_pane_visible("Error Report"): # Close Error Report windows that block focus. -# general.close_pane("Error Report") -# if general.is_pane_visible("Error Log"): # Close Error Log windows that block focus. -# general.close_pane("Error Log") -# general.idle_wait(1.0) -# general.run_console("r_displayInfo=0") -# general.idle_wait(1.0) -# -# # Delete all existing entities & create default_level entity -# search_filter = azlmbr.entity.SearchFilter() -# all_entities = entity.SearchBus(azlmbr.bus.Broadcast, "SearchEntities", search_filter) -# editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", all_entities) -# default_level = hydra.Entity("default_level") -# default_position = math.Vector3(0.0, 0.0, 0.0) -# default_level.create_entity(default_position, ["Grid"]) -# default_level.get_set_test(0, "Controller|Configuration|Secondary Grid Spacing", 1.0) -# -# # Set the viewport up correctly after adding the parent default_level entity. -# screen_width = 1280 -# screen_height = 720 -# degree_radian_factor = 0.0174533 # Used by "Rotation" property for the Transform component. -# general.set_viewport_size(screen_width, screen_height) -# general.update_viewport() -# helper.wait_for_condition( -# function=lambda: helper.isclose(a=general.get_viewport_size().x, b=screen_width, rel_tol=0.1) -# and helper.isclose(a=general.get_viewport_size().y, b=screen_height, rel_tol=0.1), -# timeout_in_seconds=4.0 -# ) -# result = helper.isclose(a=general.get_viewport_size().x, b=screen_width, rel_tol=0.1) and helper.isclose( -# a=general.get_viewport_size().y, b=screen_height, rel_tol=0.1) -# general.log(general.get_viewport_size().x) -# general.log(general.get_viewport_size().y) -# general.log(general.get_viewport_size().z) -# general.log(f"Viewport is set to the expected size: {result}") -# general.log("Basic level created") -# general.run_console("r_DisplayInfo = 0") -# -# # Create global_skylight entity and set the properties -# global_skylight = hydra.Entity("global_skylight") -# global_skylight.create_entity( -# entity_position=default_position, -# components=["HDRi Skybox", "Global Skylight (IBL)"], -# parent_id=default_level.id) -# global_skylight_asset_path = os.path.join("LightingPresets", "default_iblskyboxcm.exr.streamingimage") -# global_skylight_asset_value = asset.AssetCatalogRequestBus( -# bus.Broadcast, "GetAssetIdByPath", global_skylight_asset_path, math.Uuid(), False) -# global_skylight.get_set_test(0, "Controller|Configuration|Cubemap Texture", global_skylight_asset_value) -# global_skylight.get_set_test(1, "Controller|Configuration|Diffuse Image", global_skylight_asset_value) -# global_skylight.get_set_test(1, "Controller|Configuration|Specular Image", global_skylight_asset_value) -# -# # Create ground_plane entity and set the properties -# ground_plane = hydra.Entity("ground_plane") -# ground_plane.create_entity( -# entity_position=default_position, -# components=["Material"], -# parent_id=default_level.id) -# azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalUniformScale", ground_plane.id, 32.0) -# -# # Work around to add the correct Atom Mesh component and asset. -# mesh_type_id = azlmbr.globals.property.EditorMeshComponentTypeId -# ground_plane.components.append( -# editor.EditorComponentAPIBus( -# bus.Broadcast, "AddComponentsOfType", ground_plane.id, [mesh_type_id] -# ).GetValue()[0] -# ) -# ground_plane_mesh_asset_path = os.path.join("TestData", "Objects", "plane.azmodel") -# ground_plane_mesh_asset_value = asset.AssetCatalogRequestBus( -# bus.Broadcast, "GetAssetIdByPath", ground_plane_mesh_asset_path, math.Uuid(), False) -# ground_plane.get_set_test(1, "Controller|Configuration|Mesh Asset", ground_plane_mesh_asset_value) -# -# # Add Atom Material component and asset. -# ground_plane_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_chrome.azmaterial") -# ground_plane_material_asset_value = asset.AssetCatalogRequestBus( -# bus.Broadcast, "GetAssetIdByPath", ground_plane_material_asset_path, math.Uuid(), False) -# ground_plane.get_set_test(0, "Default Material|Material Asset", ground_plane_material_asset_value) -# -# # Create directional_light entity and set the properties -# directional_light = hydra.Entity("directional_light") -# directional_light.create_entity( -# entity_position=math.Vector3(0.0, 0.0, 10.0), -# components=["Directional Light"], -# parent_id=default_level.id) -# directional_light_rotation = math.Vector3(degree_radian_factor * -90.0, 0.0, 0.0) -# azlmbr.components.TransformBus( -# azlmbr.bus.Event, "SetLocalRotation", directional_light.id, directional_light_rotation) -# -# # Create sphere entity and set the properties -# sphere_entity = hydra.Entity("sphere") -# sphere_entity.create_entity( -# entity_position=math.Vector3(0.0, 0.0, 1.0), -# components=["Material"], -# parent_id=default_level.id) -# -# # Work around to add the correct Atom Mesh component and asset. -# sphere_entity.components.append( -# editor.EditorComponentAPIBus( -# bus.Broadcast, "AddComponentsOfType", sphere_entity.id, [mesh_type_id] -# ).GetValue()[0] -# ) -# sphere_mesh_asset_path = os.path.join("Models", "sphere.azmodel") -# sphere_mesh_asset_value = asset.AssetCatalogRequestBus( -# bus.Broadcast, "GetAssetIdByPath", sphere_mesh_asset_path, math.Uuid(), False) -# sphere_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", sphere_mesh_asset_value) -# -# # Add Atom Material component and asset. -# sphere_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_brass_polished.azmaterial") -# sphere_material_asset_value = asset.AssetCatalogRequestBus( -# bus.Broadcast, "GetAssetIdByPath", sphere_material_asset_path, math.Uuid(), False) -# sphere_entity.get_set_test(0, "Default Material|Material Asset", sphere_material_asset_value) -# -# # Create camera component and set the properties -# camera_entity = hydra.Entity("camera") -# camera_entity.create_entity( -# entity_position=math.Vector3(5.5, -12.0, 9.0), -# components=["Camera"], -# parent_id=default_level.id) -# rotation = math.Vector3( -# degree_radian_factor * -27.0, degree_radian_factor * -12.0, degree_radian_factor * 25.0 -# ) -# azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", camera_entity.id, rotation) -# camera_entity.get_set_test(0, "Controller|Configuration|Field of view", 60.0) -# camera.EditorCameraViewRequestBus(azlmbr.bus.Event, "ToggleCameraAsActiveView", camera_entity.id) + +def initial_viewport_setup(screen_width=1280, screen_height=720): + """ + For setting up the initial viewport resolution to expected default values before running a screenshot test. + Defaults to 1280 x 720 resolution (in pixels). + :param screen_width: Width in pixels to set the viewport width size to. + :param screen_height: Height in pixels to set the viewport height size to. + :return: None + """ + import azlmbr.legacy.general as general + + general.set_viewport_size(screen_width, screen_height) + general.update_viewport() + + +def create_basic_atom_rendering_scene(): + """ + Sets up a new scene inside the Editor for testing Atom rendering GPU output. + Setup: Deletes all existing entities before creating the scene. + The created scene includes: + 1. "Default Level" entity that holds all of the other entities. + 2. "Grid" entity: Contains a Grid component. + 3. "Global Skylight (IBL)" entity: Contains HDRI Skybox & Global Skylight (IBL) components. + 4. "Ground Plane" entity: Contains Material & Mesh components. + 5. "Directional Light" entity: Contains Directional Light component. + 6. "Sphere" entity: Contains Material & Mesh components. + 7. "Camera" entity: Contains Camera component. + :return: None + """ + import azlmbr.math as math + import azlmbr.paths + + from editor_python_test_tools.asset_utils import Asset + from editor_python_test_tools.editor_entity_utils import EditorEntity + + from Atom.atom_utils.atom_constants import AtomComponentProperties + + DEGREE_RADIAN_FACTOR = 0.0174533 + + # Setup: Deletes all existing entities before creating the scene. + search_filter = azlmbr.entity.SearchFilter() + all_entities = azlmbr.entity.SearchBus(azlmbr.bus.Broadcast, "SearchEntities", search_filter) + azlmbr.editor.ToolsApplicationRequestBus(azlmbr.bus.Broadcast, "DeleteEntities", all_entities) + + # 1. "Default Level" entity that holds all of the other entities. + default_level_entity_name = "Default Level" + default_level_entity = EditorEntity.create_editor_entity_at(math.Vector3(0.0, 0.0, 0.0), default_level_entity_name) + + # 2. "Grid" entity: Contains a Grid component. + grid_entity = EditorEntity.create_editor_entity(AtomComponentProperties.grid(), default_level_entity.id) + grid_component = grid_entity.add_component(AtomComponentProperties.grid()) + secondary_grid_spacing_value = 1.0 + grid_component.set_component_property_value( + AtomComponentProperties.grid('Secondary Grid Spacing'), secondary_grid_spacing_value) + + # 3. "Global Skylight (IBL)" entity: Contains HDRI Skybox & Global Skylight (IBL) components. + global_skylight_entity = EditorEntity.create_editor_entity( + AtomComponentProperties.global_skylight(), default_level_entity.id) + hdri_skybox_component = global_skylight_entity.add_component(AtomComponentProperties.hdri_skybox()) + global_skylight_component = global_skylight_entity.add_component(AtomComponentProperties.global_skylight()) + global_skylight_image_asset_path = os.path.join("LightingPresets", "default_iblskyboxcm.exr.streamingimage") + global_skylight_image_asset = Asset.find_asset_by_path(global_skylight_image_asset_path, False) + hdri_skybox_component.set_component_property_value( + AtomComponentProperties.hdri_skybox('Cubemap Texture'), global_skylight_image_asset.id) + global_skylight_diffuse_image_asset_path = os.path.join( + "LightingPresets", "default_iblskyboxcm_ibldiffuse.exr.streamingimage") + global_skylight_diffuse_image_asset = Asset.find_asset_by_path(global_skylight_diffuse_image_asset_path, False) + global_skylight_component.set_component_property_value( + AtomComponentProperties.global_skylight('Diffuse Image'), global_skylight_diffuse_image_asset.id) + global_skylight_specular_image_asset_path = os.path.join( + "LightingPresets", "default_iblskyboxcm_iblspecular.exr.streamingimage") + global_skylight_specular_image_asset = Asset.find_asset_by_path( + global_skylight_specular_image_asset_path, False) + global_skylight_component.set_component_property_value( + AtomComponentProperties.global_skylight('Specular Image'), global_skylight_specular_image_asset.id) + + # 4. "Ground Plane" entity: Contains Material & Mesh components. + ground_plane_name = "Ground Plane" + ground_plane_entity = EditorEntity.create_editor_entity(ground_plane_name, default_level_entity.id) + ground_plane_material_component = ground_plane_entity.add_component(AtomComponentProperties.material()) + ground_plane_entity.set_local_uniform_scale(32.0) + ground_plane_mesh_component = ground_plane_entity.add_component(AtomComponentProperties.mesh()) + ground_plane_mesh_asset_path = os.path.join("TestData", "Objects", "plane.azmodel") + ground_plane_mesh_asset = Asset.find_asset_by_path(ground_plane_mesh_asset_path, False) + ground_plane_mesh_component.set_component_property_value( + AtomComponentProperties.mesh('Mesh Asset'), ground_plane_mesh_asset.id) + ground_plane_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_chrome.azmaterial") + ground_plane_material_asset = Asset.find_asset_by_path(ground_plane_material_asset_path, False) + ground_plane_material_component.set_component_property_value( + AtomComponentProperties.material('Material Asset'), ground_plane_material_asset.id) + + # 5. "Directional Light" entity: Contains Directional Light component. + directional_light_entity = EditorEntity.create_editor_entity_at( + math.Vector3(0.0, 0.0, 10.0), AtomComponentProperties.directional_light(), default_level_entity.id) + directional_light_entity.add_component(AtomComponentProperties.directional_light()) + directional_light_entity_rotation = math.Vector3(DEGREE_RADIAN_FACTOR * -90.0, 0.0, 0.0) + directional_light_entity.set_local_rotation(directional_light_entity_rotation) + + # 6. "Sphere" entity: Contains Material & Mesh components. + sphere_entity = EditorEntity.create_editor_entity_at( + math.Vector3(0.0, 0.0, 1.0), "Sphere", default_level_entity.id) + sphere_mesh_component = sphere_entity.add_component(AtomComponentProperties.mesh()) + sphere_mesh_asset_path = os.path.join("Models", "sphere.azmodel") + sphere_mesh_asset = Asset.find_asset_by_path(sphere_mesh_asset_path, False) + sphere_mesh_component.set_component_property_value( + AtomComponentProperties.mesh('Mesh Asset'), sphere_mesh_asset.id) + sphere_material_component = sphere_entity.add_component(AtomComponentProperties.material()) + sphere_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_brass_polished.azmaterial") + sphere_material_asset = Asset.find_asset_by_path(sphere_material_asset_path, False) + sphere_material_component.set_component_property_value( + AtomComponentProperties.material('Material Asset'), sphere_material_asset.id) + + # 7. "Camera" entity: Contains Camera component. + camera_entity = EditorEntity.create_editor_entity_at( + math.Vector3(5.5, -12.0, 9.0), AtomComponentProperties.camera(), default_level_entity.id) + camera_component = camera_entity.add_component(AtomComponentProperties.camera()) + camera_entity_rotation = math.Vector3( + DEGREE_RADIAN_FACTOR * -27.0, DEGREE_RADIAN_FACTOR * -12.0, DEGREE_RADIAN_FACTOR * 25.0) + camera_entity.set_local_rotation(camera_entity_rotation) + camera_fov_value = 60.0 + camera_component.set_component_property_value(AtomComponentProperties.camera('Field of view'), camera_fov_value) + azlmbr.camera.EditorCameraViewRequestBus(azlmbr.bus.Event, "ToggleCameraAsActiveView", camera_entity.id) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py index ef9e90802b..2655a79fde 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py @@ -255,6 +255,9 @@ class AtomComponentProperties: """ properties = { 'name': 'Light', + 'Attenuation Radius Mode': 'Controller|Configuration|Attenuation radius|Mode', + 'Color': 'Controller|Configuration|Color', + 'Intensity': 'Controller|Configuration|Intensity', 'Light type': 'Controller|Configuration|Light type', } return properties[property] diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_AreaLightScreenshotTest.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_AreaLightScreenshotTest.py new file mode 100644 index 0000000000..d9a24c13ec --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_AreaLightScreenshotTest.py @@ -0,0 +1,217 @@ +""" +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 +""" + + +class Tests: + area_light_entity_created = ( + "Area Light entity successfully created", + "Area Light entity failed to be created") + area_light_entity_deleted = ( + "Area Light entity was deleted", + "Area Light entity was not deleted") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + light_component_added = ( + "Light component was added", + "Light component wasn't added") + light_component_attenuation_radius_property_set = ( + "Light component Attenuation Radius Property was set", + "Light component Attenuation Radius Property was not set") + light_component_color_property_set = ( + "Light component Color property was set", + "Light component Color property was not set") + light_component_intensity_property_set = ( + "Light component Intensity property was set", + "Light component Intensity property was not set") + light_component_light_type_property_set = ( + "Light type property was set", + "Light type property was not set") + + +def AtomGPU_LightComponent_AreaLightScreenshotsMatchGoldenImages(): + """ + Summary: + Light component test using the Capsule, Spot (disk), and Point (sphere) Light type property options. + Sets each scene up and then takes a screenshot of each scene for test comparison. + + Test setup: + - Wait for Editor idle loop. + - Open the "Base" level. + - Close error windows and display helpers then update the viewport size. + - Runs the create_basic_atom_rendering_scene() function to setup the test scene. + + Expected Behavior: + The test scripts sets up the scenes correctly and takes accurate screenshots. + + Test Steps: + 1. Create Area Light entity with no components. + 2. Add a Light component to the Area Light entity. + 3. Set the Light type property to Capsule for the Light component. + 4. Set the Light component's Color property to 255, 0, 0. + 5. Enter game mode and take a screenshot then exit game mode. + 6. Set the Intensity property of the Light component to 0.0. + 7. Set the Attenuation Radius Mode property of the Light component to 1 (automatic). + 8. Enter game mode and take a screenshot then exit game mode. + 9. Set the Intensity property of the Light component to 1000.0 + 10. Enter game mode and take a screenshot then exit game mode. + 11. Set the Light type property to Spot (disk) for the Light component & rotate DEGREE_RADIAN_FACTOR * 90 degrees. + 12. Enter game mode and take a screenshot then exit game mode. + 13. Set the Light type property to Point (sphere) instead of Spot (disk) for the Light component. + 14. Enter game mode and take a screenshot then exit game mode. + 15. Delete the Area Light entity. + 16. Look for errors. + + :return: None + """ + + import azlmbr.legacy.general as general + import azlmbr.paths + + from editor_python_test_tools.editor_entity_utils import EditorEntity + from editor_python_test_tools.utils import Report, Tracer, TestHelper + + from Atom.atom_utils.atom_constants import AtomComponentProperties, LIGHT_TYPES + from Atom.atom_utils.atom_component_helper import initial_viewport_setup, create_basic_atom_rendering_scene + from Atom.atom_utils.screenshot_utils import ScreenshotHelper + + DEGREE_RADIAN_FACTOR = 0.0174533 + + with Tracer() as error_tracer: + # Test setup begins. + # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. + TestHelper.init_idle() + TestHelper.open_level("", "Base") + + # Setup: Close error windows and display helpers then update the viewport size. + TestHelper.close_error_windows() + TestHelper.close_display_helpers() + initial_viewport_setup() + general.update_viewport() + + # Setup: Runs the create_basic_atom_rendering_scene() function to setup the test scene. + create_basic_atom_rendering_scene() + + # Test steps begin. + # 1. Create Area Light entity with no components. + area_light_entity_name = "Area Light" + area_light_entity = EditorEntity.create_editor_entity_at( + azlmbr.math.Vector3(0.0, 0.0, 0.0), area_light_entity_name) + Report.critical_result(Tests.area_light_entity_created, area_light_entity.exists()) + + # 2. Add a Light component to the Area Light entity. + light_component = area_light_entity.add_component(AtomComponentProperties.light()) + Report.critical_result( + Tests.light_component_added, area_light_entity.has_component(AtomComponentProperties.light())) + + # 3. Set the Light type property to Capsule for the Light component. + light_component.set_component_property_value( + AtomComponentProperties.light('Light type'), LIGHT_TYPES['capsule']) + Report.result( + Tests.light_component_light_type_property_set, + light_component.get_component_property_value( + AtomComponentProperties.light('Light type')) == LIGHT_TYPES['capsule']) + + # 4. Set the Light component's Color property to 255, 0, 0. + light_component_color_value = azlmbr.math.Color(255.0, 0.0, 0.0, 0.0) + light_component.set_component_property_value( + AtomComponentProperties.light('Color'), light_component_color_value) + Report.result( + Tests.light_component_color_property_set, + light_component.get_component_property_value( + AtomComponentProperties.light('Color')) == light_component_color_value) + + # 5. Enter game mode and take a screenshot then exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) + ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("AreaLight_1.ppm") + TestHelper.exit_game_mode(Tests.exit_game_mode) + TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + + # 6. Set the Intensity property of the Light component to 0.0. + light_component.set_component_property_value(AtomComponentProperties.light('Intensity'), 0.0) + Report.result( + Tests.light_component_intensity_property_set, + light_component.get_component_property_value(AtomComponentProperties.light('Intensity')) == 0.0) + + # 7. Set the Attenuation Radius Mode property of the Light component to 1 (automatic). + light_component.set_component_property_value(AtomComponentProperties.light('Attenuation Radius Mode'), 1) + Report.result( + Tests.light_component_attenuation_radius_property_set, + light_component.get_component_property_value(AtomComponentProperties.light('Attenuation Radius Mode')) == 1) + + # 8. Enter game mode and take a screenshot then exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) + ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("AreaLight_2.ppm") + TestHelper.exit_game_mode(Tests.exit_game_mode) + TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + + # 9. Set the Intensity property of the Light component to 1000.0 + light_component.set_component_property_value(AtomComponentProperties.light('Intensity'), 1000.0) + Report.result( + Tests.light_component_intensity_property_set, + light_component.get_component_property_value(AtomComponentProperties.light('Intensity')) == 1000.0) + + # 10. Enter game mode and take a screenshot then exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) + ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("AreaLight_3.ppm") + TestHelper.exit_game_mode(Tests.exit_game_mode) + TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + + # 11. Set the Light type property to Spot (disk) for the Light component & + # rotate DEGREE_RADIAN_FACTOR * 90 degrees. + light_component.set_component_property_value( + AtomComponentProperties.light('Light type'), LIGHT_TYPES['spot_disk']) + area_light_rotation = azlmbr.math.Vector3(DEGREE_RADIAN_FACTOR * 90.0, 0.0, 0.0) + azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", area_light_entity.id, area_light_rotation) + Report.result( + Tests.light_component_light_type_property_set, + light_component.get_component_property_value( + AtomComponentProperties.light('Light type')) == LIGHT_TYPES['spot_disk']) + + # 12. Enter game mode and take a screenshot then exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) + ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("AreaLight_4.ppm") + TestHelper.exit_game_mode(Tests.exit_game_mode) + TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + + # 13. Set the Light type property to Point (sphere) instead of Spot (disk) for the Light component. + light_component.set_component_property_value( + AtomComponentProperties.light('Light type'), LIGHT_TYPES['sphere']) + Report.result( + Tests.light_component_light_type_property_set, + light_component.get_component_property_value( + AtomComponentProperties.light('Light type')) == LIGHT_TYPES['sphere']) + + # 14. Enter game mode and take a screenshot then exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) + ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("AreaLight_4.ppm") + TestHelper.exit_game_mode(Tests.exit_game_mode) + TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + + # 15. Delete the Area Light entity. + area_light_entity.delete() + Report.result(Tests.area_light_entity_deleted, not area_light_entity.exists()) + + # 16. Look for errors. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") + + +if __name__ == "__main__": + from editor_python_test_tools.utils import Report + Report.start_test(AtomGPU_LightComponent_AreaLightScreenshotsMatchGoldenImages) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_BasicLevelSetup.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_BasicLevelSetup.py index 127b3e5b5f..b15e5b2131 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_BasicLevelSetup.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_BasicLevelSetup.py @@ -80,6 +80,7 @@ def AtomGPU_BasicLevelSetup_SetsUpLevel(): Test setup: - Wait for Editor idle loop. - Open the "Base" level. + - Deletes all existing entities before creating the scene. Expected Behavior: The scene can be setup for a basic level. @@ -115,7 +116,6 @@ def AtomGPU_BasicLevelSetup_SetsUpLevel(): """ import os - from math import isclose import azlmbr.legacy.general as general import azlmbr.math as math @@ -126,21 +126,11 @@ def AtomGPU_BasicLevelSetup_SetsUpLevel(): from editor_python_test_tools.utils import Report, Tracer, TestHelper from Atom.atom_utils.atom_constants import AtomComponentProperties + from Atom.atom_utils.atom_component_helper import initial_viewport_setup from Atom.atom_utils.screenshot_utils import ScreenshotHelper - SCREENSHOT_NAME = "AtomBasicLevelSetup" - SCREEN_WIDTH = 1280 - SCREEN_HEIGHT = 720 DEGREE_RADIAN_FACTOR = 0.0174533 - - def initial_viewport_setup(screen_width, screen_height): - general.set_viewport_size(screen_width, screen_height) - general.update_viewport() - TestHelper.wait_for_condition( - function=lambda: isclose(a=general.get_viewport_size().x, b=SCREEN_WIDTH, rel_tol=0.1) - and isclose(a=general.get_viewport_size().y, b=SCREEN_HEIGHT, rel_tol=0.1), - timeout_in_seconds=4.0 - ) + SCREENSHOT_NAME = "AtomBasicLevelSetup" with Tracer() as error_tracer: # Test setup begins. @@ -148,11 +138,16 @@ def AtomGPU_BasicLevelSetup_SetsUpLevel(): TestHelper.init_idle() TestHelper.open_level("", "Base") + # Setup: Deletes all existing entities before creating the scene. + search_filter = azlmbr.entity.SearchFilter() + all_entities = azlmbr.entity.SearchBus(azlmbr.bus.Broadcast, "SearchEntities", search_filter) + azlmbr.editor.ToolsApplicationRequestBus(azlmbr.bus.Broadcast, "DeleteEntities", all_entities) + # Test steps begin. # 1. Close error windows and display helpers then update the viewport size. TestHelper.close_error_windows() TestHelper.close_display_helpers() - initial_viewport_setup(SCREEN_WIDTH, SCREEN_HEIGHT) + initial_viewport_setup() general.update_viewport() # 2. Create Default Level Entity. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_LightComponentScreenshotsMatch.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_LightComponentScreenshotsMatch.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py new file mode 100644 index 0000000000..e7ac32b339 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py @@ -0,0 +1,71 @@ +""" +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 +""" + + +class Tests: + tbd = ( + "tbd", + "tbd") + + +def AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages(): + """ + Summary: + Light component test using the Spot (disk) Light type property option and modifying the shadows and colors. + Sets each scene up and then takes a screenshot of each scene for test comparison. + + Test setup: + - Wait for Editor idle loop. + - Open the "Base" level. + - Close error windows and display helpers then update the viewport size. + - Runs the create_basic_atom_rendering_scene() function to setup the test scene. + + Expected Behavior: + The test scripts sets up the scenes correctly and takes accurate screenshots. + + Test Steps: + 1. Add Directional Light component to the existing Directional Light entity. + 2. + :return: None + """ + + import azlmbr.legacy.general as general + import azlmbr.paths + + from editor_python_test_tools.utils import Report, Tracer, TestHelper + + from Atom.atom_utils.atom_component_helper import initial_viewport_setup, create_basic_atom_rendering_scene + + with Tracer() as error_tracer: + # Test setup begins. + # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. + TestHelper.init_idle() + TestHelper.open_level("", "Base") + + # Setup: Close error windows and display helpers then update the viewport size. + TestHelper.close_error_windows() + TestHelper.close_display_helpers() + initial_viewport_setup() + general.update_viewport() + + # Setup: Runs the create_basic_atom_rendering_scene() function to setup the test scene. + create_basic_atom_rendering_scene() + + # Test steps begin. + # 1. + + # ???. Look for errors. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") + + +if __name__ == "__main__": + from editor_python_test_tools.utils import Report + Report.start_test(AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages) From 132d06b6dac133e657faf3f4d25ef76ee60b513e Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 24 Nov 2021 18:55:11 -0800 Subject: [PATCH 044/128] fixed unit tests bugs, removed commented out code, removed loading spam Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Builder/ScriptCanvasBuilder.cpp | 34 ++++- .../Code/Builder/ScriptCanvasBuilder.h | 1 - .../Code/Builder/ScriptCanvasBuilderWorker.h | 5 +- .../Editor/Assets/ScriptCanvasAssetHolder.cpp | 25 ---- .../Assets/ScriptCanvasAssetTracker.cpp | 103 --------------- .../Editor/Assets/ScriptCanvasAssetTracker.h | 3 - .../Assets/ScriptCanvasAssetTrackerBus.h | 12 -- .../Editor/Assets/ScriptCanvasMemoryAsset.cpp | 86 +------------ .../EditorScriptCanvasComponent.cpp | 2 - .../Code/Editor/Components/EditorUtils.cpp | 6 +- .../Framework/ScriptCanvasTraceUtilities.h | 6 +- .../Include/ScriptCanvas/Bus/RequestBus.h | 1 - .../ScriptCanvas/Components/EditorGraph.h | 7 - .../Code/Editor/View/Widgets/GraphTabBar.cpp | 30 ----- .../Code/Editor/View/Widgets/GraphTabBar.h | 7 - .../LoggingPanel/LoggingWindowTreeItems.cpp | 15 --- .../Code/Editor/View/Windows/MainWindow.cpp | 86 +------------ .../Windows/Tools/UpgradeTool/Controller.cpp | 8 +- .../Code/Include/ScriptCanvas/Core/Graph.cpp | 13 +- .../Include/ScriptCanvas/Core/Nodeable.cpp | 8 +- .../Interpreted/ExecutionInterpretedAPI.cpp | 50 +------- ...ExecutionStateInterpretedPerActivation.cpp | 64 +--------- .../Code/Tests/ScriptCanvas_VM.cpp | 120 ------------------ 23 files changed, 52 insertions(+), 640 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp index fe89c57009..31b63e8fad 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp @@ -16,6 +16,38 @@ #include #include +namespace BuildVariableOverridesCpp +{ + enum Version + { + EditorAssetRedux, + + // add description above + Current + }; + + bool VersionConverter + ( [[maybe_unused]] AZ::SerializeContext& serializeContext + , [[maybe_unused]] AZ::SerializeContext::DataElementNode& rootElement) + { + // #sc_editor_asset +// ScriptCanvasBuilder::BuildVariableOverrides overrides; +// overrides.m_source = SourceHandle(nullptr, assetHolder.GetAssetId().m_guid, {}); +// +// for (auto& variable : editableData.GetVariables()) +// { +// overrides.m_overrides.push_back(variable.m_graphVariable); +// } +// +// if (!rootElement.AddElementWithData(serializeContext, "runtimeDataOverrides", overrides)) +// { +// AZ_Error("ScriptCanvas", false, "EditorScriptCanvasComponent conversion failed: failed to add 'runtimeDataOverrides'"); +// return false; +// } + return true; + } +} + namespace ScriptCanvasBuilder { void BuildVariableOverrides::Clear() @@ -109,7 +141,7 @@ namespace ScriptCanvasBuilder if (auto serializeContext = azrtti_cast(reflectContext)) { serializeContext->Class() - ->Version(1) + ->Version(BuildVariableOverridesCpp::Version::Current, &BuildVariableOverridesCpp::VersionConverter) ->Field("source", &BuildVariableOverrides::m_source) ->Field("variables", &BuildVariableOverrides::m_variables) ->Field("entityId", &BuildVariableOverrides::m_entityIds) diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.h b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.h index 0dedd67847..5cffa823dc 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.h +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.h @@ -49,7 +49,6 @@ namespace ScriptCanvasBuilder // these two variable lists are all that gets exposed to the edit context AZStd::vector m_overrides; AZStd::vector m_overridesUnused; - // AZStd::vector m_entityIdRuntimeInputIndices; since all oSf the entity ids need to go in, they may not need indices AZStd::vector m_dependencies; }; diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h index e1bf80aa2e..77b90df3e0 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h @@ -59,10 +59,7 @@ namespace ScriptCanvasBuilder PrefabIntegration, CorrectGraphVariableVersion, ReflectEntityIdNodes, - - ForceBuildForDevTest0, - ForceBuildForDevTest1, - ForceBuildForDevTest2, + FixExecutionStateNodeableConstrution, // add new entries above Current, diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHolder.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHolder.cpp index c5c08d5bbe..f8c89ae7e5 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHolder.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetHolder.cpp @@ -82,31 +82,6 @@ namespace ScriptCanvasEditor void ScriptCanvasAssetHolder::OpenEditor() const { - // #sc_editor_asset -// AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); -// -// AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); -// -// if (m_scriptCanvasAsset.IsReady()) -// { -// GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, m_scriptCanvasAsset.GetId(), -1); -// -// if (!openOutcome) -// { -// AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data()); -// } -// } -// else if (m_ownerId.first.IsValid()) -// { -// AzToolsFramework::EntityIdList selectedEntityIds; -// AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(selectedEntityIds, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities); -// -// // Going to bypass the multiple selected entities flow for right now. -// if (selectedEntityIds.size() == 1) -// { -// GeneralRequestBus::Broadcast(&GeneralRequests::CreateScriptCanvasAssetFor, m_ownerId); -// } -// } } ScriptCanvas::ScriptCanvasId ScriptCanvasAssetHolder::GetScriptCanvasId() const diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.cpp index 5ec620a907..09b967281d 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.cpp @@ -60,109 +60,6 @@ namespace ScriptCanvasEditor void AssetTracker::SaveAs(AZ::Data::AssetId /*assetId*/, const AZStd::string& /*path*/, Callbacks::OnSave /*onSaveCallback*/) { -// auto assetIter = m_assetsInUse.find(assetId); -// -// if (assetIter != m_assetsInUse.end()) -// { -// auto onSave = [this, assetId, onSaveCallback](bool saveSuccess, AZ::Data::AssetPtr asset, AZ::Data::AssetId previousFileAssetId) -// { -// AZ::Data::AssetId signalId = assetId; -// AZ::Data::AssetId fileAssetId = asset->GetId(); -// -// // If there is a previous file Id is valid, it means this is a save-as operation and we need to remap the tracking. -// if (previousFileAssetId.IsValid()) -// { -// if (saveSuccess) -// { -// fileAssetId = m_assetsInUse[assetId]->GetFileAssetId(); -// m_remappedAsset[asset->GetId()] = fileAssetId; -// -// // Erase the asset first so the smart pointer can deal with it's things. -// m_assetsInUse.erase(fileAssetId); -// -// // Then perform the insert once we know nothing will attempt to delete this while we are operating on it. -// m_assetsInUse[fileAssetId] = m_assetsInUse[assetId]; -// m_assetsInUse.erase(assetId); -// } -// -// m_savingAssets.erase(assetId); -// m_savingAssets.insert(fileAssetId); -// -// signalId = fileAssetId; -// -// if (m_queuedCloses.erase(assetId)) -// { -// m_queuedCloses.insert(fileAssetId); -// } -// -// auto assetIter = m_assetsInUse.find(fileAssetId); -// -// if (assetIter != m_assetsInUse.end()) -// { -// AZStd::invoke(onSaveCallback, saveSuccess, m_assetsInUse[fileAssetId]->GetAsset().Get(), previousFileAssetId); -// } -// else -// { -// AZ_Error("ScriptCanvas", !saveSuccess, "Unable to find Memory Asset for Asset(%s)", fileAssetId.ToString().c_str()); -// AZStd::invoke(onSaveCallback, saveSuccess, asset, previousFileAssetId); -// } -// } -// else -// { -// if (saveSuccess) -// { -// // This should be the case when we get a save as from a newly created file. -// // -// // If we find the 'memory' asset id in the assets in use. This means this was a new file that was saved. -// // To maintain all of the look-up stuff, we need to treat this like a remapping stage. -// auto assetInUseIter = m_assetsInUse.find(assetId); -// if (assetInUseIter != m_assetsInUse.end()) -// { -// fileAssetId = assetInUseIter->second->GetFileAssetId(); -// -// if (assetId != fileAssetId) -// { -// m_remappedAsset[assetId] = fileAssetId; -// -// m_assetsInUse.erase(fileAssetId); -// m_assetsInUse[fileAssetId] = AZStd::move(assetInUseIter->second); -// m_assetsInUse.erase(assetId); -// -// m_savingAssets.erase(assetId); -// m_savingAssets.insert(fileAssetId); -// -// if (m_queuedCloses.erase(assetId)) -// { -// m_queuedCloses.insert(fileAssetId); -// } -// } -// } -// else -// { -// fileAssetId = CheckAssetId(fileAssetId); -// } -// -// signalId = fileAssetId; -// } -// -// if (onSaveCallback) -// { -// AZStd::invoke(onSaveCallback, saveSuccess, m_assetsInUse[signalId]->GetAsset().Get(), previousFileAssetId); -// } -// -// AssetTrackerNotificationBus::Broadcast(&AssetTrackerNotifications::OnAssetSaved, m_assetsInUse[signalId], saveSuccess); -// } -// -// SignalSaveComplete(signalId); -// }; -// -// m_savingAssets.insert(assetId); -// assetIter->second->SaveAs(path, onSave); -// } -// else -// { -// AZ_Assert(false, "Cannot SaveAs into an existing AssetId"); -// } } bool AssetTracker::Load(AZ::Data::AssetId fileAssetId, AZ::Data::AssetType assetType, Callbacks::OnAssetReadyCallback onAssetReadyCallback) diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.h b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.h index 247aba3b94..aa06029c98 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.h +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTracker.h @@ -23,9 +23,6 @@ namespace ScriptCanvasEditor { class ScriptCanvasMemoryAsset; - - // MOVE THIS MOSTLY TO TAB BAR, MAIN WINDOW AND THE CANVAS WIDGET - // This class tracks all things related to the assets that the Script Canvas editor // has in play. It also provides helper functionality to quickly getting asset information // from GraphCanvas diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerBus.h b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerBus.h index fd50b40768..7125cb7d9b 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerBus.h +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasAssetTrackerBus.h @@ -155,17 +155,5 @@ namespace ScriptCanvasEditor using MemoryAssetSystemNotificationBus = AZ::EBus; } - class MemoryAssetNotifications - : public AZ::EBusTraits - { - public: - static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; - static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; - using BusIdType = AZ::Data::AssetId; - - virtual void OnFileStateChanged(Tracker::ScriptCanvasFileState) {} - }; - - using MemoryAssetNotificationBus = AZ::EBus; ////////////////////////////////////////////////////////////////////////////////////////////////////////// } diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp index 7af1aa3d9f..01595e0702 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp @@ -285,8 +285,6 @@ namespace ScriptCanvasEditor ScriptCanvasEditor::Widget::CanvasWidget* ScriptCanvasMemoryAsset::CreateView(QWidget* /*parent*/) { - //m_canvasWidget = new Widget::CanvasWidget(m_fileAssetId, parent); - //return m_canvasWidget; return nullptr; } @@ -433,66 +431,11 @@ namespace ScriptCanvasEditor void ScriptCanvasMemoryAsset::SourceFileFailed(AZStd::string /*relativePath*/, AZStd::string /*scanFolder*/, AZ::Uuid) { -// AZStd::string fullPath; -// AzFramework::StringFunc::Path::Join(scanFolder.data(), relativePath.data(), fullPath); -// AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::NormalizePath, fullPath); -// -// auto assetPathIdIt = AZStd::find(m_pendingSave.begin(), m_pendingSave.end(), fullPath); -// -// if (assetPathIdIt != m_pendingSave.end()) -// { -// if (m_onSaveCallback) -// { -// m_onSaveCallback(false, m_inMemoryAsset.Get(), AZ::Data::AssetId()); -// m_onSaveCallback = nullptr; -// } -// -// m_pendingSave.erase(assetPathIdIt); -// } + } void ScriptCanvasMemoryAsset::SavingComplete(const AZStd::string& /*streamName*/, AZ::Uuid /*sourceAssetId*/) { -// AZStd::string normPath = streamName; -// AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::NormalizePath, normPath); -// -// auto assetPathIdIt = AZStd::find(m_pendingSave.begin(), m_pendingSave.end(), normPath); -// if (assetPathIdIt != m_pendingSave.end()) -// { -// AZ::Data::AssetId previousFileAssetId; -// -// if (sourceAssetId != m_fileAssetId.m_guid) -// { -// previousFileAssetId = m_fileAssetId; -// -// // The source file has changed, store the AssetId to the canonical asset on file -// SetFileAssetId(sourceAssetId); -// -// } -// else if (!m_fileAssetId.IsValid()) -// { -// SetFileAssetId(sourceAssetId); -// } -// -// m_formerGraphIdPair = AZStd::make_pair(m_scriptCanvasId, m_graphId); -// -// m_fileState = Tracker::ScriptCanvasFileState::UNMODIFIED; -// -// m_pendingSave.erase(assetPathIdIt); -// -// m_absolutePath = m_saveAsPath; -// m_saveAsPath.clear(); -// -// // Connect to the source asset's bus to monitor for situations we may need to handle -// AZ::Data::AssetBus::MultiHandler::BusConnect(m_inMemoryAsset.GetId()); -// AZ::Data::AssetBus::MultiHandler::BusConnect(m_fileAssetId); -// -// if (m_onSaveCallback) -// { -// m_onSaveCallback(true, m_inMemoryAsset.Get(), previousFileAssetId); -// m_onSaveCallback = nullptr; -// } -// } } void ScriptCanvasMemoryAsset::FinalizeAssetSave(bool, const AzToolsFramework::SourceControlFileInfo& fileInfo, const AZ::Data::AssetStreamInfo& saveInfo, Callbacks::OnSave onSaveCallback) @@ -528,17 +471,11 @@ namespace ScriptCanvasEditor void ScriptCanvasMemoryAsset::SetFileAssetId(const AZ::Data::AssetId& /*fileAssetId*/) { -// m_fileAssetId = fileAssetId; -// -// if (m_canvasWidget) -// { -// m_canvasWidget->SetAssetId(fileAssetId); -// } + } void ScriptCanvasMemoryAsset::SignalFileStateChanged() { - MemoryAssetNotificationBus::Event(m_fileAssetId, &MemoryAssetNotifications::OnFileStateChanged, GetFileState()); } AZStd::string ScriptCanvasMemoryAsset::MakeTemporaryFilePathForSave(AZStd::string_view targetFilename) @@ -607,25 +544,6 @@ namespace ScriptCanvasEditor bool AssetSaveFinalizer::ValidateStatus(const AzToolsFramework::SourceControlFileInfo& /*fileInfo*/) { -// auto fileIO = AZ::IO::FileIOBase::GetInstance(); -// if (fileInfo.IsLockedByOther()) -// { -// AZ_Error("Script Canvas", !fileInfo.IsLockedByOther(), "The file is already exclusively opened by another user: %s", fileInfo.m_filePath.data()); -// AZStd::invoke(m_onSave, false, m_inMemoryAsset, m_fileAssetId); -// return false; -// } -// else if (fileInfo.IsReadOnly() && fileIO->Exists(fileInfo.m_filePath.c_str())) -// { -// AZ_Error("Script Canvas", !fileInfo.IsReadOnly(), "File %s is read-only. It cannot be saved." -// " If this file is in Perforce it may not have been checked out by the Source Control API.", fileInfo.m_filePath.data()); -// AZStd::invoke(m_onSave, false, m_inMemoryAsset, m_fileAssetId); -// return false; -// } -// else if (m_saving) -// { -// AZ_Warning("Script Canvas", false, "Trying to save the same file twice. Will result in one save callback being ignored."); -// return false; -// } return true; } diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp index 26fbf85a82..9209196873 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp @@ -51,8 +51,6 @@ namespace ScriptCanvasEditor { static bool EditorScriptCanvasComponentVersionConverter(AZ::SerializeContext& serializeContext, AZ::SerializeContext::DataElementNode& rootElement) { - AZ_TracePrintf("ScriptCanvas", "EditorScriptCanvasComponentVersionConverter called!"); - if (rootElement.GetVersion() <= 4) { int assetElementIndex = rootElement.FindElement(AZ::Crc32("m_asset")); diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp index d21b3d004c..2cd2dda89e 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorUtils.cpp @@ -54,11 +54,7 @@ namespace ScriptCanvasEditor if (assetSystem->GetSourceInfoBySourcePath(fullPathHandle.Path().c_str(), assetInfo, watchFolder) && assetInfo.m_assetId.IsValid()) { - if (assetInfo.m_assetId.m_guid != source.Id()) - { - AZ_TracePrintf("ScriptCanvas", "This is what I don't get"); - } - + AZ_Warning("ScriptCanvas", assetInfo.m_assetId.m_guid == source.Id(), "SourceHandle completion produced conflicting AssetId."); auto path = fullPathHandle.Path(); return SourceHandle(source, assetInfo.m_assetId.m_guid, path.MakePreferred()); } diff --git a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasTraceUtilities.h b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasTraceUtilities.h index dfcb0d2643..458852132d 100644 --- a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasTraceUtilities.h +++ b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasTraceUtilities.h @@ -163,13 +163,13 @@ namespace ScriptCanvasEditor { ScopedOutputSuppression([[maybe_unused]] bool suppressState = true) { - // AZ::Debug::TraceMessageBus::BroadcastResult(m_oldSuppression, &AZ::Debug::TraceMessageEvents::OnOutput, "", ""); - // TraceSuppressionBus::Broadcast(&TraceSuppressionRequests::SuppressAllOutput, suppressState); + AZ::Debug::TraceMessageBus::BroadcastResult(m_oldSuppression, &AZ::Debug::TraceMessageEvents::OnOutput, "", ""); + TraceSuppressionBus::Broadcast(&TraceSuppressionRequests::SuppressAllOutput, suppressState); } ~ScopedOutputSuppression() { - // TraceSuppressionBus::Broadcast(&TraceSuppressionRequests::SuppressAllOutput, m_oldSuppression); + TraceSuppressionBus::Broadcast(&TraceSuppressionRequests::SuppressAllOutput, m_oldSuppression); } private: bool m_oldSuppression = false; diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h index 15600c2b88..5ec0ee1636 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/RequestBus.h @@ -54,7 +54,6 @@ namespace ScriptCanvasEditor NEW, MODIFIED, UNMODIFIED, - // #sc_editor_asset restore this SOURCE_REMOVED, INVALID = -1 }; diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h index 8a98601d54..319a835ba5 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h @@ -140,10 +140,6 @@ namespace ScriptCanvasEditor void ReleaseVariableCounter(AZ::u32 variableCounter) override; //// - // RuntimeBus - //AZ::Data::AssetId GetAssetId() const override { return m_assetId; } - //// - // GraphCanvas::GraphModelRequestBus void RequestUndoPoint() override; @@ -223,9 +219,6 @@ namespace ScriptCanvasEditor void OnGraphCanvasNodeCreated(const AZ::EntityId& nodeId) override; /////////////////////////// - // EditorGraphRequestBus - // void SetAssetId(const AZ::Data::AssetId& assetId) override { m_assetId = assetId; } - void CreateGraphCanvasScene() override; void ClearGraphCanvasScene() override; void DisplayGraphCanvasScene() override; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp index 17228565da..b00e2ea3de 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp @@ -251,16 +251,6 @@ namespace ScriptCanvasEditor { if (index >= 0 && index < count()) { - QVariant tabdata = tabData(index); - if (tabdata.isValid()) - { - // #sc_editor_asset fix tabData - auto tabAssetId = tabdata.value(); - - //MemoryAssetNotificationBus::MultiHandler::BusDisconnect(tabAssetId); - //AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::ClearView, tabAssetId); - } - qobject_cast(parent())->removeTab(index); } } @@ -271,8 +261,6 @@ namespace ScriptCanvasEditor { Q_EMIT TabCloseNoButton(i); } - - MemoryAssetNotificationBus::MultiHandler::BusDisconnect(); } void GraphTabBar::OnContextMenu(const QPoint& point) @@ -289,8 +277,6 @@ namespace ScriptCanvasEditor auto tabAssetId = tabdata.value(); Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::INVALID; - //AssetTrackerRequestBus::BroadcastResult(fileState , &AssetTrackerRequests::GetFileState, tabAssetId); - isModified = fileState == Tracker::ScriptCanvasFileState::NEW || fileState == Tracker::ScriptCanvasFileState::MODIFIED; } @@ -362,22 +348,6 @@ namespace ScriptCanvasEditor AzQtComponents::TabBar::mouseReleaseEvent(event); } - void GraphTabBar::OnFileStateChanged(Tracker::ScriptCanvasFileState ) - { - // #sc_editor_asset - // const AZ::Data::AssetId* fileAssetId = MemoryAssetNotificationBus::GetCurrentBusId(); - -// if (fileAssetId) -// { -// SetFileState((*fileAssetId), fileState); -// -// if (FindTab((*fileAssetId)) == currentIndex()) -// { -// Q_EMIT OnActiveFileStateChanged(); -// } -// } - } - void GraphTabBar::SetTabText(int tabIndex, const QString& path, Tracker::ScriptCanvasFileState fileState) { if (tabIndex >= 0 && tabIndex < count()) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h index 9d86583f76..40b785f016 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h @@ -42,7 +42,6 @@ namespace ScriptCanvasEditor class GraphTabBar : public AzQtComponents::TabBar - , public MemoryAssetNotificationBus::MultiHandler { Q_OBJECT @@ -63,8 +62,6 @@ namespace ScriptCanvasEditor int InsertGraphTab(int tabIndex, ScriptCanvasEditor::SourceHandle assetId, Tracker::ScriptCanvasFileState fileState); bool SelectTab(ScriptCanvasEditor::SourceHandle assetId); - // void ConfigureTab(int tabIndex, ScriptCanvasEditor::SourceHandle fileAssetId, const AZStd::string& tabName); - int FindTab(ScriptCanvasEditor::SourceHandle assetId) const; ScriptCanvasEditor::SourceHandle FindTabByPath(AZStd::string_view path) const; ScriptCanvasEditor::SourceHandle FindAssetId(int tabIndex); @@ -78,10 +75,6 @@ namespace ScriptCanvasEditor void mouseReleaseEvent(QMouseEvent* event) override; - // MemoryAssetNotifications - void OnFileStateChanged(Tracker::ScriptCanvasFileState fileState) override; - //// - // Updates the tab at the supplied index with the GraphTabMetadata // The host widget field of the tabMetadata is not used and will not overwrite the tab data void SetTabText(int tabIndex, const QString& path, Tracker::ScriptCanvasFileState fileState = Tracker::ScriptCanvasFileState::INVALID); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp index a9ffe30fb1..636ee832d4 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp @@ -137,17 +137,6 @@ namespace ScriptCanvasEditor m_additionTimer.start(); } } - - if (m_updatePolicy == UpdatePolicy::SingleTime) - { - // #sc_editor_asset - // treeItem = CreateChildNodeWithoutAddSignal(loggingDataId, nodeType, graphInfo, nodeId); - } - else - { - // #sc_editor_asset - // treeItem = CreateChildNode(loggingDataId, nodeType, graphInfo, nodeId); - } return treeItem; } @@ -207,9 +196,6 @@ namespace ScriptCanvasEditor AZ::NamedEntityId entityName; - // #sc_editor_asset restore this - //LoggingDataRequestBus::EventResult(entityName, m_loggingDataId, &LoggingDataRequests::FindNamedEntityId, m_graphInfo.m_runtimeEntity); - m_sourceEntityName = entityName.ToString().c_str(); m_displayName = nodeId.m_name.c_str(); @@ -514,7 +500,6 @@ namespace ScriptCanvasEditor const ScriptCanvas::GraphIdentifier& ExecutionLogTreeItem::GetGraphIdentifier() const { - // #sc_editor_asset return m_graphIdentifier; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index d6efe246a0..666467001c 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -1665,42 +1665,6 @@ namespace ScriptCanvasEditor return SaveAssetImpl(m_activeGraph, Save::As); } - /* - bool MainWindow::SaveAssetImpl_OLD(const ScriptCanvasEditor::SourceHandle& assetId, const Callbacks::OnSave& saveCB) - { - if (!assetId.IsValid()) - { - return false; - } - - // TODO: Set graph read-only to prevent edits during save - - bool saveSuccessful = false; - - Tracker::ScriptCanvasFileState fileState = GetAssetFileState(assetId); - - if (fileState == Tracker::ScriptCanvasFileState::NEW) - { - saveSuccessful = SaveAssetImpl(assetId, saveCB); - } - else if (fileState == Tracker::ScriptCanvasFileState::MODIFIED - || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED) - { - SaveAs(assetId.Path(), assetId, saveCB); - saveSuccessful = true; - } - - return saveSuccessful; - } - */ - - - // 1. SaveAssetImpl - // 2. SaveAs - // // 3. OnSaveCallback - // SaveAsEnd - // SaveAssetImpl end - bool MainWindow::SaveAssetImpl(const ScriptCanvasEditor::SourceHandle& inMemoryAssetId, Save save) { if (!inMemoryAssetId.IsGraphValid()) @@ -1768,11 +1732,6 @@ namespace ScriptCanvasEditor AZ::IO::FileIOBase::GetInstance()->ResolvePath("@engroot@", assetRootChar.data(), assetRootChar.size()); assetRoot = assetRootChar.data(); -// if (!AZ::StringFunc::StartsWith(filePath, assetRoot)) -// { -// QMessageBox::information(this, "Unable to Save", AZStd::string::format("You must select a path within the current project\n\n%s", assetRoot.c_str()).c_str()); -// } -// else if (AzFramework::StringFunc::Path::GetFileName(filePath.c_str(), fileName)) { isValidFileName = !(fileName.empty()); @@ -1924,14 +1883,6 @@ namespace ScriptCanvasEditor { m_tabBar->setCurrentIndex(saveTabIndex); } - else - { -// // Something weird happens with our saving. Where we are relying on these scene changes being called. -// ScriptCanvasEditor::SourceHandle previousAssetId = m_activeGraph; -// -// OnChangeActiveGraphTab(ScriptCanvasEditor::SourceHandle()); -// OnChangeActiveGraphTab(previousAssetId); - } UpdateAssignToSelectionState(); @@ -2365,6 +2316,7 @@ namespace ScriptCanvasEditor GraphCanvas::ViewRequestBus::Event(viewId, &GraphCanvas::ViewRequests::CenterOnEndOfChain); } + // #sc_editor_asset void MainWindow::UpdateWorkspaceStatus(const ScriptCanvasMemoryAsset& /*memoryAsset*/) { // only occurs on file open, do it there, if necessary @@ -2656,16 +2608,6 @@ namespace ScriptCanvasEditor void MainWindow::Clear() { m_tabBar->CloseAllTabs(); - // #sc_editor_asset -// -// AssetTrackerRequests::AssetList assets; -// AssetTrackerRequestBus::BroadcastResult(assets, &AssetTrackerRequests::GetAssets); -// -// for (auto asset : assets) -// { -// RemoveScriptCanvasAsset(asset->GetAsset().GetId()); -// } - SetActiveAsset({}); } @@ -4093,32 +4035,6 @@ namespace ScriptCanvasEditor void MainWindow::PrepareAssetForSave(const ScriptCanvasEditor::SourceHandle& /*assetId*/) { - /* - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); - - if (memoryAsset) - { - AZ::EntityId graphId = memoryAsset->GetGraphId(); - AZ::EntityId scriptCanvasId = memoryAsset->GetScriptCanvasId(); - - AZ::Entity* entity = nullptr; - GraphRequestBus::EventResult(entity, scriptCanvasId, &GraphRequests::GetGraphEntity); - - if (entity) - { - GraphCanvas::GraphModelRequestBus::Event(graphId, &GraphCanvas::GraphModelRequests::OnSaveDataDirtied, entity->GetId()); - } - - GraphCanvas::GraphModelRequestBus::Event(graphId, &GraphCanvas::GraphModelRequests::OnSaveDataDirtied, graphId); - - ScriptCanvasEditor::Graph* graph = AZ::EntityUtils::FindFirstDerivedComponent(entity); - if (graph) - { - graph->MarkVersion(); - } - } - */ } void MainWindow::RestartAutoTimerSave(bool forceTimer) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp index 888f183151..b8ae59d43b 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp @@ -323,13 +323,7 @@ namespace ScriptCanvasEditor m_view->tableWidget->setCellWidget(rowIndex, static_cast(ColumnAction), upgradeButton); } - - char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; - AZStd::string path = AZStd::string::format("@devroot@/%s", assetInfo.Path().c_str()); - AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); - AZ::StringFunc::Path::GetFullPath(resolvedBuffer, path); - AZ::StringFunc::Path::Normalize(path); - + bool result = false; AZ::Data::AssetInfo info; AZStd::string watchFolder; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp index aff212fa4c..9c2c854055 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp @@ -72,19 +72,16 @@ namespace ScriptCanvas componentElementNode.AddElementWithData(context, "m_assetType", azrtti_typeid()); } - if (componentElementNode.GetVersion() <= GraphCpp::GraphVersion::RemoveFunctionGraphMarker) + if (auto subElement = componentElementNode.FindElement(AZ_CRC_CE("isFunctionGraph")); subElement > 0) { - componentElementNode.RemoveElementByName(AZ_CRC_CE("isFunctionGraph")); + componentElementNode.RemoveElement(subElement); } - if (componentElementNode.GetVersion() < GraphCpp::GraphVersion::FixupVersionDataTypeId) + if (auto subElement = componentElementNode.FindSubElement(AZ_CRC_CE("versionData"))) { - if (auto subElement = componentElementNode.FindSubElement(AZ_CRC_CE("versionData"))) + if (subElement->GetId() == azrtti_typeid()) { - if (subElement->GetId() == azrtti_typeid()) - { - componentElementNode.RemoveElementByName(AZ_CRC_CE("versionData")); - } + componentElementNode.RemoveElementByName(AZ_CRC_CE("versionData")); } } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp index 023d46097d..7bb37a87dc 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp @@ -22,16 +22,12 @@ namespace ScriptCanvas Nodeable::Nodeable() : m_noOpFunctor(&NodeableOutCpp::NoOp) - { - AZ_TracePrintf("SCDB", "How many times does this get called? Because it should....NOT GET CALLED!"); - } + {} Nodeable::Nodeable(ExecutionStateWeakPtr executionState) : m_noOpFunctor(&NodeableOutCpp::NoOp) , m_executionState(executionState) - { - AZ_TracePrintf("SCDB", "How many times does this get called 2?"); - } + {} #if !defined(RELEASE) void Nodeable::CallOut(size_t index, AZ::BehaviorValueParameter* resultBVP, AZ::BehaviorValueParameter* argsBVPs, int numArguments) const diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp index c43214eeea..3b95c7895c 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp @@ -68,9 +68,7 @@ namespace ExecutionInterpretedAPICpp { if (lua_isstring(lua, -1)) { - AZStd::string errorResult = lua_tostring(lua, -1); - AZ_TracePrintf("ScriptCanvas", errorResult.c_str()); - AZ::ScriptContext::FromNativeContext(lua)->Error(AZ::ScriptContext::ErrorType::Error, true, "%s", lua_tostring(lua, -1)); + AZ::ScriptContext::FromNativeContext(lua)->Error(AZ::ScriptContext::ErrorType::Error, true, lua_tostring(lua, -1)); } else { @@ -403,51 +401,7 @@ namespace ScriptCanvas // \note: the the object is being constructed, and is assumed to never leave or re-enter Lua again AZ_Assert(lua_isuserdata(lua, -2) && !lua_islightuserdata(lua, -2), "Error in compiled lua file, 1st argument to OverrideNodeableMetatable is not userdata (Nodeable)"); AZ_Assert(lua_istable(lua, -1), "Error in compiled lua file, 2nd argument to OverrideNodeableMetatable is not a Lua table"); - - /* table is in the stack at index 't' */ - if (lua_istable(lua, -1)) - { - lua_getfield(lua, -1, "__index"); - - if (lua_istable(lua, -1)) - { - int t = -2; - AZStd::string tableGuts; - lua_pushnil(lua); - /* first key */ - while (lua_next(lua, t) != 0) - { - /* uses 'key' (at index -2) and 'value' (at index -1) */ - if (lua_type(lua, -2) == LUA_TSTRING) - { - size_t len; - tableGuts += AZStd::string::format("%s - %s\n", - lua_tolstring(lua, -2, &len), - lua_typename(lua, lua_type(lua, -1))); - } - else if (lua_type(lua, -2) == LUA_TNUMBER) - { - tableGuts += AZStd::string::format("%f - %s\n", - lua_tonumber(lua, -2), - lua_typename(lua, lua_type(lua, -1))); - } - else - { - tableGuts += AZStd::string::format("%s - %s\n", - lua_typename(lua, lua_type(lua, -2)), - lua_typename(lua, lua_type(lua, -1))); - } - - /* removes 'value'; keeps 'key' for next iteration */ - lua_pop(lua, 1); - } - - AZ_TracePrintf("SCDB", tableGuts.c_str()); - } - - lua_pop(lua, 1); - } - + [[maybe_unused]] auto userData = reinterpret_cast(lua_touserdata(lua, -2)); AZ_Assert(userData && userData->magicData == AZ_CRC_CE("AZLuaUserData"), "this isn't user data"); // Lua: LuaUserData::nodeable, class_mt diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpretedPerActivation.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpretedPerActivation.cpp index 7ef1e22fbf..425af171c5 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpretedPerActivation.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpretedPerActivation.cpp @@ -111,75 +111,13 @@ namespace ScriptCanvas auto& lua = m_luaState; // Lua: lua_rawgeti(lua, LUA_REGISTRYINDEX, registryIndex); - if (!lua_isuserdata(lua, -1)) - { - AZ_TracePrintf("SCDB", "No light userdata"); - } - // Lua: instance - - lua_getmetatable(lua, -1); - if (!lua_istable(lua, -1)) - { - AZ_TracePrintf("SCDB", "no metatable"); - } - - - /* table is in the stack at index 't' */ - if (lua_istable(lua, -1)) - { - int t = -2; - AZStd::string tableGuts; - lua_pushnil(lua); - /* first key */ - while (lua_next(lua, t) != 0) - { - /* uses 'key' (at index -2) and 'value' (at index -1) */ - if (lua_type(lua, -2) == LUA_TSTRING) - { - size_t len; - tableGuts += AZStd::string::format("%s - %s\n", - lua_tolstring(lua, -2, &len), - lua_typename(lua, lua_type(lua, -1))); - } - else if (lua_type(lua, -2) == LUA_TNUMBER) - { - tableGuts += AZStd::string::format("%f - %s\n", - lua_tonumber(lua, -2), - lua_typename(lua, lua_type(lua, -1))); - } - else - { - tableGuts += AZStd::string::format("%s - %s\n", - lua_typename(lua, lua_type(lua, -2)), - lua_typename(lua, lua_type(lua, -1))); - } - - /* removes 'value'; keeps 'key' for next iteration */ - lua_pop(lua, 1); - } - - AZ_TracePrintf("SCDB", tableGuts.c_str()); - } - - // Lua: instance, instance_mt - lua_pop (lua, 1); - - // Lua: instance lua_getfield(lua, -1, Grammar::k_OnGraphStartFunctionName); // Lua: instance, graph_VM.k_OnGraphStartFunctionName - if (!lua_isfunction(lua, -1)) - { - AZ_TracePrintf("SCDB", "No function"); - } lua_pushvalue(lua, -2); - if (!lua_isuserdata(lua, -1)) - { - AZ_TracePrintf("SCDB", "No light userdata"); - } // Lua: instance, graph_VM.k_OnGraphStartFunctionName, instance const int result = Execution::InterpretedSafeCall(lua, 1, 0); - // Lua: instance ? + // Lua: instance, ? if (result == LUA_OK) { // Lua: instance diff --git a/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_VM.cpp b/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_VM.cpp index 2a20ca84df..2c455d80f5 100644 --- a/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_VM.cpp +++ b/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_VM.cpp @@ -25,126 +25,6 @@ using namespace ScriptCanvasTests; using namespace TestNodes; using namespace ScriptCanvas::Execution; -// TODO: This fails to compile on Linux only -//ScriptCanvas::Grammar::SubgraphInterface* CreateExecutionMap(AZ::BehaviorContext& behaviorContext) -//{ -// using namespace ScriptCanvas; -// using namespace ScriptCanvas::Grammar; -// -// auto ins = CreateInsFromBehaviorContextMethods("TestNodeableObject", behaviorContext, { "Branch" } ); -// auto branchOutVoidTrue = CreateOut("BranchTrue", { "condition", "message" }); -// auto branchOutVoidFalse = CreateOut("BranchFalse", { "condition", "message", "vector" }); -// -// auto branchOut = FindInByName("Branch", ins); -// -// EXPECT_NE(branchOut, nullptr); -// if (branchOut) -// { -// branchOut->outs.emplace_back(AZStd::move(branchOutVoidTrue)); -// branchOut->outs.emplace_back(AZStd::move(branchOutVoidFalse)); -// } -// -// return aznew SubgraphInterface(AZStd::move(ins)); -//} - - -TEST_F(ScriptCanvasTestFixture, TestLuaObjectOrientation) -{ - using namespace ScriptCanvas; - using namespace ScriptCanvas::Grammar; - - AZ::ScriptContext sc; - sc.BindTo(m_behaviorContext); - RegisterAPI(sc.NativeContext()); - EXPECT_TRUE(sc.Execute( - R"LUA( - -assert(Nodeable ~= nil, 'Nodeable was nill') -assert(Nodeable.__call ~= nil, 'Nodeable.__call was nil') -assert(type(Nodeable.__call) == 'function', 'Nodeable.__call was not a function') - -local nodeable = Nodeable() -assert(nodeable ~= nil, 'nodeable was nil') -assert(type(nodeable) == "userdata", 'nodeable not userdata') - -local SubGraph = {} -SubGraph.s_name = "SubGraphery" -SubGraph.s_createdCount = 0 -function SubGraph:IncrementCreated() - SubGraph.s_createdCount = 1 + SubGraph.s_createdCount -end - -setmetatable(SubGraph, { __index = Nodeable }) -- exposed through BehaviorContext -local SubGraphInstanceMetatable = { __index = SubGraph } - -assert(getmetatable(SubGraph).__index == Nodeable, 'getmetatable(SubGraph).__index = Nodeable') -assert(type(getmetatable(SubGraph).__index) == 'table', "type(getmetatable(SubGraph).__index) ~= 'table'") - -function SubGraph.new() -- Add executionState input here and to Nodeable() - -- now individual instance values can be initialized - local instance = OverrideNodeableMetatable(Nodeable(), SubGraphInstanceMetatable) - assert(type(instance.s_createdCount) == 'number', 'subgraph.s_createdCount was not a number') - instance:IncrementCreated() - instance.name = 'SubGraph '..tostring(instance.s_createdCount) - return instance -end - -function SubGraph.newTable() -- Add executionState input here and to Nodeable() - -- now individual instance values can be initialized - local instance = setmetatable({}, SubGraphInstanceMetatable) - -- assert(getmetatable(instance) == SubGraphInstanceMetatable, "subgraphT") - assert(type(instance.s_createdCount) == 'number', 'subgraphT.s_createdCount was not a number') - instance:IncrementCreated() - instance.name = 'SubGraph '..tostring(instance.s_createdCount) - return instance -end - -function SubGraph:Foo() - return "I, " .. tostring(self.name) .. ", am a user function" -end - -local subgraphT = SubGraph.newTable() -assert(subgraphT ~= nil, "subgraphT was nil") -assert(type(subgraphT) == 'table', 'subgraphT was not a table') -assert(type(subgraphT.IsActive)== 'function', "subgraphT IsActive was not a function") -assert(type(subgraphT.Foo) == 'function', 'subgraphT was not a function') -local subgraphTResult = subgraphT:Foo() -assert(subgraphTResult == "I, SubGraph 1, am a user function", 'subgraphT did not return the right results:' .. tostring(subgraphTResult)) -assert(subgraphT.s_createdCount == 1, "subgraphT created count was not one: ".. tostring(subgraphT.s_createdCount)) -subgraphT = SubGraph.newTable() -assert(subgraphT.s_createdCount == 2, "subgraphT created count was not two: ".. tostring(subgraphT.s_createdCount)) - -local subgraph = SubGraph.new() -assert(subgraph ~= nil, "subgraph was nil") -assert(type(subgraph) == 'userdata', 'was not userdata') -assert(type(subgraph.IsActive)== 'function', "IsActive was not a function") -assert(not subgraph.IsActive(subgraph), "did not inherit properly") -assert(not subgraph:IsActive(), "did not inherit properly") -assert(type(subgraph.Foo) == 'function', 'was not a function') -local subgraphResult = subgraph:Foo() -assert(subgraphResult == "I, SubGraph 3, am a user function", 'subgraph:Foo() did not return the right results: ' .. tostring(subgraphResult)) -assert(subgraph.s_createdCount == 3, "created count was not three: "..tostring(subgraph.s_createdCount)) - -local subgraph2 = SubGraph.new() -assert(subgraph2 ~= nil, "subgraph2 was nil") -assert(type(subgraph2) == 'userdata', 'subgraph2 was not userdata') -assert(type(subgraph2.IsActive)== 'function', "subgraph2 IsActive was not a function") -assert(not subgraph2.IsActive(subgraph2), "subgraph2 did not inherit properly") -assert(not subgraph2:IsActive(), "subgraph2 did not inherit properly") -assert(type(subgraph2.Foo) == 'function', 'subgraph2 was not a function') -local subgraph2Result = subgraph2:Foo() -assert(subgraph2Result == "I, SubGraph 4, am a user function", 'subgraph2:Foo() did not return the right results: ' .. tostring(subgraph2Result)) -assert(subgraph2.s_createdCount == 4, "created count was not three: "..tostring(subgraph2.s_createdCount)) - -return SubGraph - -)LUA" -)); - -} - - -// // TEST_F(ScriptCanvasTestFixture, NativeNodeableStack) // { // TestNodeableObject nodeable; From 8c308fc3da4a39729831d6fde95a979288c37733 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Mon, 29 Nov 2021 13:43:39 -0800 Subject: [PATCH 045/128] Clean up modifier asset handling. Fix file handling string error. Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Assets/ScriptCanvasFileHandling.cpp | 3 +- .../Windows/Tools/UpgradeTool/Modifier.cpp | 49 +++++++++---------- .../View/Windows/Tools/UpgradeTool/Modifier.h | 5 +- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp index 8cecdc86d9..706c46fa75 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp @@ -317,8 +317,7 @@ namespace ScriptCanvasEditor 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::Failure(AZStd::string::format("JSON serialization failed to save source: %s", saveOutcome.GetError().c_str())); } return AZ::Success(); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp index 71aeb1dbb9..242aea355e 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp @@ -32,6 +32,14 @@ namespace ScriptCanvasEditor AZ::SystemTickBus::Handler::BusConnect(); } + size_t Modifier::GetCurrentIndex() const + { + return m_state == State::GatheringDependencies + ? m_assetIndex + : m_dependencyOrderedAssetIndicies[m_assetIndex]; + + } + AZStd::unordered_set& Modifier::GetOrCreateDependencyIndexSet() { auto iter = m_dependencies.find(m_assetIndex); @@ -55,10 +63,10 @@ namespace ScriptCanvasEditor AZ_Assert(serializeContext, "SerializeContext is required to enumerate dependent assets in the ScriptCanvas file"); bool anyFailures = false; - auto asset = LoadAsset(); - if (asset.Get() && asset.Mod()->GetGraphData()) + + if (m_result.asset.Get() && m_result.asset.Mod()->GetGraphData()) { - auto graphData = asset.Mod()->GetGraphData(); + auto graphData = m_result.asset.Mod()->GetGraphData(); auto dependencyGrabber = [this] ( void* instancePointer @@ -94,19 +102,19 @@ namespace ScriptCanvasEditor { anyFailures = true; VE_LOG("Modifier: ERROR - Failed to gather dependencies from graph data: %s" - , ModCurrentAsset().Path().c_str()) + , m_result.asset.Path().c_str()) } } else { anyFailures = true; VE_LOG("Modifier: ERROR - Failed to load asset %s for modification, even though it scanned properly" - , ModCurrentAsset().Path().c_str()); + , m_result.asset.Path().c_str()); } ModelNotificationsBus::Broadcast ( &ModelNotificationsTraits::OnUpgradeDependenciesGathered - , ModCurrentAsset() + , m_result.asset , anyFailures ? Result::Failure : Result::Success); ReleaseCurrentAsset(); @@ -115,9 +123,9 @@ namespace ScriptCanvasEditor AZ::Data::AssetManager::Instance().DispatchEvents(); } - SourceHandle Modifier::LoadAsset() + void Modifier::LoadAsset() { - auto& handle = ModCurrentAsset(); + auto& handle = m_result.asset; if (!handle.IsGraphValid()) { auto outcome = LoadFromFile(handle.Path().c_str()); @@ -126,8 +134,6 @@ namespace ScriptCanvasEditor handle = outcome.TakeValue(); } } - - return handle; } void Modifier::ModificationComplete(const ModificationResult& result) @@ -144,25 +150,18 @@ namespace ScriptCanvasEditor } } - SourceHandle& Modifier::ModCurrentAsset() - { - return m_state == State::GatheringDependencies - ? m_assets[m_assetIndex] - : m_assets[m_dependencyOrderedAssetIndicies[m_assetIndex]]; - } - void Modifier::ModifyCurrentAsset() { m_result = {}; - m_result.asset = ModCurrentAsset(); + m_result.asset = m_assets[GetCurrentIndex()]; + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeModificationBegin, m_config, m_result.asset); + LoadAsset(); - ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeModificationBegin, m_config, ModCurrentAsset()); - - if (auto asset = LoadAsset(); asset.IsGraphValid()) + if (m_result.asset.IsGraphValid()) { ModificationNotificationsBus::Handler::BusConnect(); m_modifyState = ModifyState::InProgress; - m_config.modification(asset); + m_config.modification(m_result.asset); } else { @@ -173,7 +172,7 @@ namespace ScriptCanvasEditor void Modifier::ModifyNextAsset() { ModelNotificationsBus::Broadcast - ( &ModelNotificationsTraits::OnUpgradeModificationEnd, m_config, ModCurrentAsset(), m_result); + ( &ModelNotificationsTraits::OnUpgradeModificationEnd, m_config, m_result.asset, m_result); ModificationNotificationsBus::Handler::BusDisconnect(); m_modifyState = ModifyState::Idle; ReleaseCurrentAsset(); @@ -183,7 +182,7 @@ namespace ScriptCanvasEditor void Modifier::ReleaseCurrentAsset() { - ModCurrentAsset() = ModCurrentAsset().Describe(); + m_result.asset = m_result.asset.Describe(); } void Modifier::ReportModificationError(AZStd::string_view report) @@ -381,7 +380,7 @@ namespace ScriptCanvasEditor (ScriptCanvas::k_VersionExplorerWindow.data() , false , "Modifier: Dependency sort has failed during, circular dependency detected for Asset: %s" - , modifier->ModCurrentAsset().Path().c_str()); + , modifier->m_result.asset.Path().c_str()); return; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h index 78c9b3a877..32b9253bb5 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h @@ -67,6 +67,7 @@ namespace ScriptCanvasEditor State m_state = State::GatheringDependencies; ModifyState m_modifyState = ModifyState::Idle; size_t m_assetIndex = 0; + AZStd::function m_onComplete; // asset infos in scanned order AZStd::vector m_assets; @@ -82,10 +83,10 @@ namespace ScriptCanvasEditor AZStd::unique_ptr m_fileSaver; FileSaveResult m_fileSaveResult; + size_t GetCurrentIndex() const; void GatherDependencies(); AZStd::unordered_set& GetOrCreateDependencyIndexSet(); - SourceHandle LoadAsset(); - SourceHandle& ModCurrentAsset(); + void LoadAsset(); void ModifyCurrentAsset(); void ModifyNextAsset(); void ModificationComplete(const ModificationResult& result) override; From af2e0a117d45b86722b828fa9a588961f172a7c4 Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Tue, 30 Nov 2021 08:10:55 +0000 Subject: [PATCH 046/128] LYN-6357 Terrain Macro Material tests Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- AutomatedTesting/Assets/Textures/image.png | 3 + AutomatedTesting/Assets/Textures/normal.png | 3 + .../Gem/PythonTests/Terrain/TestSuite_Main.py | 3 + .../TerrainMacroMaterialComponent.cpp | 3 +- .../TerrainMacroMaterialBus.cpp | 93 +++++++++++++++++++ .../TerrainRenderer/TerrainMacroMaterialBus.h | 6 +- .../Code/Tests/TerrainMacroMaterialTests.cpp | 86 +++++++++++++++++ Gems/Terrain/Code/terrain_files.cmake | 1 + Gems/Terrain/Code/terrain_tests_files.cmake | 1 + 9 files changed, 197 insertions(+), 2 deletions(-) create mode 100644 AutomatedTesting/Assets/Textures/image.png create mode 100644 AutomatedTesting/Assets/Textures/normal.png create mode 100644 Gems/Terrain/Code/Source/TerrainRenderer/TerrainMacroMaterialBus.cpp create mode 100644 Gems/Terrain/Code/Tests/TerrainMacroMaterialTests.cpp diff --git a/AutomatedTesting/Assets/Textures/image.png b/AutomatedTesting/Assets/Textures/image.png new file mode 100644 index 0000000000..2f558c634e --- /dev/null +++ b/AutomatedTesting/Assets/Textures/image.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:011454252e40c927343cce16296412f02f45d1f345c75c036651bdcca473bda5 +size 2672 diff --git a/AutomatedTesting/Assets/Textures/normal.png b/AutomatedTesting/Assets/Textures/normal.png new file mode 100644 index 0000000000..d3355e6699 --- /dev/null +++ b/AutomatedTesting/Assets/Textures/normal.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7bafcc4aefab827e1414e64bcdde235500b51392e52c9ccd588b2d7a24b865a0 +size 20214 diff --git a/AutomatedTesting/Gem/PythonTests/Terrain/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Terrain/TestSuite_Main.py index 786651713c..41b6774046 100644 --- a/AutomatedTesting/Gem/PythonTests/Terrain/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/Terrain/TestSuite_Main.py @@ -27,3 +27,6 @@ class TestAutomation(EditorTestSuite): class test_Terrain_SupportsPhysics(EditorSharedTest): from .EditorScripts import Terrain_SupportsPhysics as test_module + + class test_TerrainMacroMaterialComponent_MacroMaterialActivates(EditorSharedTest): + from .EditorScripts import TerrainMacroMaterialComponent_MacroMaterialActivates as test_module \ No newline at end of file diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.cpp index a65cbad50b..304d5aecd4 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.cpp @@ -93,7 +93,8 @@ namespace Terrain void TerrainMacroMaterialComponent::Reflect(AZ::ReflectContext* context) { TerrainMacroMaterialConfig::Reflect(context); - + TerrainMacroMaterialRequests::Reflect(context); + AZ::SerializeContext* serialize = azrtti_cast(context); if (serialize) { diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMacroMaterialBus.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMacroMaterialBus.cpp new file mode 100644 index 0000000000..b1c6f2d54b --- /dev/null +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMacroMaterialBus.cpp @@ -0,0 +1,93 @@ +/* + * 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 "TerrainMacroMaterialBus.h" +#include +#include + +namespace Terrain +{ + // Create a handler that can be accessed from Python scripts to receive terrain change notifications. + class TerrainMacroMaterialNotificationHandler final + : public Terrain::TerrainMacroMaterialNotificationBus::Handler + , public AZ::BehaviorEBusHandler + { + public: + AZ_EBUS_BEHAVIOR_BINDER( + TerrainMacroMaterialNotificationHandler, + "{B0ED8B29-0E0D-4567-BEAF-C842C4DB2700}", + AZ::SystemAllocator, + OnTerrainMacroMaterialCreated, + OnTerrainMacroMaterialChanged, + OnTerrainMacroMaterialRegionChanged, + OnTerrainMacroMaterialDestroyed); + + void OnTerrainMacroMaterialCreated( + [[maybe_unused]] AZ::EntityId macroMaterialEntity, + [[maybe_unused]] const Terrain::MacroMaterialData& macroMaterial) override + { + Call(FN_OnTerrainMacroMaterialCreated); + } + + void OnTerrainMacroMaterialChanged( + [[maybe_unused]] AZ::EntityId macroMaterialEntity, + [[maybe_unused]] const Terrain::MacroMaterialData& macroMaterial) override + { + Call(FN_OnTerrainMacroMaterialChanged); + } + + void OnTerrainMacroMaterialRegionChanged( + [[maybe_unused]] AZ::EntityId macroMaterialEntity, + [[maybe_unused]] const AZ::Aabb& oldRegion, + [[maybe_unused]] const AZ::Aabb& newRegion) override + { + Call(FN_OnTerrainMacroMaterialRegionChanged); + } + + void OnTerrainMacroMaterialDestroyed([[maybe_unused]] AZ::EntityId macroMaterialEntity) override + { + Call(FN_OnTerrainMacroMaterialDestroyed); + } + + static void Reflect(AZ::ReflectContext* context) + { + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->EBus("TerrainMacroMaterialAutomationBus") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) + ->Attribute(AZ::Script::Attributes::Module, "terrain") + ->Handler(); + } + } + }; + + void TerrainMacroMaterialRequests::Reflect(AZ::ReflectContext* context) + { + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->EBus("TerrainMacroMaterialRequestBus") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Category, "Terrain") + ->Attribute(AZ::Script::Attributes::Module, "terrain") + ->Event("GetTerrainMacroMaterialData", &Terrain::TerrainMacroMaterialRequestBus::Events::GetTerrainMacroMaterialData) + ; + + behaviorContext->EBus("TerrainMacroMaterialNotificationBus") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Category, "Terrain") + ->Attribute(AZ::Script::Attributes::Module, "terrain") + ->Event("OnTerrainMacroMaterialCreated", &Terrain::TerrainMacroMaterialNotifications::OnTerrainMacroMaterialCreated) + ->Event("OnTerrainMacroMaterialChanged", &Terrain::TerrainMacroMaterialNotifications::OnTerrainMacroMaterialChanged) + ->Event("OnTerrainMacroMaterialRegionChanged", &Terrain::TerrainMacroMaterialNotifications::OnTerrainMacroMaterialRegionChanged) + ->Event("OnTerrainMacroMaterialDestroyed", &Terrain::TerrainMacroMaterialNotifications::OnTerrainMacroMaterialDestroyed) + ; + + Terrain::TerrainMacroMaterialNotificationHandler::Reflect(context); + } + } +} // namespace Terrain diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMacroMaterialBus.h b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMacroMaterialBus.h index af1e755b32..9a7151da56 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMacroMaterialBus.h +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMacroMaterialBus.h @@ -16,8 +16,10 @@ namespace Terrain { - struct MacroMaterialData + struct MacroMaterialData final { + AZ_RTTI(MacroMaterialData, "{DC68E20A-3251-4E4E-8BC7-F6A2521FEF46}"); + AZ::EntityId m_entityId; AZ::Aabb m_bounds = AZ::Aabb::CreateNull(); @@ -35,6 +37,8 @@ namespace Terrain : public AZ::ComponentBus { public: + static void Reflect(AZ::ReflectContext* context); + //////////////////////////////////////////////////////////////////////// // EBusTraits using MutexType = AZStd::recursive_mutex; diff --git a/Gems/Terrain/Code/Tests/TerrainMacroMaterialTests.cpp b/Gems/Terrain/Code/Tests/TerrainMacroMaterialTests.cpp new file mode 100644 index 0000000000..a3b772035f --- /dev/null +++ b/Gems/Terrain/Code/Tests/TerrainMacroMaterialTests.cpp @@ -0,0 +1,86 @@ +/* + * 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 + +using ::testing::NiceMock; +using ::testing::AtLeast; +using ::testing::_; + + +class TerrainMacroMaterialComponentTest + : public ::testing::Test +{ +protected: + AZ::ComponentApplication m_app; + + UnitTest::MockAxisAlignedBoxShapeComponent* m_shapeComponent; + + void SetUp() override + { + AZ::ComponentApplication::Descriptor appDesc; + appDesc.m_memoryBlocksByteSize = 20 * 1024 * 1024; + appDesc.m_recordingMode = AZ::Debug::AllocationRecords::RECORD_NO_RECORDS; + appDesc.m_stackRecordLevels = 20; + + m_app.Create(appDesc); + } + + void TearDown() override + { + m_app.Destroy(); + } + + AZStd::unique_ptr CreateEntity() + { + auto entity = AZStd::make_unique(); + entity->Init(); + + return entity; + } +}; + +TEST_F(TerrainMacroMaterialComponentTest, MissingRequiredComponentsActivateFailure) +{ + auto entity = CreateEntity(); + + auto macroMaterialComponent = entity->CreateComponent(); + m_app.RegisterComponentDescriptor(macroMaterialComponent->CreateDescriptor()); + + const AZ::Entity::DependencySortOutcome sortOutcome = entity->EvaluateDependenciesGetDetails(); + EXPECT_FALSE(sortOutcome.IsSuccess()); + + entity.reset(); +} + +TEST_F(TerrainMacroMaterialComponentTest, RequiredComponentsPresentEntityActivateSuccess) +{ + auto entity = CreateEntity(); + + auto macroMaterialComponent = entity->CreateComponent(); + m_app.RegisterComponentDescriptor(macroMaterialComponent->CreateDescriptor()); + + auto shapeComponent = entity->CreateComponent(); + m_app.RegisterComponentDescriptor(shapeComponent->CreateDescriptor()); + + entity->Activate(); + EXPECT_EQ(entity->GetState(), AZ::Entity::State::Active); + + entity.reset(); +} diff --git a/Gems/Terrain/Code/terrain_files.cmake b/Gems/Terrain/Code/terrain_files.cmake index 893477e10d..3feacf6254 100644 --- a/Gems/Terrain/Code/terrain_files.cmake +++ b/Gems/Terrain/Code/terrain_files.cmake @@ -33,6 +33,7 @@ set(FILES Source/TerrainRenderer/TerrainFeatureProcessor.cpp Source/TerrainRenderer/TerrainFeatureProcessor.h Source/TerrainRenderer/TerrainAreaMaterialRequestBus.h + Source/TerrainRenderer/TerrainMacroMaterialBus.cpp Source/TerrainRenderer/TerrainMacroMaterialBus.h Source/TerrainSystem/TerrainSystem.cpp Source/TerrainSystem/TerrainSystem.h diff --git a/Gems/Terrain/Code/terrain_tests_files.cmake b/Gems/Terrain/Code/terrain_tests_files.cmake index 3e37e509a7..88de53f8cf 100644 --- a/Gems/Terrain/Code/terrain_tests_files.cmake +++ b/Gems/Terrain/Code/terrain_tests_files.cmake @@ -14,5 +14,6 @@ set(FILES Tests/SurfaceMaterialsListTest.cpp Tests/MockAxisAlignedBoxShapeComponent.h Tests/TerrainHeightGradientListTests.cpp + Tests/TerrainMacroMaterialTests.cpp Tests/TerrainSurfaceGradientListTests.cpp ) From 502a9e9e19b950157396947a4196db88a7621fd1 Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Tue, 30 Nov 2021 08:13:45 +0000 Subject: [PATCH 047/128] missed file Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- ...aterialComponent_MacroMaterialActivates.py | 166 ++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainMacroMaterialComponent_MacroMaterialActivates.py diff --git a/AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainMacroMaterialComponent_MacroMaterialActivates.py b/AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainMacroMaterialComponent_MacroMaterialActivates.py new file mode 100644 index 0000000000..71ff02739a --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainMacroMaterialComponent_MacroMaterialActivates.py @@ -0,0 +1,166 @@ +""" +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 +""" + +class MacroMaterialTests: + setup_test = ( + "Setup successful", + "Setup failed" + ) + material_changed_not_called_when_inactive = ( + "OnTerrainMacroMaterialRegionChanged not called successfully", + "OnTerrainMacroMaterialRegionChanged called when component inactive." + ) + material_created = ( + "MaterialCreated called successfully", + "MaterialCreated failed" + ) + material_destroyed = ( + "MaterialDestroyed called successfully", + "MaterialDestroyed failed" + ) + material_recreated = ( + "MaterialCreated called successfully on second test", + "MaterialCreated failed on second test" + ) + material_changed_call_on_aabb_change = ( + "OnTerrainMacroMaterialRegionChanged called successfully", + "Timed out waiting for OnTerrainMacroMaterialRegionChanged" + ) + +def TerrainMacroMaterialComponent_MacroMaterialActivates(): + """ + Summary: + Load an empty level, create a MacroMaterialComponent and check assigning textures results in the correct callbacks. + :return: None + """ + + import os + import math as sys_math + + import azlmbr.legacy.general as general + import azlmbr.asset as asset + import azlmbr.bus as bus + import azlmbr.math as math + import azlmbr.terrain as terrain + import azlmbr.editor as editor + import azlmbr.vegetation as vegetation + import azlmbr.entity as EntityId + + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + import editor_python_test_tools.pyside_utils as pyside_utils + from editor_python_test_tools.editor_entity_utils import EditorEntity + from editor_python_test_tools.asset_utils import Asset + + material_created_called = False + material_changed_called = False + material_region_changed_called = False + material_destroyed_called = False + + def create_entity_at(entity_name, components_to_add, x, y, z): + entity = EditorEntity.create_editor_entity_at([x, y, z], entity_name) + for component in components_to_add: + entity.add_component(component) + + return entity + + def on_macro_material_created(args): + nonlocal material_created_called + material_created_called = True + + def on_macro_material_changed(args): + nonlocal material_changed_called + material_changed_called = True + + def on_macro_material_region_changed(args): + nonlocal material_region_changed_called + material_region_changed_called = True + + def on_macro_material_destroyed(args): + nonlocal material_destroyed_called + material_destroyed_called = True + + helper.init_idle() + + # Open a level. + helper.open_level("Physics", "Base") + helper.wait_for_condition(lambda: general.get_current_level_name() == "Base", 2.0) + + general.idle_wait_frames(1) + + # Set up a handler to wait for notifications from the TerrainSystem. + handler = terrain.TerrainMacroMaterialAutomationBusHandler() + handler.connect() + handler.add_callback("OnTerrainMacroMaterialCreated", on_macro_material_created) + handler.add_callback("OnTerrainMacroMaterialChanged", on_macro_material_changed) + handler.add_callback("OnTerrainMacroMaterialRegionChanged", on_macro_material_region_changed) + handler.add_callback("OnTerrainMacroMaterialDestroyed", on_macro_material_destroyed) + + macro_material_entity = create_entity_at("macro", ["Terrain Macro Material", "Axis Aligned Box Shape"], 0.0, 0.0, 0.0) + + # Check that no macro material callbacks happened. It should be "inactive" as it has no assets assigned. + setup_success = not material_created_called and not material_changed_called and not material_region_changed_called and not material_destroyed_called + Report.result(MacroMaterialTests.setup_test, setup_success) + + # Find the aabb component. + aabb_component_type_id_type = azlmbr.editor.EditorComponentAPIBus(azlmbr.bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Axis Aligned Box Shape"], 0)[0] + aabb_component_id = azlmbr.editor.EditorComponentAPIBus(azlmbr.bus.Broadcast, 'GetComponentOfType', macro_material_entity.id, aabb_component_type_id_type).GetValue() + + # Change the aabb dimensions + material_region_changed_called = False + box_dimensions_path = "Axis Aligned Box Shape|Box Configuration|Dimensions" + editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", aabb_component_id, box_dimensions_path, math.Vector3(1.0, 1.0, 1.0)) + + # Check we don't receive a callback. The macro material component should be inactive as it has no images assigned. + general.idle_wait_frames(1) + Report.result(MacroMaterialTests.material_changed_not_called_when_inactive, material_region_changed_called == False) + + # Find the macro material component. + macro_material_id_type = azlmbr.editor.EditorComponentAPIBus(azlmbr.bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Terrain Macro Material"], 0)[0] + macro_material_component_id = azlmbr.editor.EditorComponentAPIBus(azlmbr.bus.Broadcast, 'GetComponentOfType', macro_material_entity.id, macro_material_id_type).GetValue() + + # Find a color image asset. + color_image_path = os.path.join("assets", "textures", "image.png.streamingimage") + color_image_asset = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", color_image_path, math.Uuid(), False) + + # Assign the image to the MacroMaterial component, which should result in a created message. + material_created_called = False + color_texture_path = "Configuration|Color Texture" + editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", macro_material_component_id, color_texture_path, color_image_asset) + + call_result = helper.wait_for_condition(lambda: material_created_called == True, 2.0) + Report.result(MacroMaterialTests.material_created, call_result) + + # Find a normal image asset. + normal_image_path = os.path.join("assets", "textures", "normal.png.streamingimage") + normal_image_asset = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", normal_image_path, math.Uuid(), False) + + # Assign the normal image to the MacroMaterial component, which should result in a created message. + material_created_called = False + material_destroyed_called = False + normal_texture_path = "Configuration|Normal Texture" + editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", macro_material_component_id, normal_texture_path, normal_image_asset) + + # Check the MacroMaterial was destroyed and recreated. + destroyed_call_result = helper.wait_for_condition(lambda: material_destroyed_called == True, 2.0) + Report.result(MacroMaterialTests.material_destroyed, destroyed_call_result) + + recreated_call_result = helper.wait_for_condition(lambda: material_created_called == True, 2.0) + Report.result(MacroMaterialTests.material_recreated, recreated_call_result) + + # Change the aabb dimensions. + box_dimensions_path = "Axis Aligned Box Shape|Box Configuration|Dimensions" + editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", aabb_component_id, box_dimensions_path, math.Vector3(1.0, 1.0, 1.0)) + + # Check that a callback is received. + region_changed_call_result = helper.wait_for_condition(lambda: material_region_changed_called == True, 2.0) + Report.result(MacroMaterialTests.material_changed_call_on_aabb_change, region_changed_call_result) + +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(TerrainMacroMaterialComponent_MacroMaterialActivates) \ No newline at end of file From 5dbe9e387b3fc827aa2f7598f116e7f78a87faa9 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Tue, 30 Nov 2021 12:10:16 -0800 Subject: [PATCH 048/128] Address some review feedback, remove DomBackendRegistry Signed-off-by: Nicholas Van Sickle --- .../AzCore/DOM/Backends/JSON/JsonBackend.cpp | 12 +- .../AzCore/DOM/Backends/JSON/JsonBackend.h | 8 +- .../Backends/JSON/JsonSerializationUtils.cpp | 228 +++++++++--------- .../Backends/JSON/JsonSerializationUtils.h | 4 +- .../AzCore/AzCore/DOM/DomBackend.cpp | 34 +-- Code/Framework/AzCore/AzCore/DOM/DomBackend.h | 9 +- .../AzCore/AzCore/DOM/DomBackendRegistry.cpp | 68 ------ .../AzCore/AzCore/DOM/DomBackendRegistry.h | 44 ---- .../AzCore/DOM/DomBackendRegistryInterface.h | 54 ----- .../AzCore/AzCore/DOM/DomVisitor.cpp | 4 +- Code/Framework/AzCore/AzCore/DOM/DomVisitor.h | 4 +- .../AzCore/AzCore/azcore_files.cmake | 3 - .../AzCore/Tests/DOM/DomJsonBenchmarks.cpp | 26 +- .../AzCore/Tests/DOM/DomJsonTests.cpp | 14 +- 14 files changed, 150 insertions(+), 362 deletions(-) delete mode 100644 Code/Framework/AzCore/AzCore/DOM/DomBackendRegistry.cpp delete mode 100644 Code/Framework/AzCore/AzCore/DOM/DomBackendRegistry.h delete mode 100644 Code/Framework/AzCore/AzCore/DOM/DomBackendRegistryInterface.h diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.cpp b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.cpp index 4abeeaf07e..db7b209310 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.cpp @@ -8,9 +8,7 @@ #include -#include - -namespace AZ::DOM +namespace AZ::Dom { Visitor::Result JsonBackend::ReadFromStringInPlace(AZStd::string& buffer, Visitor* visitor) { @@ -26,12 +24,4 @@ namespace AZ::DOM { return Json::GetJsonStreamWriter(stream, Json::OutputFormatting::PrettyPrintedJson); } - - void JsonBackend::Register() - { - if (auto backendRegistry = BackendRegistry::Get()) - { - backendRegistry->RegisterBackend(kName, {kExtension}); - } - } } diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h index 5e93ece1de..9de3db573d 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h @@ -11,7 +11,7 @@ #include #include -namespace AZ::DOM +namespace AZ::Dom { class JsonBackend final : public Backend { @@ -19,9 +19,5 @@ namespace AZ::DOM Visitor::Result ReadFromStringInPlace(AZStd::string& buffer, Visitor* visitor) override; Visitor::Result ReadFromString(AZStd::string_view buffer, Lifetime lifetime, Visitor* visitor) override; AZStd::unique_ptr CreateStreamWriter(AZ::IO::GenericStream* stream) override; - - static constexpr const char* kName = "JSON"; - static constexpr const char* kExtension = ".json"; - static void Register(); }; -} // namespace AZ::DOM +} // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp index aa0b24a5ad..4cdf680aff 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp @@ -21,7 +21,7 @@ #include #include -namespace AZ::DOM::Json +namespace AZ::Dom::Json { // // class DocumentWriter @@ -73,7 +73,7 @@ namespace AZ::DOM::Json } else { - CurrentValue().SetString(value.data(), static_cast(value.size())); + CurrentValue().SetString(value.data(), static_cast(value.length())); } return FinishWrite(); } @@ -210,11 +210,11 @@ namespace AZ::DOM::Json { } - bool m_isObject; - rapidjson::Value& m_container; - rapidjson::Value m_value; - AZ::u64 m_entryCount = 0; rapidjson::Value m_key; + rapidjson::Value m_value; + rapidjson::Value& m_container; + AZ::u64 m_entryCount = 0; + bool m_isObject; }; rapidjson::Document m_result; @@ -225,13 +225,13 @@ namespace AZ::DOM::Json // class StreamWriter // // Visitor that writes to a rapidjson::Writer - template + template class StreamWriter : public Visitor { public: StreamWriter(AZ::IO::GenericStream* stream) : m_streamWriter(stream) - , m_writer(TWriter(m_streamWriter)) + , m_writer(Writer(m_streamWriter)) { } @@ -305,22 +305,25 @@ namespace AZ::DOM::Json private: Result CheckWrite(bool writeSucceeded) { - if (!writeSucceeded) + if (writeSucceeded) + { + return VisitorSuccess(); + } + else { return VisitorFailure(VisitorErrorCode::InternalError, "Failed to write JSON"); } - return VisitorSuccess(); } AZ::IO::RapidJSONStreamWriter m_streamWriter; - TWriter m_writer; + Writer m_writer; }; // // struct JsonReadHandler // - // Handler for a rapidjson::Reader that translates reads into an AZ::DOM::Visitor - struct JsonReadHandler : public rapidjson::BaseReaderHandler, JsonReadHandler> + // Handler for a rapidjson::Reader that translates reads into an AZ::Dom::Visitor + struct JsonReadHandler { public: JsonReadHandler(Visitor* visitor, Lifetime stringLifetime) @@ -365,13 +368,13 @@ namespace AZ::DOM::Json return CheckResult(m_visitor->Double(d)); } - bool RawNumber([[maybe_unused]] const Ch* str, [[maybe_unused]] rapidjson::SizeType length, [[maybe_unused]] bool copy) + bool RawNumber([[maybe_unused]] const char* str, [[maybe_unused]] rapidjson::SizeType length, [[maybe_unused]] bool copy) { - AZ_Assert(false, "Raw numbers are unsupported"); + AZ_Assert(false, "Raw numbers are unsupported in the rapidjson DOM backend"); return false; } - bool String(const Ch* str, rapidjson::SizeType length, bool copy) + bool String(const char* str, rapidjson::SizeType length, bool copy) { Lifetime lifetime = m_stringLifetime; if (!copy) @@ -386,7 +389,7 @@ namespace AZ::DOM::Json return CheckResult(m_visitor->StartObject()); } - bool Key(const Ch* str, rapidjson::SizeType length, [[maybe_unused]] bool copy) + bool Key(const char* str, rapidjson::SizeType length, [[maybe_unused]] bool copy) { AZStd::string_view key = AZStd::string_view(str, length); if (!m_visitor->SupportsRawKeys()) @@ -552,17 +555,18 @@ namespace AZ::DOM::Json Visitor::Result VisitRapidJsonValue(const rapidjson::Value& value, Visitor* visitor, Lifetime lifetime) { - enum class EndMarker + struct EndArrayMarker + { + }; + struct EndObjectMarker { - EndArray, - EndObject }; // Processing stack consists of values comprised of one of a: // - rapidjson::Value to process - // - EndMarker denoting the end of an array or object + // - EndArrayMarker or EndObjectMarker denoting the end of an array or object // - string denoting a key at the beginning of a key/value pair - using Entry = AZStd::variant; + using Entry = AZStd::variant; AZStd::stack entryStack; AZStd::stack entryCountStack; entryStack.push(&value); @@ -572,97 +576,99 @@ namespace AZ::DOM::Json const auto currentEntry = entryStack.top(); entryStack.pop(); - if (AZStd::holds_alternative(currentEntry)) - { - EndMarker marker = AZStd::get(currentEntry); - if (marker == EndMarker::EndArray) - { - visitor->EndArray(entryCountStack.top()); - } - else - { - visitor->EndObject(entryCountStack.top()); - } - entryCountStack.pop(); - continue; - } - - if (AZStd::holds_alternative(currentEntry)) - { - AZStd::string_view key = AZStd::get(currentEntry); - if (visitor->SupportsRawKeys()) - { - visitor->RawKey(key, lifetime); - } - else - { - visitor->Key(AZ::Name(key)); - } - continue; - } - - const rapidjson::Value& currentValue = *AZStd::get(currentEntry); - if (!entryCountStack.empty()) - { - ++entryCountStack.top(); - } - Visitor::Result result = AZ::Success(); - switch (currentValue.GetType()) - { - case rapidjson::kNullType: - result = visitor->Null(); - break; - case rapidjson::kFalseType: - result = visitor->Bool(false); - break; - case rapidjson::kTrueType: - result = visitor->Bool(true); - break; - case rapidjson::kObjectType: - entryStack.push(EndMarker::EndObject); - entryCountStack.push(0); - result = visitor->StartObject(); - for (auto it = currentValue.MemberEnd(); it != currentValue.MemberBegin(); --it) + AZStd::visit( + [visitor, &entryStack, &entryCountStack, &result, lifetime](auto&& arg) { - auto entry = (it - 1); - const AZStd::string_view key(entry->name.GetString(), static_cast(entry->name.GetStringLength())); - entryStack.push(&entry->value); - entryStack.push(key); - } - break; - case rapidjson::kArrayType: - entryStack.push(EndMarker::EndArray); - entryCountStack.push(0); - result = visitor->StartArray(); - for (auto it = currentValue.End(); it != currentValue.Begin(); --it) - { - auto entry = (it - 1); - entryStack.push(entry); - } - break; - case rapidjson::kStringType: - result = visitor->String( - AZStd::string_view(currentValue.GetString(), static_cast(currentValue.GetStringLength())), lifetime); - break; - case rapidjson::kNumberType: - if (currentValue.IsFloat() || currentValue.IsDouble()) - { - result = visitor->Double(currentValue.GetDouble()); - } - else if (currentValue.IsInt64() || currentValue.IsInt()) - { - result = visitor->Int64(currentValue.GetInt64()); - } - else - { - result = visitor->Uint64(currentValue.GetUint64()); - } - break; - default: - return AZ::Failure(VisitorError(VisitorErrorCode::InvalidData, "Value with invalid type specified")); - } + using Alternative = AZStd::decay_t; + if constexpr (AZStd::is_same_v) + { + const rapidjson::Value& currentValue = *arg; + if (!entryCountStack.empty()) + { + ++entryCountStack.top(); + } + + switch (currentValue.GetType()) + { + case rapidjson::kNullType: + result = visitor->Null(); + break; + case rapidjson::kFalseType: + result = visitor->Bool(false); + break; + case rapidjson::kTrueType: + result = visitor->Bool(true); + break; + case rapidjson::kObjectType: + entryStack.push(EndObjectMarker{}); + entryCountStack.push(0); + result = visitor->StartObject(); + for (auto it = currentValue.MemberEnd(); it != currentValue.MemberBegin(); --it) + { + auto entry = (it - 1); + const AZStd::string_view key(entry->name.GetString(), static_cast(entry->name.GetStringLength())); + entryStack.push(&entry->value); + entryStack.push(key); + } + break; + case rapidjson::kArrayType: + entryStack.push(EndArrayMarker{}); + entryCountStack.push(0); + result = visitor->StartArray(); + for (auto it = currentValue.End(); it != currentValue.Begin(); --it) + { + auto entry = (it - 1); + entryStack.push(entry); + } + break; + case rapidjson::kStringType: + result = visitor->String( + AZStd::string_view(currentValue.GetString(), static_cast(currentValue.GetStringLength())), + lifetime); + break; + case rapidjson::kNumberType: + if (currentValue.IsFloat() || currentValue.IsDouble()) + { + result = visitor->Double(currentValue.GetDouble()); + } + else if (currentValue.IsInt64() || currentValue.IsInt()) + { + result = visitor->Int64(currentValue.GetInt64()); + } + else + { + result = visitor->Uint64(currentValue.GetUint64()); + } + break; + default: + result = AZ::Failure(VisitorError(VisitorErrorCode::InvalidData, "Value with invalid type specified")); + } + } + else if constexpr (AZStd::is_same_v) + { + result = visitor->EndArray(entryCountStack.top()); + entryCountStack.pop(); + } + else if constexpr (AZStd::is_same_v) + { + result = visitor->EndObject(entryCountStack.top()); + entryCountStack.pop(); + } + else if constexpr (AZStd::is_same_v) + { + if (visitor->SupportsRawKeys()) + { + visitor->RawKey(arg, lifetime); + } + else + { + visitor->Key(AZ::Name(arg)); + } + } + }, + currentEntry); if (!result.IsSuccess()) { @@ -672,4 +678,4 @@ namespace AZ::DOM::Json return AZ::Success(); } -} // namespace AZ::DOM::Json +} // namespace AZ::Dom::Json diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h index 323e0b880c..1f9b58ac51 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h @@ -16,7 +16,7 @@ #include #include -namespace AZ::DOM::Json +namespace AZ::Dom::Json { //! Specifies how JSON should be formatted when serialized. enum class OutputFormatting @@ -57,4 +57,4 @@ namespace AZ::DOM::Json //! before the visitor is finished using these values, Lifetime::Temporary should be specified. //! \return The aggregate result specifying whether the visitor operations were successful. Visitor::Result VisitRapidJsonValue(const rapidjson::Value& value, Visitor* visitor, Lifetime lifetime); -} // namespace AZ::DOM::Json +} // namespace AZ::Dom::Json diff --git a/Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp b/Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp index f26e34acdf..925897c299 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp @@ -12,20 +12,8 @@ #include #include "DomBackend.h" -namespace AZ::DOM +namespace AZ::Dom { - Visitor::Result Backend::ReadFromPath(AZ::IO::PathView pathName, Visitor* visitor, size_t maxFileSize) - { - auto readResult = AZ::Utils::ReadFile(pathName.Native(), maxFileSize); - if (!readResult.IsSuccess()) - { - return AZ::Failure(VisitorError(VisitorErrorCode::InternalError, readResult.TakeError())); - } - - AZStd::string fileContents = readResult.TakeValue(); - return ReadFromString(fileContents, Lifetime::Temporary, visitor); - } - Visitor::Result Backend::ReadFromStream(AZ::IO::GenericStream* stream, Visitor* visitor, size_t maxSize) { size_t length = stream->GetLength(); @@ -34,7 +22,7 @@ namespace AZ::DOM return AZ::Failure(VisitorError(VisitorErrorCode::InternalError, "Stream is too large.")); } AZStd::string buffer; - buffer.resize(maxSize); + buffer.resize(length); stream->Read(length, buffer.data()); return ReadFromString(buffer, Lifetime::Temporary, visitor); } @@ -50,24 +38,6 @@ namespace AZ::DOM return callback(writer.get()); } - Visitor::Result Backend::WriteToPath(AZ::IO::PathView pathName, WriteCallback callback) - { - AZStd::string buffer; - auto serializeResult = WriteToString(buffer, callback); - if (!serializeResult.IsSuccess()) - { - return serializeResult; - } - - auto writeResult = AZ::Utils::WriteFile(buffer, pathName.Native()); - if (!writeResult.IsSuccess()) - { - return AZ::Failure(VisitorError(VisitorErrorCode::InternalError, writeResult.TakeError())); - } - - return AZ::Success(); - } - Visitor::Result Backend::WriteToString(AZStd::string& buffer, WriteCallback callback) { AZ::IO::ByteContainerStream stream{&buffer}; diff --git a/Code/Framework/AzCore/AzCore/DOM/DomBackend.h b/Code/Framework/AzCore/AzCore/DOM/DomBackend.h index bb5c9e40fe..d11335262e 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomBackend.h +++ b/Code/Framework/AzCore/AzCore/DOM/DomBackend.h @@ -14,7 +14,7 @@ #include #include -namespace AZ::DOM +namespace AZ::Dom { //! Backends are registered centrally and used to transition DOM formats to and from a textual format. class Backend @@ -22,9 +22,6 @@ namespace AZ::DOM public: virtual ~Backend() = default; - //! Attempt to read this format from the given file into the target Visitor. - Visitor::Result ReadFromPath( - AZ::IO::PathView pathName, Visitor* visitor, size_t maxFileSize = AZStd::numeric_limits::max()); //! Attempt to read this format from the given stream into the target Visitor. //! The base implementation reads the stream into memory and calls ReadFromString. virtual Visitor::Result ReadFromStream( @@ -46,9 +43,7 @@ namespace AZ::DOM using WriteCallback = AZStd::function; //! Attempt to write a value to a stream using a write callback. Visitor::Result WriteToStream(AZ::IO::GenericStream* stream, WriteCallback callback); - //! Attempt to write a value to a file using a write callback. - Visitor::Result WriteToPath(AZ::IO::PathView pathName, WriteCallback callback); //! Attempt to write a value to a string using a write callback. Visitor::Result WriteToString(AZStd::string& buffer, WriteCallback callback); }; -} // namespace AZ::DOM +} // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/DomBackendRegistry.cpp b/Code/Framework/AzCore/AzCore/DOM/DomBackendRegistry.cpp deleted file mode 100644 index c8f4050602..0000000000 --- a/Code/Framework/AzCore/AzCore/DOM/DomBackendRegistry.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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 - -namespace AZ::DOM -{ - BackendRegistry* BackendRegistry::s_instance = nullptr; - - BackendRegistryInterface* BackendRegistry::Get() - { - return AZ::Interface::Get(); - } - - void BackendRegistry::Create() - { - AZ_Assert(!s_instance, "Attempted to register BackendRegistry when it's already registered"); - s_instance = aznew BackendRegistry; - AZ::Interface::Register(s_instance); - } - - void BackendRegistry::Destroy() - { - AZ_Assert(s_instance, "Attempted to unregister a non-existent BackendRegistry"); - AZ::Interface::Unregister(s_instance); - delete s_instance; - s_instance = nullptr; - } - - AZStd::unique_ptr BackendRegistry::GetBackendByName(AZStd::string_view name) - { - auto backendIterator = m_nameToBackend.find(name); - if (backendIterator != m_nameToBackend.end()) - { - return backendIterator->second(); - } - return nullptr; - } - - AZStd::unique_ptr BackendRegistry::GetBackendForExtension(AZStd::string_view extension) - { - auto extensionIterator = m_extensionToName.find(extension); - if (extensionIterator != m_extensionToName.end()) - { - return GetBackendByName(extensionIterator->second); - } - return nullptr; - } - - void BackendRegistry::RegisterBackendInternal( - BackendRegistryInterface::BackendFactory factory, AZStd::string name, AZStd::vector extensions) - { - AZ_Assert(m_nameToBackend.find(name) == m_nameToBackend.end(), "DOM Backend %s already registered", name.c_str()); - m_nameToBackend.insert({name, factory}); - for (AZStd::string& extension : extensions) - { - AZ_Assert(m_extensionToName.find(extension) == m_extensionToName.end(), "DOM Extensions already registered", extension.c_str()); - m_extensionToName.insert({AZStd::move(extension), name}); - } - } -} diff --git a/Code/Framework/AzCore/AzCore/DOM/DomBackendRegistry.h b/Code/Framework/AzCore/AzCore/DOM/DomBackendRegistry.h deleted file mode 100644 index c71e6798fc..0000000000 --- a/Code/Framework/AzCore/AzCore/DOM/DomBackendRegistry.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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 - -namespace AZ::DOM -{ - //! DOM backend registry implementation. - //! \see BackendRegistryInterface - class BackendRegistry final : public BackendRegistryInterface - { - public: - AZ_RTTI(BackendRegistry, "{95533861-6201-4E45-BD03-097A20850C48}", BackendRegistryInterface); - AZ_CLASS_ALLOCATOR(BackendRegistry, AZ::SystemAllocator, 0); - - AZStd::unique_ptr GetBackendByName(AZStd::string_view name) override; - AZStd::unique_ptr GetBackendForExtension(AZStd::string_view extension) override; - - //! Convenience method, gets the current instance of the BackendRegistry via AZ::Interface. - static BackendRegistryInterface* Get(); - //! Creates a singleton BackendRegistry and registers it via AZ::Interface. - static void Create(); - //! Destroys the singleton BackendRegistry created by Create and unregisters it from AZ::Interface. - static void Destroy(); - - protected: - void RegisterBackendInternal(BackendFactory factory, AZStd::string name, AZStd::vector extensions) override; - - private: - using BackendFactory = AZStd::function()>; - AZStd::unordered_map m_nameToBackend; - AZStd::unordered_map m_extensionToName; - - static BackendRegistry* s_instance; - }; -} // namespace AZ::DOM diff --git a/Code/Framework/AzCore/AzCore/DOM/DomBackendRegistryInterface.h b/Code/Framework/AzCore/AzCore/DOM/DomBackendRegistryInterface.h deleted file mode 100644 index 4651f35961..0000000000 --- a/Code/Framework/AzCore/AzCore/DOM/DomBackendRegistryInterface.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 - -namespace AZ::DOM -{ - //! Central interface for registering and looking up backend types by file extension. - class BackendRegistryInterface - { - public: - AZ_RTTI(BackendRegistryInterface, "{B72A88AC-DF15-4F92-9489-ABCDEA3D94E6}") - using BackendFactory = AZStd::function()>; - - virtual ~BackendRegistryInterface() = default; - - //! Registers a factory for a given backend. - //! \param name A unique name to identify this backend. - //! \param extensions A set of file extensions this backend supports. - //! Extensions should by the entire file suffix including any dots (.), for example: - //! ".json" or ".tar.gz" - template - void RegisterBackend(AZStd::string name, AZStd::vector extensions); - - //! Looks up a DOM backend based on its name. - virtual AZStd::unique_ptr GetBackendByName(AZStd::string_view name) = 0; - - //! Looks up a DOM backend based on a file extension. - virtual AZStd::unique_ptr GetBackendForExtension(AZStd::string_view extension) = 0; - - protected: - //! Registers a factory for a given backend, called by RegisterBackend. - //! \param factory The factory function to create new backend instances. - //! \param name The unique name to identify this backend. - //! \param extensions A set of file extensions this backend supports. - //! \see RegisterBackend - virtual void RegisterBackendInternal(BackendFactory factory, AZStd::string name, AZStd::vector extensions) = 0; - }; - - template - void BackendRegistryInterface::RegisterBackend(AZStd::string name, AZStd::vector extensions) - { - RegisterBackendInternal([](){ - return AZStd::make_unique(); - }, AZStd::move(name), AZStd::move(extensions)); - } -} // namespace AZ::DOM diff --git a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp index 5d66bb6ac5..ad314da385 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp @@ -8,7 +8,7 @@ #include -namespace AZ::DOM +namespace AZ::Dom { const char* VisitorError::CodeToString(VisitorErrorCode code) { @@ -236,4 +236,4 @@ namespace AZ::DOM { return (GetVisitorFlags() & VisitorFlags::SupportsOpaqueValues) != VisitorFlags::Null; } -} // namespace AZ::DOM +} // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h index eb6f20ae1b..f36ad8d827 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h +++ b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h @@ -13,7 +13,7 @@ #include #include -namespace AZ::DOM +namespace AZ::Dom { // // Lifetime enum @@ -243,4 +243,4 @@ namespace AZ::DOM //! Helper method, constructs a success \ref Result. static Result VisitorSuccess(); }; -} // namespace AZ::DOM +} // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index aa5d49dccc..ecc7a41ba1 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -127,9 +127,6 @@ set(FILES Debug/TraceReflection.h DOM/DomBackend.cpp DOM/DomBackend.h - DOM/DomBackendRegistry.cpp - DOM/DomBackendRegistry.h - DOM/DomBackendRegistryInterface.h DOM/DomVisitor.cpp DOM/DomVisitor.h DOM/Backends/JSON/JsonBackend.cpp diff --git a/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp b/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp index 238802a35f..4596316213 100644 --- a/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp +++ b/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp @@ -20,31 +20,31 @@ namespace Benchmark class DomJsonBenchmark : public UnitTest::AllocatorsBenchmarkFixture { public: - void SetUp([[maybe_unused]] const ::benchmark::State& st) override + void SetUp(const ::benchmark::State& st) override { UnitTest::AllocatorsBenchmarkFixture::SetUp(st); AZ::NameDictionary::Create(); } - void SetUp([[maybe_unused]] ::benchmark::State& st) override + void SetUp(::benchmark::State& st) override { UnitTest::AllocatorsBenchmarkFixture::SetUp(st); AZ::NameDictionary::Create(); } - void TearDown([[maybe_unused]] ::benchmark::State& st) override + void TearDown(::benchmark::State& st) override { AZ::NameDictionary::Destroy(); UnitTest::AllocatorsBenchmarkFixture::TearDown(st); } - void TearDown([[maybe_unused]] const ::benchmark::State& st) override + void TearDown(const ::benchmark::State& st) override { AZ::NameDictionary::Destroy(); UnitTest::AllocatorsBenchmarkFixture::TearDown(st); } - AZStd::string GenerateDomJsonBenchmarkPayload(int64_t entryCount = 100, int64_t stringTemplateLength = 5) + AZStd::string GenerateDomJsonBenchmarkPayload(int64_t entryCount, int64_t stringTemplateLength) { rapidjson::Document document; document.SetObject(); @@ -120,7 +120,7 @@ namespace Benchmark BENCHMARK_DEFINE_F(DomJsonBenchmark, DomDeserializeToDocumentInPlace)(benchmark::State& state) { - AZ::DOM::JsonBackend backend; + AZ::Dom::JsonBackend backend; AZStd::string serializedPayload = GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1)); for (auto _ : state) @@ -129,8 +129,8 @@ namespace Benchmark AZStd::string payloadCopy = serializedPayload; state.ResumeTiming(); - auto result = AZ::DOM::Json::WriteToRapidJsonDocument( - [&](AZ::DOM::Visitor* visitor) + auto result = AZ::Dom::Json::WriteToRapidJsonDocument( + [&](AZ::Dom::Visitor* visitor) { return backend.ReadFromStringInPlace(payloadCopy, visitor); }); @@ -144,15 +144,15 @@ namespace Benchmark BENCHMARK_DEFINE_F(DomJsonBenchmark, DomDeserializeToDocument)(benchmark::State& state) { - AZ::DOM::JsonBackend backend; + AZ::Dom::JsonBackend backend; AZStd::string serializedPayload = GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1)); for (auto _ : state) { - auto result = AZ::DOM::Json::WriteToRapidJsonDocument( - [&](AZ::DOM::Visitor* visitor) + auto result = AZ::Dom::Json::WriteToRapidJsonDocument( + [&](AZ::Dom::Visitor* visitor) { - return backend.ReadFromString(serializedPayload, AZ::DOM::Lifetime::Temporary, visitor); + return backend.ReadFromString(serializedPayload, AZ::Dom::Lifetime::Temporary, visitor); }); benchmark::DoNotOptimize(result.GetValue()); @@ -164,7 +164,7 @@ namespace Benchmark BENCHMARK_DEFINE_F(DomJsonBenchmark, JsonUtilsDeserializeToDocument)(benchmark::State& state) { - AZ::DOM::JsonBackend backend; + AZ::Dom::JsonBackend backend; AZStd::string serializedPayload = GenerateDomJsonBenchmarkPayload(state.range(0), state.range(1)); for (auto _ : state) diff --git a/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp b/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp index e778a449d5..25deeb8a82 100644 --- a/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp +++ b/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp @@ -12,7 +12,7 @@ #include #include -namespace AZ::DOM::Tests +namespace AZ::Dom::Tests { class DomJsonTests : public UnitTest::AllocatorsFixture { @@ -125,7 +125,7 @@ namespace AZ::DOM::Tests AZStd::string canonicalSerializedDocument; AZ::JsonSerializationUtils::WriteJsonString(*m_document, canonicalSerializedDocument); - auto visitDocumentFn = [this](AZ::DOM::Visitor* visitor) + auto visitDocumentFn = [this](AZ::Dom::Visitor* visitor) { return Json::VisitRapidJsonValue(*m_document, visitor, Lifetime::Persistent); }; @@ -149,10 +149,10 @@ namespace AZ::DOM::Tests // string -> Document { auto result = Json::WriteToRapidJsonDocument( - [&canonicalSerializedDocument](AZ::DOM::Visitor* visitor) + [&canonicalSerializedDocument](AZ::Dom::Visitor* visitor) { JsonBackend backend; - return backend.ReadFromString(canonicalSerializedDocument, AZ::DOM::Lifetime::Temporary, visitor); + return backend.ReadFromString(canonicalSerializedDocument, AZ::Dom::Lifetime::Temporary, visitor); }); EXPECT_TRUE(result.IsSuccess()); EXPECT_TRUE(DeepCompare(*m_document, result.GetValue())); @@ -164,9 +164,9 @@ namespace AZ::DOM::Tests JsonBackend backend; auto result = backend.WriteToString( serializedDocument, - [&backend, &canonicalSerializedDocument](AZ::DOM::Visitor* visitor) + [&backend, &canonicalSerializedDocument](AZ::Dom::Visitor* visitor) { - return backend.ReadFromString(canonicalSerializedDocument, AZ::DOM::Lifetime::Temporary, visitor); + return backend.ReadFromString(canonicalSerializedDocument, AZ::Dom::Lifetime::Temporary, visitor); }); EXPECT_TRUE(result.IsSuccess()); EXPECT_EQ(canonicalSerializedDocument, serializedDocument); @@ -285,4 +285,4 @@ namespace AZ::DOM::Tests m_document->AddMember(CreateString("long_string"), CreateString("abcdefghijklmnopqrstuvwxyz0123456789"), m_document->GetAllocator()); PerformSerializationChecks(); } -} // namespace AZ::DOM::Tests +} // namespace AZ::Dom::Tests From a9c05372d526f35af31ae5906793f71fdcd4ea3e Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Tue, 30 Nov 2021 18:00:59 -0800 Subject: [PATCH 049/128] API tweaks - Use ref types - Support using rapidjson::Value in lieu of rapidjson::Document - Use the existing JSON comparison util function in tests Signed-off-by: Nicholas Van Sickle --- .../AzCore/DOM/Backends/JSON/JsonBackend.cpp | 6 +- .../AzCore/DOM/Backends/JSON/JsonBackend.h | 6 +- .../Backends/JSON/JsonSerializationUtils.cpp | 374 +++++++++--------- .../Backends/JSON/JsonSerializationUtils.h | 57 ++- .../AzCore/AzCore/DOM/DomBackend.cpp | 14 +- Code/Framework/AzCore/AzCore/DOM/DomBackend.h | 12 +- .../AzCore/Tests/DOM/DomJsonBenchmarks.cpp | 4 +- .../AzCore/Tests/DOM/DomJsonTests.cpp | 88 +---- 8 files changed, 265 insertions(+), 296 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.cpp b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.cpp index db7b209310..288d3c0699 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.cpp @@ -10,17 +10,17 @@ namespace AZ::Dom { - Visitor::Result JsonBackend::ReadFromStringInPlace(AZStd::string& buffer, Visitor* visitor) + Visitor::Result JsonBackend::ReadFromStringInPlace(AZStd::string& buffer, Visitor& visitor) { return Json::VisitSerializedJsonInPlace(buffer, visitor); } - Visitor::Result JsonBackend::ReadFromString(AZStd::string_view buffer, Lifetime lifetime, Visitor* visitor) + Visitor::Result JsonBackend::ReadFromString(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor) { return Json::VisitSerializedJson(buffer, lifetime, visitor); } - AZStd::unique_ptr JsonBackend::CreateStreamWriter(AZ::IO::GenericStream* stream) + AZStd::unique_ptr JsonBackend::CreateStreamWriter(AZ::IO::GenericStream& stream) { return Json::GetJsonStreamWriter(stream, Json::OutputFormatting::PrettyPrintedJson); } diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h index 9de3db573d..536fec7418 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h @@ -16,8 +16,8 @@ namespace AZ::Dom class JsonBackend final : public Backend { public: - Visitor::Result ReadFromStringInPlace(AZStd::string& buffer, Visitor* visitor) override; - Visitor::Result ReadFromString(AZStd::string_view buffer, Lifetime lifetime, Visitor* visitor) override; - AZStd::unique_ptr CreateStreamWriter(AZ::IO::GenericStream* stream) override; + Visitor::Result ReadFromStringInPlace(AZStd::string& buffer, Visitor& visitor) override; + Visitor::Result ReadFromString(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor) override; + AZStd::unique_ptr CreateStreamWriter(AZ::IO::GenericStream& stream) override; }; } // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp index 4cdf680aff..743ef3df43 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -24,202 +23,185 @@ namespace AZ::Dom::Json { // - // class DocumentWriter + // class RapidJsonValueWriter // - // Visitor that produces a rapidjson::Document - class DocumentWriter final : public Visitor + RapidJsonValueWriter::RapidJsonValueWriter(rapidjson::Value& outputValue, rapidjson::Value::AllocatorType& allocator) + : m_result(outputValue) + , m_allocator(allocator) { - public: - VisitorFlags GetVisitorFlags() const override + } + + VisitorFlags RapidJsonValueWriter::GetVisitorFlags() const + { + return VisitorFlags::SupportsRawKeys | VisitorFlags::SupportsArrays | VisitorFlags::SupportsObjects; + } + + Visitor::Result RapidJsonValueWriter::Null() + { + CurrentValue().SetNull(); + return FinishWrite(); + } + + Visitor::Result RapidJsonValueWriter::Bool(bool value) + { + CurrentValue().SetBool(value); + return FinishWrite(); + } + + Visitor::Result RapidJsonValueWriter::Int64(AZ::s64 value) + { + CurrentValue().SetInt64(value); + return FinishWrite(); + } + + Visitor::Result RapidJsonValueWriter::Uint64(AZ::u64 value) + { + CurrentValue().SetUint64(value); + return FinishWrite(); + } + + Visitor::Result RapidJsonValueWriter::Double(double value) + { + CurrentValue().SetDouble(value); + return FinishWrite(); + } + + Visitor::Result RapidJsonValueWriter::String(AZStd::string_view value, Lifetime lifetime) + { + if (lifetime == Lifetime::Temporary) { - return VisitorFlags::SupportsRawKeys | VisitorFlags::SupportsArrays | VisitorFlags::SupportsObjects; + CurrentValue().SetString(value.data(), static_cast(value.length()), m_allocator); + } + else + { + CurrentValue().SetString(value.data(), static_cast(value.length())); + } + return FinishWrite(); + } + + Visitor::Result RapidJsonValueWriter::StartObject() + { + CurrentValue().SetObject(); + + const bool isObject = true; + m_entryStack.emplace_front(isObject, CurrentValue()); + return VisitorSuccess(); + } + + Visitor::Result RapidJsonValueWriter::EndObject(AZ::u64 attributeCount) + { + if (m_entryStack.empty()) + { + return VisitorFailure(VisitorErrorCode::InternalError, "EndObject called without a matching BeginObject call"); } - Result Null() override + if (!m_entryStack.front().m_isObject) { - CurrentValue().SetNull(); - return FinishWrite(); + return VisitorFailure(VisitorErrorCode::InternalError, "Expected EndArray and received EndObject instead"); } - Result Bool(bool value) override + if (m_entryStack.front().m_entryCount != attributeCount) { - CurrentValue().SetBool(value); - return FinishWrite(); + return FormatVisitorFailure( + VisitorErrorCode::InternalError, "EndObject: Expected %lu attributes but received %lu attributes instead", attributeCount, + m_entryStack.front().m_entryCount); } - Result Int64(AZ::s64 value) override + m_entryStack.pop_front(); + return FinishWrite(); + } + + Visitor::Result RapidJsonValueWriter::Key(AZ::Name key) + { + return RawKey(key.GetStringView(), Lifetime::Persistent); + } + + Visitor::Result RapidJsonValueWriter::RawKey(AZStd::string_view key, Lifetime lifetime) + { + AZ_Assert(!m_entryStack.empty(), "Attempmted to push a key with no object"); + AZ_Assert(m_entryStack.front().m_isObject, "Attempted to push a key to an array"); + if (lifetime == Lifetime::Persistent) { - CurrentValue().SetInt64(value); - return FinishWrite(); + m_entryStack.front().m_key.SetString(key.data(), static_cast(key.size())); + } + else + { + m_entryStack.front().m_key.SetString(key.data(), static_cast(key.size()), m_allocator); + } + return VisitorSuccess(); + } + + Visitor::Result RapidJsonValueWriter::StartArray() + { + CurrentValue().SetArray(); + + const bool isObject = false; + m_entryStack.emplace_front(isObject, CurrentValue()); + return VisitorSuccess(); + } + + Visitor::Result RapidJsonValueWriter::EndArray(AZ::u64 elementCount) + { + if (m_entryStack.empty()) + { + return VisitorFailure(VisitorErrorCode::InternalError, "EndArray called without a matching BeginArray call"); } - Result Uint64(AZ::u64 value) override + if (m_entryStack.front().m_isObject) { - CurrentValue().SetUint64(value); - return FinishWrite(); + return VisitorFailure(VisitorErrorCode::InternalError, "Expected EndObject and received EndArray instead"); } - Result Double(double value) override + if (m_entryStack.front().m_entryCount != elementCount) { - CurrentValue().SetDouble(value); - return FinishWrite(); + return FormatVisitorFailure( + VisitorErrorCode::InternalError, "EndArray: Expected %lu elements but received %lu elements instead", elementCount, + m_entryStack.front().m_entryCount); } - Result String(AZStd::string_view value, Lifetime lifetime) override - { - if (lifetime == Lifetime::Temporary) - { - CurrentValue().SetString(value.data(), static_cast(value.length()), m_result.GetAllocator()); - } - else - { - CurrentValue().SetString(value.data(), static_cast(value.length())); - } - return FinishWrite(); - } + m_entryStack.pop_front(); + return FinishWrite(); + } - Result StartObject() override + Visitor::Result RapidJsonValueWriter::FinishWrite() + { + if (m_entryStack.empty()) { - CurrentValue().SetObject(); - - const bool isObject = true; - m_entryStack.emplace_front(isObject, CurrentValue()); return VisitorSuccess(); } - Result EndObject(AZ::u64 attributeCount) override + // Retrieve the top value of the stack and replace it with a null value + rapidjson::Value value; + m_entryStack.front().m_value.Swap(value); + ++m_entryStack.front().m_entryCount; + + if (m_entryStack.front().m_key.IsString()) { - if (m_entryStack.empty()) - { - return VisitorFailure(VisitorErrorCode::InternalError, "EndObject called without a matching BeginObject call"); - } - - if (!m_entryStack.front().m_isObject) - { - return VisitorFailure(VisitorErrorCode::InternalError, "Expected EndArray and received EndObject instead"); - } - - if (m_entryStack.front().m_entryCount != attributeCount) - { - return FormatVisitorFailure( - VisitorErrorCode::InternalError, "EndObject: Expected %lu attributes but received %lu attributes instead", - attributeCount, m_entryStack.front().m_entryCount); - } - - m_entryStack.pop_front(); - return FinishWrite(); + m_entryStack.front().m_container.AddMember(m_entryStack.front().m_key.Move(), AZStd::move(value), m_allocator); + m_entryStack.front().m_key.SetNull(); + } + else + { + m_entryStack.front().m_container.PushBack(AZStd::move(value), m_allocator); } - Result Key(AZ::Name key) override + return VisitorSuccess(); + } + + rapidjson::Value& RapidJsonValueWriter::CurrentValue() + { + if (m_entryStack.empty()) { - return RawKey(key.GetStringView(), Lifetime::Persistent); + return m_result; } + return m_entryStack.front().m_value; + } - Result RawKey(AZStd::string_view key, Lifetime lifetime) override - { - AZ_Assert(!m_entryStack.empty(), "Attempmted to push a key with no object"); - AZ_Assert(m_entryStack.front().m_isObject, "Attempted to push a key to an array"); - if (lifetime == Lifetime::Persistent) - { - m_entryStack.front().m_key.SetString(key.data(), static_cast(key.size())); - } - else - { - m_entryStack.front().m_key.SetString(key.data(), static_cast(key.size()), m_result.GetAllocator()); - } - return VisitorSuccess(); - } - - Result StartArray() override - { - CurrentValue().SetArray(); - - const bool isObject = false; - m_entryStack.emplace_front(isObject, CurrentValue()); - return VisitorSuccess(); - } - - Result EndArray(AZ::u64 elementCount) override - { - if (m_entryStack.empty()) - { - return VisitorFailure(VisitorErrorCode::InternalError, "EndArray called without a matching BeginArray call"); - } - - if (m_entryStack.front().m_isObject) - { - return VisitorFailure(VisitorErrorCode::InternalError, "Expected EndObject and received EndArray instead"); - } - - if (m_entryStack.front().m_entryCount != elementCount) - { - return FormatVisitorFailure( - VisitorErrorCode::InternalError, "EndArray: Expected %lu elements but received %lu elements instead", elementCount, - m_entryStack.front().m_entryCount); - } - - m_entryStack.pop_front(); - return FinishWrite(); - } - - rapidjson::Document&& TakeDocument() - { - return AZStd::move(m_result); - } - - private: - Result FinishWrite() - { - if (m_entryStack.empty()) - { - return VisitorSuccess(); - } - - // Retrieve the top value of the stack and replace it with a null value - rapidjson::Value value; - m_entryStack.front().m_value.Swap(value); - ++m_entryStack.front().m_entryCount; - - if (m_entryStack.front().m_key.IsString()) - { - m_entryStack.front().m_container.AddMember(m_entryStack.front().m_key.Move(), AZStd::move(value), m_result.GetAllocator()); - m_entryStack.front().m_key.SetNull(); - } - else - { - m_entryStack.front().m_container.PushBack(AZStd::move(value), m_result.GetAllocator()); - } - - return VisitorSuccess(); - } - - rapidjson::Value& CurrentValue() - { - if (m_entryStack.empty()) - { - return m_result; - } - return m_entryStack.front().m_value; - } - - struct ValueInfo - { - ValueInfo(bool isObject, rapidjson::Value& container) - : m_isObject(isObject) - , m_container(container) - { - } - - rapidjson::Value m_key; - rapidjson::Value m_value; - rapidjson::Value& m_container; - AZ::u64 m_entryCount = 0; - bool m_isObject; - }; - - rapidjson::Document m_result; - AZStd::deque m_entryStack; - }; + RapidJsonValueWriter::ValueInfo::ValueInfo(bool isObject, rapidjson::Value& container) + : m_isObject(isObject) + , m_container(container) + { + } // // class StreamWriter @@ -503,36 +485,36 @@ namespace AZ::Dom::Json // // Serialized JSON util functions // - AZStd::unique_ptr GetJsonStreamWriter(AZ::IO::GenericStream* stream, OutputFormatting format) + AZStd::unique_ptr GetJsonStreamWriter(AZ::IO::GenericStream& stream, OutputFormatting format) { if (format == OutputFormatting::MinifiedJson) { using WriterType = rapidjson::Writer; - return AZStd::make_unique>(stream); + return AZStd::make_unique>(&stream); } else { using WriterType = rapidjson::PrettyWriter; - return AZStd::make_unique>(stream); + return AZStd::make_unique>(&stream); } } - Visitor::Result VisitSerializedJson(AZStd::string_view buffer, Lifetime lifetime, Visitor* visitor) + Visitor::Result VisitSerializedJson(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor) { rapidjson::Reader reader; rapidjson::MemoryStream stream(buffer.data(), buffer.size()); - JsonReadHandler handler(visitor, lifetime); + JsonReadHandler handler(&visitor, lifetime); constexpr int flags = rapidjson::kParseCommentsFlag; reader.Parse(stream, handler); return handler.TakeOutcome(); } - Visitor::Result VisitSerializedJsonInPlace(AZStd::string& buffer, Visitor* visitor) + Visitor::Result VisitSerializedJsonInPlace(AZStd::string& buffer, Visitor& visitor) { rapidjson::Reader reader; AzStringStream stream(buffer); - JsonReadHandler handler(visitor, Lifetime::Persistent); + JsonReadHandler handler(&visitor, Lifetime::Persistent); constexpr int flags = rapidjson::kParseCommentsFlag | rapidjson::kParseInsituFlag; reader.Parse(stream, handler); @@ -544,16 +526,24 @@ namespace AZ::Dom::Json // AZ::Outcome WriteToRapidJsonDocument(Backend::WriteCallback writeCallback) { - DocumentWriter writer; - auto result = writeCallback(&writer); + rapidjson::Document document; + RapidJsonValueWriter writer(document, document.GetAllocator()); + auto result = writeCallback(writer); if (!result.IsSuccess()) { return AZ::Failure(result.TakeError().FormatVisitorErrorMessage()); } - return AZ::Success(writer.TakeDocument()); + return AZ::Success(AZStd::move(document)); } - Visitor::Result VisitRapidJsonValue(const rapidjson::Value& value, Visitor* visitor, Lifetime lifetime) + Visitor::Result WriteToRapidJsonValue( + rapidjson::Value& value, rapidjson::Value::AllocatorType& allocator, Backend::WriteCallback writeCallback) + { + RapidJsonValueWriter writer(value, allocator); + return writeCallback(writer); + } + + Visitor::Result VisitRapidJsonValue(const rapidjson::Value& value, Visitor& visitor, Lifetime lifetime) { struct EndArrayMarker { @@ -579,7 +569,7 @@ namespace AZ::Dom::Json Visitor::Result result = AZ::Success(); AZStd::visit( - [visitor, &entryStack, &entryCountStack, &result, lifetime](auto&& arg) + [&visitor, &entryStack, &entryCountStack, &result, lifetime](auto&& arg) { using Alternative = AZStd::decay_t; if constexpr (AZStd::is_same_v) @@ -593,18 +583,18 @@ namespace AZ::Dom::Json switch (currentValue.GetType()) { case rapidjson::kNullType: - result = visitor->Null(); + result = visitor.Null(); break; case rapidjson::kFalseType: - result = visitor->Bool(false); + result = visitor.Bool(false); break; case rapidjson::kTrueType: - result = visitor->Bool(true); + result = visitor.Bool(true); break; case rapidjson::kObjectType: entryStack.push(EndObjectMarker{}); entryCountStack.push(0); - result = visitor->StartObject(); + result = visitor.StartObject(); for (auto it = currentValue.MemberEnd(); it != currentValue.MemberBegin(); --it) { auto entry = (it - 1); @@ -616,7 +606,7 @@ namespace AZ::Dom::Json case rapidjson::kArrayType: entryStack.push(EndArrayMarker{}); entryCountStack.push(0); - result = visitor->StartArray(); + result = visitor.StartArray(); for (auto it = currentValue.End(); it != currentValue.Begin(); --it) { auto entry = (it - 1); @@ -624,22 +614,22 @@ namespace AZ::Dom::Json } break; case rapidjson::kStringType: - result = visitor->String( + result = visitor.String( AZStd::string_view(currentValue.GetString(), static_cast(currentValue.GetStringLength())), lifetime); break; case rapidjson::kNumberType: if (currentValue.IsFloat() || currentValue.IsDouble()) { - result = visitor->Double(currentValue.GetDouble()); + result = visitor.Double(currentValue.GetDouble()); } else if (currentValue.IsInt64() || currentValue.IsInt()) { - result = visitor->Int64(currentValue.GetInt64()); + result = visitor.Int64(currentValue.GetInt64()); } else { - result = visitor->Uint64(currentValue.GetUint64()); + result = visitor.Uint64(currentValue.GetUint64()); } break; default: @@ -648,23 +638,23 @@ namespace AZ::Dom::Json } else if constexpr (AZStd::is_same_v) { - result = visitor->EndArray(entryCountStack.top()); + result = visitor.EndArray(entryCountStack.top()); entryCountStack.pop(); } else if constexpr (AZStd::is_same_v) { - result = visitor->EndObject(entryCountStack.top()); + result = visitor.EndObject(entryCountStack.top()); entryCountStack.pop(); } else if constexpr (AZStd::is_same_v) { - if (visitor->SupportsRawKeys()) + if (visitor.SupportsRawKeys()) { - visitor->RawKey(arg, lifetime); + visitor.RawKey(arg, lifetime); } else { - visitor->Key(AZ::Name(arg)); + visitor.Key(AZ::Name(arg)); } } }, diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h index 1f9b58ac51..007134227e 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -25,36 +26,84 @@ namespace AZ::Dom::Json PrettyPrintedJson, //!< Formats JSON in a pretty printed form, focusing on legibility to readers. }; + //! Visitor that feeds into a rapidjson::Value + class RapidJsonValueWriter final : public Visitor + { + public: + RapidJsonValueWriter(rapidjson::Value& outputValue, rapidjson::Value::AllocatorType& allocator); + + VisitorFlags GetVisitorFlags() const override; + Result Null() override; + Result Bool(bool value) override; + Result Int64(AZ::s64 value) override; + Result Uint64(AZ::u64 value) override; + Result Double(double value) override; + + Result String(AZStd::string_view value, Lifetime lifetime) override; + Result StartObject() override; + Result EndObject(AZ::u64 attributeCount) override; + Result Key(AZ::Name key) override; + Result RawKey(AZStd::string_view key, Lifetime lifetime) override; + Result StartArray() override; + Result EndArray(AZ::u64 elementCount) override; + + private: + Result FinishWrite(); + rapidjson::Value& CurrentValue(); + + struct ValueInfo + { + ValueInfo(bool isObject, rapidjson::Value& container); + + rapidjson::Value m_key; + rapidjson::Value m_value; + rapidjson::Value& m_container; + AZ::u64 m_entryCount = 0; + bool m_isObject; + }; + + rapidjson::Value& m_result; + rapidjson::Value::AllocatorType& m_allocator; + AZStd::deque m_entryStack; + }; + //! Creates a Visitor that will write serialized JSON to the specified stream. //! \param stream The stream the visitor will write to. //! \param format The format to write in. //! \return A Visitor that will write to stream when visited. AZStd::unique_ptr GetJsonStreamWriter( - AZ::IO::GenericStream* stream, OutputFormatting format = OutputFormatting::PrettyPrintedJson); + AZ::IO::GenericStream& stream, OutputFormatting format = OutputFormatting::PrettyPrintedJson); //! Reads serialized JSON from a string and applies it to a visitor. //! \param buffer The UTF-8 serialized JSON to read. //! \param lifetime Specifies the lifetime of the specified buffer. If the string specified by buffer might be deallocated, //! ensure specify Lifetime::Temporary is specified. //! \param visitor The visitor to visit with the JSON buffer's contents. //! \return The aggregate result specifying whether the visitor operations were successful. - Visitor::Result VisitSerializedJson(AZStd::string_view buffer, Lifetime lifetime, Visitor* visitor); + Visitor::Result VisitSerializedJson(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor); //! Reads serialized JSON from a string in-place and applies it to a visitor. //! \param buffer The UTF-8 serialized JSON to read. This buffer will be modified as part of the deserialization process to //! apply null terminators. //! \param visitor The visitor to visit with the JSON buffer's contents. The strings provided to the visitor will only //! be valid for the lifetime of buffer. //! \return The aggregate result specifying whether the visitor operations were successful. - Visitor::Result VisitSerializedJsonInPlace(AZStd::string& buffer, Visitor* visitor); + Visitor::Result VisitSerializedJsonInPlace(AZStd::string& buffer, Visitor& visitor); //! Takes a visitor specified by a callback and produces a rapidjson::Document. //! \param writeCallback A callback specifying a visitor to accept to build the resulting document. //! \return An outcome with either the rapidjson::Document or an error message. AZ::Outcome WriteToRapidJsonDocument(Backend::WriteCallback writeCallback); + //! Takes a visitor specified by a callback and reads them into a rapidjson::Value. + //! \param value The value to read into, its contents will be overridden. + //! \param allocator The allocator to use when performing rapidjson allocations (generally provded by the rapidjson::Document). + //! \param writeCallback A callback specifying a visitor to accept to build the resulting document. + //! \return An outcome with either the rapidjson::Document or an error message. + Visitor::Result WriteToRapidJsonValue( + rapidjson::Value& value, rapidjson::Value::AllocatorType& allocator, Backend::WriteCallback writeCallback); //! Accepts a visitor with the contents of a rapidjson::Value. //! \param value The rapidjson::Value to apply to visitor. //! \param visitor The visitor to receive the contents of value. //! \param lifetime The lifetime to specify for visiting strings. If the rapidjson::Value might be destroyed or changed //! before the visitor is finished using these values, Lifetime::Temporary should be specified. //! \return The aggregate result specifying whether the visitor operations were successful. - Visitor::Result VisitRapidJsonValue(const rapidjson::Value& value, Visitor* visitor, Lifetime lifetime); + Visitor::Result VisitRapidJsonValue(const rapidjson::Value& value, Visitor& visitor, Lifetime lifetime); } // namespace AZ::Dom::Json diff --git a/Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp b/Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp index 925897c299..258975eff3 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp @@ -10,11 +10,11 @@ #include #include -#include "DomBackend.h" +#include namespace AZ::Dom { - Visitor::Result Backend::ReadFromStream(AZ::IO::GenericStream* stream, Visitor* visitor, size_t maxSize) + Visitor::Result Backend::ReadFromStream(AZ::IO::GenericStream* stream, Visitor& visitor, size_t maxSize) { size_t length = stream->GetLength(); if (length > maxSize) @@ -27,21 +27,21 @@ namespace AZ::Dom return ReadFromString(buffer, Lifetime::Temporary, visitor); } - Visitor::Result Backend::ReadFromStringInPlace(AZStd::string& buffer, Visitor* visitor) + Visitor::Result Backend::ReadFromStringInPlace(AZStd::string& buffer, Visitor& visitor) { return ReadFromString(buffer, Lifetime::Persistent, visitor); } - Visitor::Result Backend::WriteToStream(AZ::IO::GenericStream* stream, WriteCallback callback) + Visitor::Result Backend::WriteToStream(AZ::IO::GenericStream& stream, WriteCallback callback) { AZStd::unique_ptr writer = CreateStreamWriter(stream); - return callback(writer.get()); + return callback(*writer.get()); } Visitor::Result Backend::WriteToString(AZStd::string& buffer, WriteCallback callback) { AZ::IO::ByteContainerStream stream{&buffer}; - AZStd::unique_ptr writer = CreateStreamWriter(&stream); - return callback(writer.get()); + AZStd::unique_ptr writer = CreateStreamWriter(stream); + return callback(*writer.get()); } } diff --git a/Code/Framework/AzCore/AzCore/DOM/DomBackend.h b/Code/Framework/AzCore/AzCore/DOM/DomBackend.h index d11335262e..d1eee5d676 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomBackend.h +++ b/Code/Framework/AzCore/AzCore/DOM/DomBackend.h @@ -25,24 +25,24 @@ namespace AZ::Dom //! Attempt to read this format from the given stream into the target Visitor. //! The base implementation reads the stream into memory and calls ReadFromString. virtual Visitor::Result ReadFromStream( - AZ::IO::GenericStream* stream, Visitor* visitor, size_t maxSize = AZStd::numeric_limits::max()); + AZ::IO::GenericStream* stream, Visitor& visitor, size_t maxSize = AZStd::numeric_limits::max()); //! Attempt to read this format from a mutable string into the target Visitor. This enables some backends to //! parse without making additional string allocations. //! This string may be modified and read in place without being copied, so when calling this please ensure that: //! - The string won't be deallocated until the visitor no longer needs the values and //! - The string is safe to modify in place. //! The base implementation simply calls ReadFromString. - virtual Visitor::Result ReadFromStringInPlace(AZStd::string& buffer, Visitor* visitor); + virtual Visitor::Result ReadFromStringInPlace(AZStd::string& buffer, Visitor& visitor); //! Attempt to read this format from an immutable buffer in memory into the target Visitor. - virtual Visitor::Result ReadFromString(AZStd::string_view buffer, Lifetime lifetime, Visitor* visitor) = 0; + virtual Visitor::Result ReadFromString(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor) = 0; //! Acquire a visitor interface for writing to the target output file. - virtual AZStd::unique_ptr CreateStreamWriter(AZ::IO::GenericStream* stream) = 0; + virtual AZStd::unique_ptr CreateStreamWriter(AZ::IO::GenericStream& stream) = 0; //! A callback that accepts a Visitor, making DOM calls to inform the serializer, and returns an //! aggregate error code to indicate whether or not the operation succeeded. - using WriteCallback = AZStd::function; + using WriteCallback = AZStd::function; //! Attempt to write a value to a stream using a write callback. - Visitor::Result WriteToStream(AZ::IO::GenericStream* stream, WriteCallback callback); + Visitor::Result WriteToStream(AZ::IO::GenericStream& stream, WriteCallback callback); //! Attempt to write a value to a string using a write callback. Visitor::Result WriteToString(AZStd::string& buffer, WriteCallback callback); }; diff --git a/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp b/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp index 4596316213..ea72092001 100644 --- a/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp +++ b/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp @@ -130,7 +130,7 @@ namespace Benchmark state.ResumeTiming(); auto result = AZ::Dom::Json::WriteToRapidJsonDocument( - [&](AZ::Dom::Visitor* visitor) + [&](AZ::Dom::Visitor& visitor) { return backend.ReadFromStringInPlace(payloadCopy, visitor); }); @@ -150,7 +150,7 @@ namespace Benchmark for (auto _ : state) { auto result = AZ::Dom::Json::WriteToRapidJsonDocument( - [&](AZ::Dom::Visitor* visitor) + [&](AZ::Dom::Visitor& visitor) { return backend.ReadFromString(serializedPayload, AZ::Dom::Lifetime::Temporary, visitor); }); diff --git a/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp b/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp index 25deeb8a82..cde5e2eb3f 100644 --- a/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp +++ b/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -31,78 +32,6 @@ namespace AZ::Dom::Tests UnitTest::AllocatorsFixture::TearDown(); } - static bool DeepCompare(const rapidjson::Value& lhs, const rapidjson::Value& rhs) - { - if (lhs.GetType() != rhs.GetType()) - { - return false; - } - - switch (lhs.GetType()) - { - case rapidjson::kNullType: - return true; - case rapidjson::kFalseType: - return true; - case rapidjson::kTrueType: - return true; - case rapidjson::kObjectType: - { - if (lhs.MemberCount() != rhs.MemberCount()) - { - return false; - } - - auto lhsIt = lhs.MemberBegin(); - auto rhsIt = rhs.MemberBegin(); - while (lhsIt != lhs.MemberEnd()) - { - if (lhsIt->name != rhsIt->name) - { - return false; - } - - if (!DeepCompare(lhsIt->value, rhsIt->value)) - { - return false; - } - - ++lhsIt; - ++rhsIt; - } - return true; - } - case rapidjson::kArrayType: - { - if (lhs.Size() != rhs.Size()) - { - return false; - } - - auto lhsIt = lhs.Begin(); - auto rhsIt = rhs.Begin(); - while (lhsIt != lhs.End()) - { - if (!DeepCompare(*lhsIt, *rhsIt)) - { - return false; - } - - ++lhsIt; - ++rhsIt; - } - return true; - } - case rapidjson::kStringType: - return lhs == rhs; - case rapidjson::kNumberType: - return lhs == rhs; - } - - AZ_Assert(false, "Unexpected JSON value type"); - return false; - } - rapidjson::Value CreateString(const AZStd::string& text) { rapidjson::Value key; @@ -110,7 +39,7 @@ namespace AZ::Dom::Tests return key; } - template + template void AddValue(const AZStd::string& key, T value) { m_document->AddMember(CreateString(key), rapidjson::Value(value), m_document->GetAllocator()); @@ -125,7 +54,7 @@ namespace AZ::Dom::Tests AZStd::string canonicalSerializedDocument; AZ::JsonSerializationUtils::WriteJsonString(*m_document, canonicalSerializedDocument); - auto visitDocumentFn = [this](AZ::Dom::Visitor* visitor) + auto visitDocumentFn = [this](AZ::Dom::Visitor& visitor) { return Json::VisitRapidJsonValue(*m_document, visitor, Lifetime::Persistent); }; @@ -134,7 +63,7 @@ namespace AZ::Dom::Tests { auto result = Json::WriteToRapidJsonDocument(visitDocumentFn); EXPECT_TRUE(result.IsSuccess()); - EXPECT_TRUE(DeepCompare(*m_document, result.GetValue())); + EXPECT_EQ(AZ::JsonSerialization::Compare(*m_document, result.GetValue()), AZ::JsonSerializerCompareResult::Equal); } // Document -> string @@ -149,13 +78,13 @@ namespace AZ::Dom::Tests // string -> Document { auto result = Json::WriteToRapidJsonDocument( - [&canonicalSerializedDocument](AZ::Dom::Visitor* visitor) + [&canonicalSerializedDocument](AZ::Dom::Visitor& visitor) { JsonBackend backend; return backend.ReadFromString(canonicalSerializedDocument, AZ::Dom::Lifetime::Temporary, visitor); }); EXPECT_TRUE(result.IsSuccess()); - EXPECT_TRUE(DeepCompare(*m_document, result.GetValue())); + EXPECT_EQ(AZ::JsonSerialization::Compare(*m_document, result.GetValue()), JsonSerializerCompareResult::Equal); } // string -> string @@ -164,7 +93,7 @@ namespace AZ::Dom::Tests JsonBackend backend; auto result = backend.WriteToString( serializedDocument, - [&backend, &canonicalSerializedDocument](AZ::Dom::Visitor* visitor) + [&backend, &canonicalSerializedDocument](AZ::Dom::Visitor& visitor) { return backend.ReadFromString(canonicalSerializedDocument, AZ::Dom::Lifetime::Temporary, visitor); }); @@ -282,7 +211,8 @@ namespace AZ::Dom::Tests m_document->SetObject(); m_document->AddMember(CreateString("empty_string"), CreateString(""), m_document->GetAllocator()); m_document->AddMember(CreateString("short_string"), CreateString("test"), m_document->GetAllocator()); - m_document->AddMember(CreateString("long_string"), CreateString("abcdefghijklmnopqrstuvwxyz0123456789"), m_document->GetAllocator()); + m_document->AddMember( + CreateString("long_string"), CreateString("abcdefghijklmnopqrstuvwxyz0123456789"), m_document->GetAllocator()); PerformSerializationChecks(); } } // namespace AZ::Dom::Tests From bc903f22cd020cfa60bf0730114996bf722b0b12 Mon Sep 17 00:00:00 2001 From: sweeneys Date: Tue, 30 Nov 2021 18:23:36 -0800 Subject: [PATCH 050/128] Remove remote console flag suppressing game logs in GameLauncher and ServerLauncher apps Signed-off-by: sweeneys --- .../launchers/platforms/linux/launcher.py | 6 +++--- .../launchers/platforms/win/launcher.py | 16 ---------------- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py index 112629b349..e8931ba07f 100644 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py @@ -179,20 +179,20 @@ class LinuxLauncher(Launcher): class DedicatedLinuxLauncher(LinuxLauncher): - def setup(self, backupFiles=True, launch_ap=False): + def setup(self, backupFiles=True, launch_ap=False, configure_settings=True): """ Perform setup of this launcher, must be called before launching. Subclasses should call its parent's setup() before calling its own code, unless it changes configuration files :param backupFiles: Bool to backup setup files - :param lauch_ap: Bool to lauch the asset processor + :param launch_ap: Bool to launch the asset processor :return: None """ # Base setup defaults to None if launch_ap is None: launch_ap = False - super(DedicatedLinuxLauncher, self).setup(backupFiles, launch_ap) + super(DedicatedLinuxLauncher, self).setup(backupFiles, launch_ap, configure_settings) def binary_path(self): """ diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py index d18431ba82..ec2b3b966c 100755 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py @@ -169,7 +169,6 @@ class WinLauncher(Launcher): host_ip = '127.0.0.1' self.args.append(f'--regset="/Amazon/AzCore/Bootstrap/project_path={self.workspace.paths.project()}"') self.args.append(f'--regset="/Amazon/AzCore/Bootstrap/remote_ip={host_ip}"') - self.args.append('--regset="/Amazon/AzCore/Bootstrap/wait_for_connect=1"') self.args.append(f'--regset="/Amazon/AzCore/Bootstrap/allowed_list={host_ip}"') self.workspace.settings.modify_platform_setting("log_RemoteConsoleAllowedAddresses", host_ip) @@ -177,21 +176,6 @@ class WinLauncher(Launcher): class DedicatedWinLauncher(WinLauncher): - def setup(self, backupFiles=True, launch_ap=False): - """ - Perform setup of this launcher, must be called before launching. - Subclasses should call its parent's setup() before calling its own code, unless it changes configuration files - - :param backupFiles: Bool to backup setup files - :param lauch_ap: Bool to lauch the asset processor - :return: None - """ - # Base setup defaults to None - if launch_ap is None: - launch_ap = False - - super(DedicatedWinLauncher, self).setup(backupFiles, launch_ap) - def binary_path(self): """ Return full path to the dedicated server launcher for the build directory. From f87021d8561f17dd05d9e2fd0239fcf7657ebbd8 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Tue, 30 Nov 2021 22:08:48 -0800 Subject: [PATCH 051/128] Expose JSON parse flag options Signed-off-by: Nicholas Van Sickle --- .../Backends/JSON/JsonSerializationUtils.cpp | 306 ++++++++---------- .../Backends/JSON/JsonSerializationUtils.h | 82 ++++- 2 files changed, 214 insertions(+), 174 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp index 743ef3df43..84f663f97c 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp @@ -304,183 +304,165 @@ namespace AZ::Dom::Json // // struct JsonReadHandler // - // Handler for a rapidjson::Reader that translates reads into an AZ::Dom::Visitor - struct JsonReadHandler + RapidJsonReadHandler::RapidJsonReadHandler(Visitor* visitor, Lifetime stringLifetime) + : m_visitor(visitor) + , m_stringLifetime(stringLifetime) + , m_outcome(AZ::Success()) { - public: - JsonReadHandler(Visitor* visitor, Lifetime stringLifetime) - : m_visitor(visitor) - , m_stringLifetime(stringLifetime) - , m_outcome(AZ::Success()) - { - } + } - bool Null() - { - return CheckResult(m_visitor->Null()); - } + bool RapidJsonReadHandler::Null() + { + return CheckResult(m_visitor->Null()); + } - bool Bool(bool b) - { - return CheckResult(m_visitor->Bool(b)); - } + bool RapidJsonReadHandler::Bool(bool b) + { + return CheckResult(m_visitor->Bool(b)); + } - bool Int(int i) - { - return CheckResult(m_visitor->Int64(static_cast(i))); - } + bool RapidJsonReadHandler::Int(int i) + { + return CheckResult(m_visitor->Int64(static_cast(i))); + } - bool Uint(unsigned i) - { - return CheckResult(m_visitor->Uint64(static_cast(i))); - } + bool RapidJsonReadHandler::Uint(unsigned i) + { + return CheckResult(m_visitor->Uint64(static_cast(i))); + } - bool Int64(int64_t i) - { - return CheckResult(m_visitor->Int64(i)); - } + bool RapidJsonReadHandler::Int64(int64_t i) + { + return CheckResult(m_visitor->Int64(i)); + } - bool Uint64(uint64_t i) - { - return CheckResult(m_visitor->Uint64(i)); - } + bool RapidJsonReadHandler::Uint64(uint64_t i) + { + return CheckResult(m_visitor->Uint64(i)); + } - bool Double(double d) - { - return CheckResult(m_visitor->Double(d)); - } + bool RapidJsonReadHandler::Double(double d) + { + return CheckResult(m_visitor->Double(d)); + } - bool RawNumber([[maybe_unused]] const char* str, [[maybe_unused]] rapidjson::SizeType length, [[maybe_unused]] bool copy) + bool RapidJsonReadHandler::RawNumber( + [[maybe_unused]] const char* str, [[maybe_unused]] rapidjson::SizeType length, [[maybe_unused]] bool copy) + { + AZ_Assert(false, "Raw numbers are unsupported in the rapidjson DOM backend"); + return false; + } + + bool RapidJsonReadHandler::String(const char* str, rapidjson::SizeType length, bool copy) + { + Lifetime lifetime = m_stringLifetime; + if (!copy) { - AZ_Assert(false, "Raw numbers are unsupported in the rapidjson DOM backend"); + lifetime = Lifetime::Temporary; + } + return CheckResult(m_visitor->String(AZStd::string_view(str, length), lifetime)); + } + + bool RapidJsonReadHandler::StartObject() + { + return CheckResult(m_visitor->StartObject()); + } + + bool RapidJsonReadHandler::Key(const char* str, rapidjson::SizeType length, [[maybe_unused]] bool copy) + { + AZStd::string_view key = AZStd::string_view(str, length); + if (!m_visitor->SupportsRawKeys()) + { + m_visitor->Key(AZ::Name(key)); + } + Lifetime lifetime = m_stringLifetime; + if (!copy) + { + lifetime = Lifetime::Temporary; + } + return CheckResult(m_visitor->RawKey(key, lifetime)); + } + + bool RapidJsonReadHandler::EndObject([[maybe_unused]] rapidjson::SizeType memberCount) + { + return CheckResult(m_visitor->EndObject(memberCount)); + } + + bool RapidJsonReadHandler::StartArray() + { + return CheckResult(m_visitor->StartArray()); + } + + bool RapidJsonReadHandler::EndArray([[maybe_unused]] rapidjson::SizeType elementCount) + { + return CheckResult(m_visitor->EndArray(elementCount)); + } + + Visitor::Result&& RapidJsonReadHandler::TakeOutcome() + { + return AZStd::move(m_outcome); + } + + bool RapidJsonReadHandler::CheckResult(Visitor::Result result) + { + if (!result.IsSuccess()) + { + m_outcome = AZStd::move(result); return false; } - - bool String(const char* str, rapidjson::SizeType length, bool copy) - { - Lifetime lifetime = m_stringLifetime; - if (!copy) - { - lifetime = Lifetime::Temporary; - } - return CheckResult(m_visitor->String(AZStd::string_view(str, length), lifetime)); - } - - bool StartObject() - { - return CheckResult(m_visitor->StartObject()); - } - - bool Key(const char* str, rapidjson::SizeType length, [[maybe_unused]] bool copy) - { - AZStd::string_view key = AZStd::string_view(str, length); - if (!m_visitor->SupportsRawKeys()) - { - m_visitor->Key(AZ::Name(key)); - } - Lifetime lifetime = m_stringLifetime; - if (!copy) - { - lifetime = Lifetime::Temporary; - } - return CheckResult(m_visitor->RawKey(key, lifetime)); - } - - bool EndObject([[maybe_unused]] rapidjson::SizeType memberCount) - { - return CheckResult(m_visitor->EndObject(memberCount)); - } - - bool StartArray() - { - return CheckResult(m_visitor->StartArray()); - } - - bool EndArray([[maybe_unused]] rapidjson::SizeType elementCount) - { - return CheckResult(m_visitor->EndArray(elementCount)); - } - - Visitor::Result&& TakeOutcome() - { - return AZStd::move(m_outcome); - } - - private: - bool CheckResult(Visitor::Result result) - { - if (!result.IsSuccess()) - { - m_outcome = AZStd::move(result); - return false; - } - return true; - } - - Visitor::Result m_outcome; - Visitor* m_visitor; - Lifetime m_stringLifetime; - }; + return true; + } // // struct AzStringStream // // rapidjson stream wrapper for AZStd::string suitable for in-situ parsing - struct AzStringStream + AzStringStream::AzStringStream(AZStd::string& buffer) { - using Ch = char; + m_cursor = buffer.data(); + m_begin = m_cursor; + } - AzStringStream(AZStd::string& buffer) - { - m_cursor = buffer.data(); - m_begin = m_cursor; - } + char AzStringStream::Peek() const + { + return *m_cursor; + } - char Peek() const - { - return *m_cursor; - } + char AzStringStream::Take() + { + return *m_cursor++; + } - char Take() - { - return *m_cursor++; - } + size_t AzStringStream::Tell() const + { + return static_cast(m_cursor - m_begin); + } - size_t Tell() const - { - return static_cast(m_cursor - m_begin); - } + char* AzStringStream::PutBegin() + { + m_write = m_cursor; + return m_cursor; + } - char* PutBegin() - { - m_write = m_cursor; - return m_cursor; - } + void AzStringStream::Put(char c) + { + (*m_write++) = c; + } - void Put(char c) - { - (*m_write++) = c; - } + void AzStringStream::Flush() + { + } - void Flush() - { - } + size_t AzStringStream::PutEnd(char* begin) + { + return m_write - begin; + } - size_t PutEnd(char* begin) - { - return m_write - begin; - } - - const char* Peek4() const - { - AZ_Assert(false, "Not implemented, encoding is hard-coded to UTF-8"); - return m_cursor; - } - - char* m_cursor; //!< Current read position. - char* m_write; //!< Current write position. - const char* m_begin; //!< Head of string. - }; + const char* AzStringStream::Peek4() const + { + AZ_Assert(false, "Not implemented, encoding is hard-coded to UTF-8"); + return m_cursor; + } // // Serialized JSON util functions @@ -499,28 +481,6 @@ namespace AZ::Dom::Json } } - Visitor::Result VisitSerializedJson(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor) - { - rapidjson::Reader reader; - rapidjson::MemoryStream stream(buffer.data(), buffer.size()); - JsonReadHandler handler(&visitor, lifetime); - - constexpr int flags = rapidjson::kParseCommentsFlag; - reader.Parse(stream, handler); - return handler.TakeOutcome(); - } - - Visitor::Result VisitSerializedJsonInPlace(AZStd::string& buffer, Visitor& visitor) - { - rapidjson::Reader reader; - AzStringStream stream(buffer); - JsonReadHandler handler(&visitor, Lifetime::Persistent); - - constexpr int flags = rapidjson::kParseCommentsFlag | rapidjson::kParseInsituFlag; - reader.Parse(stream, handler); - return handler.TakeOutcome(); - } - // // In-memory rapidjson util functions // diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h index 007134227e..be055d7f5c 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h @@ -67,6 +67,56 @@ namespace AZ::Dom::Json AZStd::deque m_entryStack; }; + //! Handler for a rapidjson::Reader that translates reads into an AZ::Dom::Visitor + struct RapidJsonReadHandler + { + public: + RapidJsonReadHandler(Visitor* visitor, Lifetime stringLifetime); + + bool Null(); + bool Bool(bool b); + bool Int(int i); + bool Uint(unsigned i); + bool Int64(int64_t i); + bool Uint64(uint64_t i); + bool Double(double d); + bool RawNumber(const char* str, rapidjson::SizeType length, bool copy); + bool String(const char* str, rapidjson::SizeType length, bool copy); + bool StartObject(); + bool Key(const char* str, rapidjson::SizeType length, bool copy); + bool EndObject(rapidjson::SizeType memberCount); + bool StartArray(); + bool EndArray(rapidjson::SizeType elementCount); + Visitor::Result&& TakeOutcome(); + + private: + bool CheckResult(Visitor::Result result); + + Visitor::Result m_outcome; + Visitor* m_visitor; + Lifetime m_stringLifetime; + }; + + //! rapidjson stream wrapper for AZStd::string suitable for in-situ parsing + struct AzStringStream + { + using Ch = char; // Visitor::Result VisitSerializedJson(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor); //! Reads serialized JSON from a string in-place and applies it to a visitor. //! \param buffer The UTF-8 serialized JSON to read. This buffer will be modified as part of the deserialization process to @@ -86,6 +137,7 @@ namespace AZ::Dom::Json //! \param visitor The visitor to visit with the JSON buffer's contents. The strings provided to the visitor will only //! be valid for the lifetime of buffer. //! \return The aggregate result specifying whether the visitor operations were successful. + template Visitor::Result VisitSerializedJsonInPlace(AZStd::string& buffer, Visitor& visitor); //! Takes a visitor specified by a callback and produces a rapidjson::Document. @@ -106,4 +158,32 @@ namespace AZ::Dom::Json //! before the visitor is finished using these values, Lifetime::Temporary should be specified. //! \return The aggregate result specifying whether the visitor operations were successful. Visitor::Result VisitRapidJsonValue(const rapidjson::Value& value, Visitor& visitor, Lifetime lifetime); + + template + Visitor::Result VisitSerializedJson(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor) + { + static_assert( + (ParseFlags & rapidjson::kParseInsituFlag) == 0, + "VisitSerializedJsonInPlace requires kParseInSituFlag not to be set, use VisitSerializedJsonInPlace to parse in-situ"); + + rapidjson::Reader reader; + rapidjson::MemoryStream stream(buffer.data(), buffer.size()); + RapidJsonReadHandler handler(&visitor, lifetime); + + reader.Parse(stream, handler); + return handler.TakeOutcome(); + } + + template + Visitor::Result VisitSerializedJsonInPlace(AZStd::string& buffer, Visitor& visitor) + { + static_assert((ParseFlags & rapidjson::kParseInsituFlag) != 0, "VisitSerializedJsonInPlace requires kParseInSituFlag to be set"); + + rapidjson::Reader reader; + AzStringStream stream(buffer); + RapidJsonReadHandler handler(&visitor, Lifetime::Persistent); + + reader.Parse(stream, handler); + return handler.TakeOutcome(); + } } // namespace AZ::Dom::Json From a5cb5b7f802ca93c093f448557b2f8767dd63b17 Mon Sep 17 00:00:00 2001 From: sweeneys Date: Tue, 30 Nov 2021 23:07:29 -0800 Subject: [PATCH 052/128] Make different launchers handle args the same way, fix missing docstrings Signed-off-by: sweeneys --- .../launchers/platforms/android/launcher.py | 20 ++++++++++++++++--- .../ly_test_tools/launchers/platforms/base.py | 2 ++ .../launchers/platforms/linux/launcher.py | 10 +++++++--- .../launchers/platforms/win/launcher.py | 7 ++++--- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py index 75eaa65e94..7c3efd9e9d 100755 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py @@ -163,9 +163,23 @@ class AndroidLauncher(Launcher): return True - def setup(self): + def setup(self, backupFiles=True, launch_ap=True, configure_settings=True): + """ + Perform setup of this launcher, must be called before launching. + Subclasses should call its parent's setup() before calling its own code, unless it changes configuration files + + :param backupFiles: Bool to backup setup files + :param launch_ap: Bool to launch the asset processor + :param configure_settings: Bool to update settings caches + :return: None + """ # Backup - self.backup_settings() + if backupFiles: + self.backup_settings() + + # Base setup defaults to None + if launch_ap is None: + launch_ap = True # Enable Android capabilities and verify environment is setup before continuing. self._is_valid_android_environment() @@ -174,7 +188,7 @@ class AndroidLauncher(Launcher): # Modify and re-configure self.configure_settings() self.workspace.shader_compiler.start() - super(AndroidLauncher, self).setup() + super(AndroidLauncher, self).setup(backupFiles, launch_ap, configure_settings) def teardown(self): ly_test_tools.mobile.android.undo_tcp_port_changes(self._device_id) diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/base.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/base.py index c9458899b4..e1b5dab1b6 100755 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/base.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/base.py @@ -75,6 +75,8 @@ class Launcher(object): ~/ly_test_tools/devices.ini (a.k.a. %USERPROFILE%/ly_test_tools/devices.ini) :param backupFiles: Bool to backup setup files + :param launch_ap: Bool to launch the asset processor + :param configure_settings: Bool to update settings caches :return: None """ # Remove existing logs and dmp files before launching for self.save_project_log_files() diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py index e8931ba07f..96e827069e 100644 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py @@ -162,7 +162,7 @@ class LinuxLauncher(Launcher): def configure_settings(self): """ - Configures system level settings and syncs the launcher to the targeted console IP. + Configures system level settings :return: None """ @@ -170,7 +170,6 @@ class LinuxLauncher(Launcher): host_ip = '127.0.0.1' self.args.append(f'--regset="/Amazon/AzCore/Bootstrap/project_path={self.workspace.paths.project()}"') self.args.append(f'--regset="/Amazon/AzCore/Bootstrap/remote_ip={host_ip}"') - self.args.append('--regset="/Amazon/AzCore/Bootstrap/wait_for_connect=1"') self.args.append(f'--regset="/Amazon/AzCore/Bootstrap/allowed_list={host_ip}"') self.workspace.settings.modify_platform_setting("r_ShaderCompilerServer", host_ip) @@ -186,11 +185,16 @@ class DedicatedLinuxLauncher(LinuxLauncher): :param backupFiles: Bool to backup setup files :param launch_ap: Bool to launch the asset processor + :param configure_settings: Bool to update settings caches :return: None """ + # Backup + if backupFiles: + self.backup_settings() + # Base setup defaults to None if launch_ap is None: - launch_ap = False + launch_ap = True super(DedicatedLinuxLauncher, self).setup(backupFiles, launch_ap, configure_settings) diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py index ec2b3b966c..f989f7bd19 100755 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py @@ -44,7 +44,8 @@ class WinLauncher(Launcher): Subclasses should call its parent's setup() before calling its own code, unless it changes configuration files :param backupFiles: Bool to backup setup files - :param lauch_ap: Bool to lauch the asset processor + :param launch_ap: Bool to lauch the asset processor + :param configure_settings: Bool to update settings caches :return: None """ # Backup @@ -58,7 +59,7 @@ class WinLauncher(Launcher): # Modify and re-configure if configure_settings: self.configure_settings() - super(WinLauncher, self).setup(backupFiles, launch_ap) + super(WinLauncher, self).setup(backupFiles, launch_ap, configure_settings) def launch(self): """ @@ -161,7 +162,7 @@ class WinLauncher(Launcher): def configure_settings(self): """ - Configures system level settings and syncs the launcher to the targeted console IP. + Configures system level settings :return: None """ From 7e93addd5378b1d46a7a8909e2c7259c0824cc88 Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Wed, 1 Dec 2021 12:56:19 +0000 Subject: [PATCH 053/128] LYN-6431 Added materials support to TerrainPhysicsCollider Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- .../TerrainPhysicsColliderComponent.cpp | 74 +++++++++- .../TerrainPhysicsColliderComponent.h | 17 +++ .../Tests/TerrainPhysicsColliderTests.cpp | 132 ++++++++++++++++++ 3 files changed, 219 insertions(+), 4 deletions(-) diff --git a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp index 6c76e90fd0..7942f1ebbd 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp @@ -16,16 +16,47 @@ #include #include +#include #include namespace Terrain { - void TerrainPhysicsColliderConfig::Reflect(AZ::ReflectContext* context) + void TerrainPhysicsSurfaceMaterialMapping::Reflect(AZ::ReflectContext* context) { if (auto serialize = azrtti_cast(context)) { - serialize->Class() + serialize->Class() ->Version(1) + ->Field("Surface", &TerrainPhysicsSurfaceMaterialMapping::m_surfaceTag) + ->Field("Material", &TerrainPhysicsSurfaceMaterialMapping::m_materialId); + + if (auto edit = serialize->GetEditContext()) + { + edit->Class( + "Terrain Surface Gradient Mapping", "Mapping between a surface and a physics material.") + + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Show) + + ->DataElement( + AZ::Edit::UIHandlers::ComboBox, &TerrainPhysicsSurfaceMaterialMapping::m_surfaceTag, "Surface Tag", + "Surface type to map to a physics material.") + ->DataElement(AZ::Edit::UIHandlers::Default, &TerrainPhysicsSurfaceMaterialMapping::m_materialId, "Material ID", "") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->Attribute(AZ::Edit::Attributes::ShowProductAssetFileName, true); + } + } + } + void TerrainPhysicsColliderConfig::Reflect(AZ::ReflectContext* context) + { + TerrainPhysicsSurfaceMaterialMapping::Reflect(context); + + if (auto serialize = azrtti_cast(context)) + { + serialize->Class() + ->Version(2)->Field( + "Mappings", &TerrainPhysicsColliderConfig::m_surfaceMaterialMappings) ; if (auto edit = serialize->GetEditContext()) @@ -35,7 +66,11 @@ namespace Terrain "Provides terrain data to a physics collider with configurable surface mappings.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) - ->Attribute(AZ::Edit::Attributes::AutoExpand, true); + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->DataElement( + AZ::Edit::UIHandlers::Default, &TerrainPhysicsColliderConfig::m_surfaceMaterialMappings, + "Surface to Material Mappings", "Maps surfaces to physics materials") + ; } } } @@ -249,6 +284,22 @@ namespace Terrain } } + uint8_t TerrainPhysicsColliderComponent::FindSurfaceTagIndex(const SurfaceData::SurfaceTag tag) const + { + uint8_t index = 0; + + for (auto& mapping : m_configuration.m_surfaceMaterialMappings) + { + if (mapping.m_surfaceTag == tag) + { + return index; + } + index++; + } + + return InvalidSurfaceTagIndex; + } + void TerrainPhysicsColliderComponent::GenerateHeightsAndMaterialsInBounds( AZStd::vector& heightMaterials) const { @@ -286,9 +337,16 @@ namespace Terrain terrainExists = false; } + // Find the best surface tag at this point. + AzFramework::SurfaceData::SurfaceTagWeight surfaceWeight; + AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult( + surfaceWeight, &AzFramework::Terrain::TerrainDataRequests::GetMaxSurfaceWeightFromFloats, x, y, + AzFramework::Terrain::TerrainDataRequests::Sampler::DEFAULT, nullptr); + Physics::HeightMaterialPoint point; point.m_height = height - worldCenterZ; point.m_quadMeshType = terrainExists ? Physics::QuadMeshType::SubdivideUpperLeftToBottomRight : Physics::QuadMeshType::Hole; + point.m_materialIndex = FindSurfaceTagIndex(surfaceWeight.m_surfaceType); heightMaterials.emplace_back(point); } } @@ -332,7 +390,15 @@ namespace Terrain AZStd::vector TerrainPhysicsColliderComponent::GetMaterialList() const { - return AZStd::vector(); + AZStd::vector materialList; + materialList.reserve(m_configuration.m_surfaceMaterialMappings.size()); + + for (auto& mapping : m_configuration.m_surfaceMaterialMappings) + { + materialList.emplace_back(mapping.m_materialId); + } + + return materialList; } AZStd::vector TerrainPhysicsColliderComponent::GetHeights() const diff --git a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h index 6462909c89..79acca7e71 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h +++ b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -24,6 +25,19 @@ namespace LmbrCentral namespace Terrain { + static const uint8_t InvalidSurfaceTagIndex = 0xFF; + + struct TerrainPhysicsSurfaceMaterialMapping final + { + public: + AZ_CLASS_ALLOCATOR(TerrainPhysicsSurfaceMaterialMapping, AZ::SystemAllocator, 0); + AZ_RTTI(TerrainPhysicsSurfaceMaterialMapping, "{A88B5289-DFCD-4564-8395-E2177DFE5B18}"); + static void Reflect(AZ::ReflectContext* context); + + SurfaceData::SurfaceTag m_surfaceTag; + Physics::MaterialId m_materialId; + }; + class TerrainPhysicsColliderConfig : public AZ::ComponentConfig { @@ -32,6 +46,7 @@ namespace Terrain AZ_RTTI(TerrainPhysicsColliderConfig, "{E9EADB8F-C3A5-4B9C-A62D-2DBC86B4CE59}", AZ::ComponentConfig); static void Reflect(AZ::ReflectContext* context); + AZStd::vector m_surfaceMaterialMappings; }; @@ -77,6 +92,8 @@ namespace Terrain bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override; bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override; + uint8_t FindSurfaceTagIndex(const SurfaceData::SurfaceTag tag) const; + void GenerateHeightsInBounds(AZStd::vector& heights) const; void GenerateHeightsAndMaterialsInBounds(AZStd::vector& heightMaterials) const; diff --git a/Gems/Terrain/Code/Tests/TerrainPhysicsColliderTests.cpp b/Gems/Terrain/Code/Tests/TerrainPhysicsColliderTests.cpp index 8770c1d6dd..b0eb5399cf 100644 --- a/Gems/Terrain/Code/Tests/TerrainPhysicsColliderTests.cpp +++ b/Gems/Terrain/Code/Tests/TerrainPhysicsColliderTests.cpp @@ -290,3 +290,135 @@ TEST_F(TerrainPhysicsColliderComponentTest, TerrainPhysicsColliderReturnsRelativ m_entity->Reset(); } + +TEST_F(TerrainPhysicsColliderComponentTest, TerrainPhysicsColliderReturnsMaterials) +{ + // Check that the TerrainPhysicsCollider returns all the assigned materials. + CreateEntity(); + + m_boxComponent = m_entity->CreateComponent(); + m_app.RegisterComponentDescriptor(m_boxComponent->CreateDescriptor()); + + // Create two SurfaceTag/Material mappings and add them to the collider. + Terrain::TerrainPhysicsColliderConfig config; + + const Physics::MaterialId mat1 = Physics::MaterialId::Create(); + const Physics::MaterialId mat2 = Physics::MaterialId::Create(); + + const SurfaceData::SurfaceTag tag1 = SurfaceData::SurfaceTag("tag1"); + const SurfaceData::SurfaceTag tag2 = SurfaceData::SurfaceTag("tag2"); + + Terrain::TerrainPhysicsSurfaceMaterialMapping mapping1; + mapping1.m_materialId = mat1; + mapping1.m_surfaceTag = tag1; + config.m_surfaceMaterialMappings.emplace_back(mapping1); + + Terrain::TerrainPhysicsSurfaceMaterialMapping mapping2; + mapping2.m_materialId = mat2; + mapping2.m_surfaceTag = tag2; + config.m_surfaceMaterialMappings.emplace_back(mapping2); + + m_colliderComponent = m_entity->CreateComponent(config); + m_app.RegisterComponentDescriptor(m_colliderComponent->CreateDescriptor()); + + m_entity->Activate(); + + AZStd::vector materialList; + Physics::HeightfieldProviderRequestsBus::EventResult( + materialList, m_entity->GetId(), &Physics::HeightfieldProviderRequestsBus::Events::GetMaterialList); + + EXPECT_EQ(materialList.size(), 2); + + EXPECT_EQ(materialList[0], mat1); + EXPECT_EQ(materialList[1], mat2); + + m_entity.reset(); +} + +TEST_F(TerrainPhysicsColliderComponentTest, TerrainPhysicsColliderGetHeightsAndMaterialsReturnsCorrectly) +{ + // Check that the TerrainPhysicsCollider returns a heightfield of the expected size. + CreateEntity(); + + m_boxComponent = m_entity->CreateComponent(); + m_app.RegisterComponentDescriptor(m_boxComponent->CreateDescriptor()); + + // Create two SurfaceTag/Material mappings and add them to the collider. + Terrain::TerrainPhysicsColliderConfig config; + + const Physics::MaterialId mat1 = Physics::MaterialId::Create(); + const Physics::MaterialId mat2 = Physics::MaterialId::Create(); + + const SurfaceData::SurfaceTag tag1 = SurfaceData::SurfaceTag("tag1"); + const SurfaceData::SurfaceTag tag2 = SurfaceData::SurfaceTag("tag2"); + + Terrain::TerrainPhysicsSurfaceMaterialMapping mapping1; + mapping1.m_materialId = mat1; + mapping1.m_surfaceTag = tag1; + config.m_surfaceMaterialMappings.emplace_back(mapping1); + + Terrain::TerrainPhysicsSurfaceMaterialMapping mapping2; + mapping2.m_materialId = mat2; + mapping2.m_surfaceTag = tag2; + config.m_surfaceMaterialMappings.emplace_back(mapping2); + + m_colliderComponent = m_entity->CreateComponent(config); + m_app.RegisterComponentDescriptor(m_colliderComponent->CreateDescriptor()); + + m_entity->Activate(); + + const AZ::Vector3 boundsMin = AZ::Vector3(0.0f); + const AZ::Vector3 boundsMax = AZ::Vector3(256.0f, 256.0f, 32768.0f); + + NiceMock boxShape(m_entity->GetId()); + const AZ::Aabb bounds = AZ::Aabb::CreateFromMinMax(boundsMin, boundsMax); + ON_CALL(boxShape, GetEncompassingAabb).WillByDefault(Return(bounds)); + + const float mockHeight = 32768.0f; + AZ::Vector2 mockHeightResolution = AZ::Vector2(1.0f); + + AzFramework::SurfaceData::SurfaceTagWeight return1; + return1.m_surfaceType = tag1; + return1.m_weight = 1.0f; + + AzFramework::SurfaceData::SurfaceTagWeight return2; + return2.m_surfaceType = tag2; + return2.m_weight = 1.0f; + + NiceMock terrainListener; + ON_CALL(terrainListener, GetTerrainHeightQueryResolution).WillByDefault(Return(mockHeightResolution)); + ON_CALL(terrainListener, GetHeightFromFloats).WillByDefault(Return(mockHeight)); + ON_CALL(terrainListener, GetMaxSurfaceWeightFromFloats) + .WillByDefault( + [return1, return2]( + [[maybe_unused]] float x, [[maybe_unused]] float y, + [[maybe_unused]] AzFramework::Terrain::TerrainDataRequests::Sampler sampleFilter, [[maybe_unused]] bool* terrainExistsPtr) + { + // return tag1 for the first half of the rows, tag2 for the rest. + if (y < 128.0) + { + return return1; + } + return return2; + }); + + AZStd::vector heightsAndMaterials; + + Physics::HeightfieldProviderRequestsBus::EventResult( + heightsAndMaterials, m_entity->GetId(), &Physics::HeightfieldProviderRequestsBus::Events::GetHeightsAndMaterials); + + // We set the bounds to 256, so check that the correct number of entries are present. + EXPECT_EQ(heightsAndMaterials.size(), 256 * 256); + + const float expectedHeightValue = 16384.0f; + + // Check an entry from the first half of the returned list. + EXPECT_EQ(heightsAndMaterials[0].m_materialIndex, 0); + EXPECT_NEAR(heightsAndMaterials[0].m_height, expectedHeightValue, 0.01f); + + // Check an entry from the second half of the list + EXPECT_EQ(heightsAndMaterials[256 * 128].m_materialIndex, 1); + EXPECT_NEAR(heightsAndMaterials[256 * 128].m_height, expectedHeightValue, 0.01f); + + m_entity.reset(); +} From 75b3393892fcc3baff4749b56c02a46adffd1b32 Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Wed, 1 Dec 2021 14:50:43 +0000 Subject: [PATCH 054/128] text change Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- .../Code/Source/Components/TerrainPhysicsColliderComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp index 7942f1ebbd..6572b008b3 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp @@ -33,7 +33,7 @@ namespace Terrain if (auto edit = serialize->GetEditContext()) { edit->Class( - "Terrain Surface Gradient Mapping", "Mapping between a surface and a physics material.") + "Terrain Surface Material Mapping", "Mapping between a surface and a physics material.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) From e0508ddefc315f3d693a9b5c82a0fe835af1969e Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Wed, 1 Dec 2021 12:10:22 -0800 Subject: [PATCH 055/128] Make JsonBackend templated Signed-off-by: Nicholas Van Sickle --- .../AzCore/DOM/Backends/JSON/JsonBackend.cpp | 27 -------------- .../AzCore/DOM/Backends/JSON/JsonBackend.h | 21 +++++++++-- .../Backends/JSON/JsonSerializationUtils.h | 35 ++++++++++++------- .../AzCore/AzCore/azcore_files.cmake | 1 - 4 files changed, 41 insertions(+), 43 deletions(-) delete mode 100644 Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.cpp diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.cpp b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.cpp deleted file mode 100644 index 288d3c0699..0000000000 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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 - -namespace AZ::Dom -{ - Visitor::Result JsonBackend::ReadFromStringInPlace(AZStd::string& buffer, Visitor& visitor) - { - return Json::VisitSerializedJsonInPlace(buffer, visitor); - } - - Visitor::Result JsonBackend::ReadFromString(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor) - { - return Json::VisitSerializedJson(buffer, lifetime, visitor); - } - - AZStd::unique_ptr JsonBackend::CreateStreamWriter(AZ::IO::GenericStream& stream) - { - return Json::GetJsonStreamWriter(stream, Json::OutputFormatting::PrettyPrintedJson); - } -} diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h index 536fec7418..1ecfa3fb37 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h @@ -13,11 +13,26 @@ namespace AZ::Dom { + //! A DOM backend for serializing and deserializing JSON <=> UTF-8 text + //! \param ParseFlags Controls how deserialized JSON is parsed. + //! \param WriteFormat Controls how serialized JSON is formatted. + template class JsonBackend final : public Backend { public: - Visitor::Result ReadFromStringInPlace(AZStd::string& buffer, Visitor& visitor) override; - Visitor::Result ReadFromString(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor) override; - AZStd::unique_ptr CreateStreamWriter(AZ::IO::GenericStream& stream) override; + Visitor::Result ReadFromStringInPlace(AZStd::string& buffer, Visitor& visitor) override + { + return Json::VisitSerializedJsonInPlace(buffer, visitor); + } + + Visitor::Result ReadFromString(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor) override + { + return Json::VisitSerializedJson(buffer, lifetime, visitor); + } + + AZStd::unique_ptr CreateStreamWriter(AZ::IO::GenericStream& stream) override + { + return Json::GetJsonStreamWriter(stream, WriteFormat); + } }; } // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h index be055d7f5c..4197209b8e 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h @@ -26,6 +26,21 @@ namespace AZ::Dom::Json PrettyPrintedJson, //!< Formats JSON in a pretty printed form, focusing on legibility to readers. }; + //! Specifies parsing behavior when deserializing JSON. + enum class ParseFlags : int + { + Null = 0, + StopWhenDone = rapidjson::kParseStopWhenDoneFlag, + FullFloatingPointPrecision = rapidjson::kParseFullPrecisionFlag, + ParseComments = rapidjson::kParseCommentsFlag, + ParseNumbersAsStrings = rapidjson::kParseNumbersAsStringsFlag, + ParseTrailingCommas = rapidjson::kParseTrailingCommasFlag, + ParseNanAndInfinity = rapidjson::kParseNanAndInfFlag, + ParseEscapedApostrophies = rapidjson::kParseEscapedApostropheFlag, + }; + + AZ_DEFINE_ENUM_BITWISE_OPERATORS(ParseFlags); + //! Visitor that feeds into a rapidjson::Value class RapidJsonValueWriter final : public Visitor { @@ -128,16 +143,18 @@ namespace AZ::Dom::Json //! \param lifetime Specifies the lifetime of the specified buffer. If the string specified by buffer might be deallocated, //! ensure Lifetime::Temporary is specified. //! \param visitor The visitor to visit with the JSON buffer's contents. + //! \param parseFlags (template) Settings for adjusting parser behavior. //! \return The aggregate result specifying whether the visitor operations were successful. - template + template Visitor::Result VisitSerializedJson(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor); //! Reads serialized JSON from a string in-place and applies it to a visitor. //! \param buffer The UTF-8 serialized JSON to read. This buffer will be modified as part of the deserialization process to //! apply null terminators. //! \param visitor The visitor to visit with the JSON buffer's contents. The strings provided to the visitor will only //! be valid for the lifetime of buffer. + //! \param parseFlags (template) Settings for adjusting parser behavior. //! \return The aggregate result specifying whether the visitor operations were successful. - template + template Visitor::Result VisitSerializedJsonInPlace(AZStd::string& buffer, Visitor& visitor); //! Takes a visitor specified by a callback and produces a rapidjson::Document. @@ -159,31 +176,25 @@ namespace AZ::Dom::Json //! \return The aggregate result specifying whether the visitor operations were successful. Visitor::Result VisitRapidJsonValue(const rapidjson::Value& value, Visitor& visitor, Lifetime lifetime); - template + template Visitor::Result VisitSerializedJson(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor) { - static_assert( - (ParseFlags & rapidjson::kParseInsituFlag) == 0, - "VisitSerializedJsonInPlace requires kParseInSituFlag not to be set, use VisitSerializedJsonInPlace to parse in-situ"); - rapidjson::Reader reader; rapidjson::MemoryStream stream(buffer.data(), buffer.size()); RapidJsonReadHandler handler(&visitor, lifetime); - reader.Parse(stream, handler); + reader.Parse(parseFlags)>(stream, handler); return handler.TakeOutcome(); } - template + template Visitor::Result VisitSerializedJsonInPlace(AZStd::string& buffer, Visitor& visitor) { - static_assert((ParseFlags & rapidjson::kParseInsituFlag) != 0, "VisitSerializedJsonInPlace requires kParseInSituFlag to be set"); - rapidjson::Reader reader; AzStringStream stream(buffer); RapidJsonReadHandler handler(&visitor, Lifetime::Persistent); - reader.Parse(stream, handler); + reader.Parse(parseFlags) | rapidjson::kParseInsituFlag>(stream, handler); return handler.TakeOutcome(); } } // namespace AZ::Dom::Json diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index ecc7a41ba1..8557773c93 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -129,7 +129,6 @@ set(FILES DOM/DomBackend.h DOM/DomVisitor.cpp DOM/DomVisitor.h - DOM/Backends/JSON/JsonBackend.cpp DOM/Backends/JSON/JsonBackend.h DOM/Backends/JSON/JsonSerializationUtils.cpp DOM/Backends/JSON/JsonSerializationUtils.h From fd45a37c7b2504522f5faa63f70d0e6dbf36fa3f Mon Sep 17 00:00:00 2001 From: sweeneys Date: Wed, 1 Dec 2021 14:13:13 -0800 Subject: [PATCH 056/128] Restore defaults, clarify comment Signed-off-by: sweeneys --- .../launchers/platforms/android/launcher.py | 2 +- .../launchers/platforms/linux/launcher.py | 6 ++--- .../launchers/platforms/win/launcher.py | 22 ++++++++++++++++++- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py index 7c3efd9e9d..9433f426b5 100755 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py @@ -177,7 +177,7 @@ class AndroidLauncher(Launcher): if backupFiles: self.backup_settings() - # Base setup defaults to None + # None reverts to function default if launch_ap is None: launch_ap = True diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py index 96e827069e..377121f2e0 100644 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py @@ -52,7 +52,7 @@ class LinuxLauncher(Launcher): if backupFiles: self.backup_settings() - # Base setup defaults to None + # None reverts to function default if launch_ap is None: launch_ap = True @@ -192,9 +192,9 @@ class DedicatedLinuxLauncher(LinuxLauncher): if backupFiles: self.backup_settings() - # Base setup defaults to None + # None reverts to function default if launch_ap is None: - launch_ap = True + launch_ap = False super(DedicatedLinuxLauncher, self).setup(backupFiles, launch_ap, configure_settings) diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py index f989f7bd19..c29aa7b10b 100755 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py @@ -52,7 +52,7 @@ class WinLauncher(Launcher): if backupFiles: self.backup_settings() - # Base setup defaults to None + # None reverts to function default if launch_ap is None: launch_ap = True @@ -177,6 +177,26 @@ class WinLauncher(Launcher): class DedicatedWinLauncher(WinLauncher): + def setup(self, backupFiles=True, launch_ap=False, configure_settings=True): + """ + Perform setup of this launcher, must be called before launching. + Subclasses should call its parent's setup() before calling its own code, unless it changes configuration files + + :param backupFiles: Bool to backup setup files + :param launch_ap: Bool to launch the asset processor + :param configure_settings: Bool to update settings caches + :return: None + """ + # Backup + if backupFiles: + self.backup_settings() + + # None reverts to function default + if launch_ap is None: + launch_ap = False + + super(DedicatedWinLauncher, self).setup(backupFiles, launch_ap, configure_settings) + def binary_path(self): """ Return full path to the dedicated server launcher for the build directory. From d519d4cb030bda67b4023c9677116801c858330c Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Wed, 1 Dec 2021 16:22:48 -0800 Subject: [PATCH 057/128] Improve performance for both in-place and copy parsing (faster than `AZ::JsonSerializationUtils::ReadJsonString` now!) Signed-off-by: Nicholas Van Sickle --- .../Backends/JSON/JsonSerializationUtils.cpp | 51 ------------ .../Backends/JSON/JsonSerializationUtils.h | 77 ++++++++++++++++--- 2 files changed, 66 insertions(+), 62 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp index 84f663f97c..104082ce54 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp @@ -413,57 +413,6 @@ namespace AZ::Dom::Json return true; } - // - // struct AzStringStream - // - // rapidjson stream wrapper for AZStd::string suitable for in-situ parsing - AzStringStream::AzStringStream(AZStd::string& buffer) - { - m_cursor = buffer.data(); - m_begin = m_cursor; - } - - char AzStringStream::Peek() const - { - return *m_cursor; - } - - char AzStringStream::Take() - { - return *m_cursor++; - } - - size_t AzStringStream::Tell() const - { - return static_cast(m_cursor - m_begin); - } - - char* AzStringStream::PutBegin() - { - m_write = m_cursor; - return m_cursor; - } - - void AzStringStream::Put(char c) - { - (*m_write++) = c; - } - - void AzStringStream::Flush() - { - } - - size_t AzStringStream::PutEnd(char* begin) - { - return m_write - begin; - } - - const char* AzStringStream::Peek4() const - { - AZ_Assert(false, "Not implemented, encoding is hard-coded to UTF-8"); - return m_cursor; - } - // // Serialized JSON util functions // diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h index 4197209b8e..5e7976568b 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h @@ -113,19 +113,65 @@ namespace AZ::Dom::Json }; //! rapidjson stream wrapper for AZStd::string suitable for in-situ parsing + //! Faster than rapidjson::MemoryStream for reading from AZStd::string / AZStd::string_view (because it requires a null terminator) + //! \note This needs to be inlined for performance reasons. struct AzStringStream { using Ch = char; //(buffer.data()); + m_begin = m_cursor; + } + + AZ_FORCE_INLINE char Peek() const + { + return *m_cursor; + } + + AZ_FORCE_INLINE char Take() + { + return *m_cursor++; + } + + AZ_FORCE_INLINE size_t Tell() const + { + return static_cast(m_cursor - m_begin); + } + + AZ_FORCE_INLINE char* PutBegin() + { + m_write = m_cursor; + return m_cursor; + } + + AZ_FORCE_INLINE void Put(char c) + { + (*m_write++) = c; + } + + AZ_FORCE_INLINE void Flush() + { + } + + AZ_FORCE_INLINE size_t PutEnd(char* begin) + { + return m_write - begin; + } + + AZ_FORCE_INLINE const char* Peek4() const + { + AZ_Assert(false, "Not implemented, encoding is hard-coded to UTF-8"); + return m_cursor; + } char* m_cursor; //!< Current read position. char* m_write; //!< Current write position. @@ -180,10 +226,19 @@ namespace AZ::Dom::Json Visitor::Result VisitSerializedJson(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor) { rapidjson::Reader reader; - rapidjson::MemoryStream stream(buffer.data(), buffer.size()); RapidJsonReadHandler handler(&visitor, lifetime); - reader.Parse(parseFlags)>(stream, handler); + // If the string is null terminated, we can use the faster AzStringStream path - otherwise we fall back on rapidjson::MemoryStream + if (buffer.data()[buffer.size()] == '\0') + { + AzStringStream stream(buffer); + reader.Parse(parseFlags)>(stream, handler); + } + else + { + rapidjson::MemoryStream stream(buffer.data(), buffer.size()); + reader.Parse(parseFlags)>(stream, handler); + } return handler.TakeOutcome(); } From 2dddb97b7c01ed13fdcd4a6f2987a071fce4dfea Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Wed, 1 Dec 2021 16:32:23 -0800 Subject: [PATCH 058/128] One last round of stray review feedback I missed Signed-off-by: Nicholas Van Sickle --- .../Backends/JSON/JsonSerializationUtils.cpp | 30 +++++++++---------- .../AzCore/AzCore/DOM/DomVisitor.cpp | 5 ---- Code/Framework/AzCore/AzCore/DOM/DomVisitor.h | 6 ++-- 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp index 104082ce54..8d8c8463ff 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp @@ -70,11 +70,11 @@ namespace AZ::Dom::Json { if (lifetime == Lifetime::Temporary) { - CurrentValue().SetString(value.data(), static_cast(value.length()), m_allocator); + CurrentValue().SetString(value.data(), aznumeric_cast(value.length()), m_allocator); } else { - CurrentValue().SetString(value.data(), static_cast(value.length())); + CurrentValue().SetString(value.data(), aznumeric_cast(value.length())); } return FinishWrite(); } @@ -102,7 +102,7 @@ namespace AZ::Dom::Json if (m_entryStack.front().m_entryCount != attributeCount) { - return FormatVisitorFailure( + return VisitorFailure( VisitorErrorCode::InternalError, "EndObject: Expected %lu attributes but received %lu attributes instead", attributeCount, m_entryStack.front().m_entryCount); } @@ -122,11 +122,11 @@ namespace AZ::Dom::Json AZ_Assert(m_entryStack.front().m_isObject, "Attempted to push a key to an array"); if (lifetime == Lifetime::Persistent) { - m_entryStack.front().m_key.SetString(key.data(), static_cast(key.size())); + m_entryStack.front().m_key.SetString(key.data(), aznumeric_cast(key.size())); } else { - m_entryStack.front().m_key.SetString(key.data(), static_cast(key.size()), m_allocator); + m_entryStack.front().m_key.SetString(key.data(), aznumeric_cast(key.size()), m_allocator); } return VisitorSuccess(); } @@ -154,7 +154,7 @@ namespace AZ::Dom::Json if (m_entryStack.front().m_entryCount != elementCount) { - return FormatVisitorFailure( + return VisitorFailure( VisitorErrorCode::InternalError, "EndArray: Expected %lu elements but received %lu elements instead", elementCount, m_entryStack.front().m_entryCount); } @@ -250,7 +250,7 @@ namespace AZ::Dom::Json Result String(AZStd::string_view value, Lifetime lifetime) override { const bool shouldCopy = lifetime == Lifetime::Temporary; - return CheckWrite(m_writer.String(value.data(), static_cast(value.size()), shouldCopy)); + return CheckWrite(m_writer.String(value.data(), aznumeric_cast(value.size()), shouldCopy)); } Result StartObject() override @@ -260,7 +260,7 @@ namespace AZ::Dom::Json Result EndObject(AZ::u64 attributeCount) override { - return CheckWrite(m_writer.EndObject(static_cast(attributeCount))); + return CheckWrite(m_writer.EndObject(aznumeric_cast(attributeCount))); } Result Key(AZ::Name key) override @@ -271,7 +271,7 @@ namespace AZ::Dom::Json Result RawKey(AZStd::string_view key, Lifetime lifetime) override { const bool shouldCopy = lifetime == Lifetime::Temporary; - return CheckWrite(m_writer.Key(key.data(), static_cast(key.size()), shouldCopy)); + return CheckWrite(m_writer.Key(key.data(), aznumeric_cast(key.size()), shouldCopy)); } Result StartArray() override @@ -281,7 +281,7 @@ namespace AZ::Dom::Json Result EndArray(AZ::u64 elementCount) override { - return CheckWrite(m_writer.EndArray(static_cast(elementCount))); + return CheckWrite(m_writer.EndArray(aznumeric_cast(elementCount))); } private: @@ -323,12 +323,12 @@ namespace AZ::Dom::Json bool RapidJsonReadHandler::Int(int i) { - return CheckResult(m_visitor->Int64(static_cast(i))); + return CheckResult(m_visitor->Int64(aznumeric_cast(i))); } bool RapidJsonReadHandler::Uint(unsigned i) { - return CheckResult(m_visitor->Uint64(static_cast(i))); + return CheckResult(m_visitor->Uint64(aznumeric_cast(i))); } bool RapidJsonReadHandler::Int64(int64_t i) @@ -472,7 +472,7 @@ namespace AZ::Dom::Json while (!entryStack.empty()) { - const auto currentEntry = entryStack.top(); + const Entry currentEntry = entryStack.top(); entryStack.pop(); Visitor::Result result = AZ::Success(); @@ -507,7 +507,7 @@ namespace AZ::Dom::Json for (auto it = currentValue.MemberEnd(); it != currentValue.MemberBegin(); --it) { auto entry = (it - 1); - const AZStd::string_view key(entry->name.GetString(), static_cast(entry->name.GetStringLength())); + const AZStd::string_view key(entry->name.GetString(), aznumeric_cast(entry->name.GetStringLength())); entryStack.push(&entry->value); entryStack.push(key); } @@ -524,7 +524,7 @@ namespace AZ::Dom::Json break; case rapidjson::kStringType: result = visitor.String( - AZStd::string_view(currentValue.GetString(), static_cast(currentValue.GetStringLength())), + AZStd::string_view(currentValue.GetString(), aznumeric_cast(currentValue.GetStringLength())), lifetime); break; case rapidjson::kNumberType: diff --git a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp index ad314da385..d5190cbbac 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp @@ -60,11 +60,6 @@ namespace AZ::Dom return AZ::Failure(VisitorError(code)); } - Visitor::Result Visitor::VisitorFailure(VisitorErrorCode code, AZStd::string additionalInfo) - { - return AZ::Failure(VisitorError(code, AZStd::move(additionalInfo))); - } - Visitor::Result Visitor::VisitorFailure(VisitorError error) { return AZ::Failure(error); diff --git a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h index f36ad8d827..c0da56036e 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h +++ b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h @@ -227,17 +227,15 @@ namespace AZ::Dom //! Helper method, constructs a failure \ref Result with the specified code. static Result VisitorFailure(VisitorErrorCode code); - //! Helper method, constructs a failure \ref Result with the specified code and supplemental info. - static Result VisitorFailure(VisitorErrorCode code, AZStd::string additionalInfo); //! Helper method, constructs a failure \ref Result with the specified error. static Result VisitorFailure(VisitorError error); //! Helper method, constructs a failure \ref Result with the specified code and supplemental info specified by a format string //! and its arguments. template - static Result FormatVisitorFailure(VisitorErrorCode code, TArgs... formatArgs) + static Result VisitorFailure(VisitorErrorCode code, TArgs... formatArgs) { - return VisitorFailure(code, AZStd::string::format(formatArgs...)); + return AZ::Failure(VisitorError(code, AZStd::string::format(formatArgs...))); } //! Helper method, constructs a success \ref Result. From b1c0d1e12b32ce49d7b11f42a0cab54e853b2995 Mon Sep 17 00:00:00 2001 From: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> Date: Wed, 1 Dec 2021 18:41:31 -0600 Subject: [PATCH 059/128] Enabling optimized test runner for Prefab tests Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> --- .../Gem/PythonTests/Prefab/CMakeLists.txt | 2 +- .../Prefab/TestSuite_Main_Optimized.py | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main_Optimized.py diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/Prefab/CMakeLists.txt index 48c24d1ebf..629db72dc7 100644 --- a/AutomatedTesting/Gem/PythonTests/Prefab/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/Prefab/CMakeLists.txt @@ -12,7 +12,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) NAME AutomatedTesting::PrefabTests TEST_SUITE main TEST_SERIAL - PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main.py + PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_Optimized.py RUNTIME_DEPENDENCIES Legacy::Editor AZ::AssetProcessor diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main_Optimized.py new file mode 100644 index 0000000000..881fc46a93 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main_Optimized.py @@ -0,0 +1,58 @@ +""" +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 +""" + +import pytest + +from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite + + +@pytest.mark.SUITE_main +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomationAutoTestMode(EditorTestSuite): + + class test_OpenLevel_ContainingTwoEntities(EditorSharedTest): + from .tests.open_level import OpenLevel_ContainingTwoEntities as test_module + + class test_CreatePrefab_WithSingleEntity(EditorSharedTest): + from .tests.create_prefab import CreatePrefab_WithSingleEntity as test_module + + class test_InstantiatePrefab_ContainingASingleEntity(EditorSharedTest): + from .tests.instantiate_prefab import InstantiatePrefab_ContainingASingleEntity as test_module + + class test_DeletePrefab_ContainingASingleEntity(EditorSharedTest): + from .tests.delete_prefab import DeletePrefab_ContainingASingleEntity as test_module + + class test_DuplicatePrefab_ContainingASingleEntity(EditorSharedTest): + from .tests.duplicate_prefab import DuplicatePrefab_ContainingASingleEntity as test_module + + +@pytest.mark.SUITE_main +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomationNoAutoTestMode(EditorTestSuite): + + # Enable only -BatchMode for these tests. Tests cannot run in -autotest_mode due to UI interactions + global_extra_cmdline_args = ["-BatchMode"] + + class test_CreatePrefab_UnderAnEntity(EditorSharedTest): + from .tests.create_prefab import CreatePrefab_UnderAnEntity as test_module + + class test_CreatePrefab_UnderAnotherPrefab(EditorSharedTest): + from .tests.create_prefab import CreatePrefab_UnderAnotherPrefab as test_module + + class test_DeleteEntity_UnderAnotherPrefab(EditorSharedTest): + from .tests.delete_entity import DeleteEntity_UnderAnotherPrefab as test_module + + class test_DeleteEntity_UnderLevelPrefab(EditorSharedTest): + from .tests.delete_entity import DeleteEntity_UnderLevelPrefab as test_module + + class test_ReparentPrefab_UnderAnotherPrefab(EditorSharedTest): + from .tests.reparent_prefab import ReparentPrefab_UnderAnotherPrefab as test_module + + class test_DetachPrefab_UnderAnotherPrefab(EditorSharedTest): + from .tests.detach_prefab import DetachPrefab_UnderAnotherPrefab as test_module From 1aaa2675857da20b16b5b2b65e3dc542c00f6fe1 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Wed, 1 Dec 2021 16:49:48 -0800 Subject: [PATCH 060/128] Fix one last bit of minor feedback Signed-off-by: Nicholas Van Sickle --- Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h | 2 +- .../AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp | 2 +- .../AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h index 1ecfa3fb37..ace21d9be8 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h @@ -32,7 +32,7 @@ namespace AZ::Dom AZStd::unique_ptr CreateStreamWriter(AZ::IO::GenericStream& stream) override { - return Json::GetJsonStreamWriter(stream, WriteFormat); + return Json::CreateJsonStreamWriter(stream, WriteFormat); } }; } // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp index 8d8c8463ff..66851f1a40 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp @@ -416,7 +416,7 @@ namespace AZ::Dom::Json // // Serialized JSON util functions // - AZStd::unique_ptr GetJsonStreamWriter(AZ::IO::GenericStream& stream, OutputFormatting format) + AZStd::unique_ptr CreateJsonStreamWriter(AZ::IO::GenericStream& stream, OutputFormatting format) { if (format == OutputFormatting::MinifiedJson) { diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h index 5e7976568b..88c6c42978 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h @@ -182,7 +182,7 @@ namespace AZ::Dom::Json //! \param stream The stream the visitor will write to. //! \param format The format to write in. //! \return A Visitor that will write to stream when visited. - AZStd::unique_ptr GetJsonStreamWriter( + AZStd::unique_ptr CreateJsonStreamWriter( AZ::IO::GenericStream& stream, OutputFormatting format = OutputFormatting::PrettyPrintedJson); //! Reads serialized JSON from a string and applies it to a visitor. //! \param buffer The UTF-8 serialized JSON to read. From cc76ee58a7d4863cd239aced499fc7de3731147d Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Wed, 1 Dec 2021 18:46:58 -0800 Subject: [PATCH 061/128] update light component constant, fixed the return value for find_editor_entity(), removed old GPU test scripts, added new GPU test scripts Signed-off-by: jromnoa <80134229+jromnoa@users.noreply.github.com> --- .../Atom/atom_utils/atom_constants.py | 5 + .../hydra_AtomGPU_SpotLightScreenshotTest.py | 217 ++++++++++++++- .../tests/hydra_GPUTest_BasicLevelSetup.py | 200 -------------- .../tests/hydra_GPUTest_LightComponent.py | 261 ------------------ .../editor_entity_utils.py | 24 +- 5 files changed, 226 insertions(+), 481 deletions(-) delete mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py delete mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py index 2655a79fde..559f4aebee 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py @@ -257,8 +257,13 @@ class AtomComponentProperties: 'name': 'Light', 'Attenuation Radius Mode': 'Controller|Configuration|Attenuation radius|Mode', 'Color': 'Controller|Configuration|Color', + 'Enable shadow': 'Controller|Configuration|Shadows|Enable shadow', + 'Enable shutters': 'Controller|Configuration|Shutters|Enable shutters', + 'Inner angle': 'Controller|Configuration|Shutters|Inner angle', 'Intensity': 'Controller|Configuration|Intensity', 'Light type': 'Controller|Configuration|Light type', + 'Outer angle': 'Controller|Configuration|Shutters|Outer angle', + 'Shadowmap size': 'Controller|Configuration|Shadows|Shadowmap size', } return properties[property] diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py index e7ac32b339..9b1c88a4fc 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py @@ -7,9 +7,54 @@ SPDX-License-Identifier: Apache-2.0 OR MIT class Tests: - tbd = ( - "tbd", - "tbd") + directional_light_component_disabled = ( + "Disabled Directional Light component", + "Couldn't disable Directional Light component") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + global_skylight_component_disabled = ( + "Disabled Global Skylight (IBL) component", + "Couldn't disable Global Skylight (IBL) component") + hdri_skybox_component_disabled = ( + "Disabled HDRi Skybox component", + "Couldn't disable HDRi Skybox component") + light_component_added = ( + "Light component added", + "Couldn't add Light component") + light_component_color_property_set = ( + "Color property was set", + "Color property was not set") + light_component_enable_shadow_property_set = ( + "Enable shadow property was set", + "Enable shadow property was not set") + light_component_enable_shutters_property_set = ( + "Enable shutters property was set", + "Enable shutters property was not set") + light_component_inner_angle_property_set = ( + "Inner angle property was set", + "Inner angle property was not set") + light_component_intensity_property_set = ( + "Intensity property was set", + "Intensity property was not set") + light_component_light_type_property_set = ( + "Light type property was set", + "Light type property was not set") + light_component_outer_angle_property_set = ( + "Outer angle property was set", + "Outer angle property was not set") + light_component_shadowmap_size_property_set = ( + "Shadowmap size was set", + "Shadowmap size was not set") + material_component_material_asset_property_set = ( + "Material Asset property was set", + "Material Asset property was not set") + spot_light_entity_created = ( + "Spot Light entity created", + "Couldn't create Spot Light entity") def AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages(): @@ -28,17 +73,26 @@ def AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages(): The test scripts sets up the scenes correctly and takes accurate screenshots. Test Steps: - 1. Add Directional Light component to the existing Directional Light entity. - 2. + 1. Find the Directional Light entity then disable its Directional Light component. + 2. Disable Global Skylight (IBL) and HDRi Skybox components on the Global Skylight entity. + + :return: None """ + import os import azlmbr.legacy.general as general import azlmbr.paths + from editor_python_test_tools.asset_utils import Asset + from editor_python_test_tools.editor_entity_utils import EditorEntity from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties, LIGHT_TYPES from Atom.atom_utils.atom_component_helper import initial_viewport_setup, create_basic_atom_rendering_scene + from Atom.atom_utils.screenshot_utils import ScreenshotHelper + + DEGREE_RADIAN_FACTOR = 0.0174533 with Tracer() as error_tracer: # Test setup begins. @@ -56,14 +110,153 @@ def AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages(): create_basic_atom_rendering_scene() # Test steps begin. - # 1. + # 1. Find the Directional Light entity then disable its Directional Light component. + directional_light_name = AtomComponentProperties.directional_light() + directional_light_entity = EditorEntity.find_editor_entity(directional_light_name) + directional_light_component = directional_light_entity.get_components_of_type([directional_light_name])[0] + directional_light_component.disable_component() + Report.critical_result(Tests.directional_light_component_disabled, not directional_light_component.is_enabled()) - # ???. Look for errors. - TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) - for error_info in error_tracer.errors: - Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") - for assert_info in error_tracer.asserts: - Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") + # 2. Disable Global Skylight (IBL) component on the Global Skylight (IBL) entity. + global_skylight_name = AtomComponentProperties.global_skylight() + global_skylight_entity = EditorEntity.find_editor_entity(global_skylight_name) + global_skylight_component = global_skylight_entity.get_components_of_type([global_skylight_name])[0] + global_skylight_component.disable_component() + Report.critical_result(Tests.global_skylight_component_disabled, not global_skylight_component.is_enabled()) + + # 3. Disable HDRi Skybox component on the Global Skylight (IBL) entity + hdri_skybox_name = AtomComponentProperties.hdri_skybox() + hdri_skybox_component = global_skylight_entity.get_components_of_type([hdri_skybox_name])[0] + hdri_skybox_component.disable_component() + Report.critical_result(Tests.hdri_skybox_component_disabled, not hdri_skybox_component.is_enabled()) + + # 4. Create a Spot Light entity and rotate it. + spot_light_name = "Spot Light" + spot_light_entity = EditorEntity.create_editor_entity_at( + azlmbr.math.Vector3(0.7, -2.0, 1.0), spot_light_name) + rotation = azlmbr.math.Vector3(DEGREE_RADIAN_FACTOR * 300.0, 0.0, 0.0) + spot_light_entity.set_local_rotation(rotation) + Report.critical_result(Tests.spot_light_entity_created, spot_light_entity.exists()) + + # 5. Attach a Light component to the Spot Light entity. + light_name = AtomComponentProperties.light() + light_component = spot_light_entity.add_component(light_name) + Report.critical_result(Tests.light_component_added, light_component.is_enabled()) + + # 6. Set the Light component Light Type to Spot (disk). + light_component.set_component_property_value( + AtomComponentProperties.light('Light type'), LIGHT_TYPES['spot_disk']) + Report.result( + Tests.light_component_light_type_property_set, + light_component.get_component_property_value( + AtomComponentProperties.light('Light type')) == LIGHT_TYPES['spot_disk']) + + # 7. Enter game mode and take a screenshot then exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) + ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("SpotLight_1.ppm") + TestHelper.exit_game_mode(Tests.exit_game_mode) + TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + + # 8. Change the default material asset for the Ground Plane entity. + ground_plane_name = "Ground Plane" + ground_plane_entity = EditorEntity.find_editor_entity(ground_plane_name) + ground_plane_material_component_name = AtomComponentProperties.material() + ground_plane_material_component = ground_plane_entity.get_components_of_type( + [ground_plane_material_component_name])[0] + ground_plane_material_asset_path = os.path.join( + "Materials", "Presets", "Macbeth", "22_neutral_5-0_0-70d.azmaterial") + ground_plane_material_asset = Asset.find_asset_by_path(ground_plane_material_asset_path, False) + ground_plane_material_component.set_component_property_value( + AtomComponentProperties.material('Material Asset'), ground_plane_material_asset.id) + Report.result( + Tests.material_component_material_asset_property_set, + light_component.get_component_property_value(AtomComponentProperties.material('Material Asset'))) + + # 9. Enter game mode and take a screenshot then exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) + ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("SpotLight_2.ppm") + TestHelper.exit_game_mode(Tests.exit_game_mode) + TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + + # 10. Increase the Intensity value of the Light component. + light_component.set_component_property_value(AtomComponentProperties.light('Intensity'), 800.0) + Report.result( + Tests.light_component_intensity_property_set, + light_component.get_component_property_value( + AtomComponentProperties.light('Intensity')) == 800.0) + + # 11. Enter game mode and take a screenshot then exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) + ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("SpotLight_3.ppm") + TestHelper.exit_game_mode(Tests.exit_game_mode) + TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + + # 12. Change the Light component Color property value. + color_value = azlmbr.math.Color(47.0 / 255.0, 75.0 / 255.0, 37.0 / 255.0, 255.0 / 255.0) + light_component.set_component_property_value(AtomComponentProperties.light('Color'), color_value) + Report.result( + Tests.light_component_color_property_set, + light_component.get_component_property_value(AtomComponentProperties.light('Color')) == color_value) + + # 13. Enter game mode and take a screenshot then exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) + ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("SpotLight_4.ppm") + TestHelper.exit_game_mode(Tests.exit_game_mode) + TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + + # 14. Change the Light component Enable shutters, Inner angle, and Outer angle property values. + enable_shutters = True + inner_angle = 60.0 + outer_angle = 75.0 + light_component.set_component_property_value(AtomComponentProperties.light('Enable shutters'), enable_shutters) + light_component.set_component_property_value(AtomComponentProperties.light('Inner angle'), inner_angle) + light_component.set_component_property_value(AtomComponentProperties.light('Outer angle'), outer_angle) + Report.result( + Tests.light_component_enable_shutters_property_set, + light_component.get_component_property_value( + AtomComponentProperties.light('Enable shutters')) == enable_shutters) + Report.result( + Tests.light_component_inner_angle_property_set, + light_component.get_component_property_value(AtomComponentProperties.light('Inner angle')) == inner_angle) + Report.result( + Tests.light_component_outer_angle_property_set, + light_component.get_component_property_value(AtomComponentProperties.light('Outer angle')) == outer_angle) + + # 15. Enter game mode and take a screenshot then exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) + ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("SpotLight_5.ppm") + TestHelper.exit_game_mode(Tests.exit_game_mode) + TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + + # 16. Change the Light component Enable shadow and Shadowmap size property values then move Spot Light entity. + light_component.set_component_property_value(AtomComponentProperties.light('Enable shadow'), True) + light_component.set_component_property_value(AtomComponentProperties.light('Shadowmap size'), 256.0) + spot_light_entity.set_world_rotation(azlmbr.math.Vector3(0.7, -2.0, 1.9)) + Report.result( + Tests.light_component_enable_shadow_property_set, + light_component.get_component_property_value(AtomComponentProperties.light('Enable shadow')) is True) + Report.result( + Tests.light_component_shadowmap_size_property_set, + light_component.get_component_property_value(AtomComponentProperties.light('Shadowmap size')) == 256.0) + + # 17. Enter game mode and take a screenshot then exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) + ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("SpotLight_6.ppm") + TestHelper.exit_game_mode(Tests.exit_game_mode) + TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + + # 18. Look for errors. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") if __name__ == "__main__": diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py deleted file mode 100644 index 1641b529ae..0000000000 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py +++ /dev/null @@ -1,200 +0,0 @@ -""" -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 -""" - -import os - -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -from Atom.atom_utils.screenshot_utils import ScreenshotHelper - -SCREEN_WIDTH = 1280 -SCREEN_HEIGHT = 720 -DEGREE_RADIAN_FACTOR = 0.0174533 - -helper = EditorTestHelper(log_prefix="Test_Atom_BasicLevelSetup") - - -def run(): - """ - 1. View -> Layouts -> Restore Default Layout, sets the viewport to ratio 16:9 @ 1280 x 720 - 2. Runs console command r_DisplayInfo = 0 - 3. Deletes all entities currently present in the level. - 4. Creates a "default_level" entity to hold all other entities, setting the translate values to x:0, y:0, z:0 - 5. Adds a Grid component to the "default_level" & updates its Grid Spacing to 1.0m - 6. Adds a "global_skylight" entity to "default_level", attaching an HDRi Skybox w/ a Cubemap Texture. - 7. Adds a Global Skylight (IBL) component w/ diffuse image and specular image to "global_skylight" entity. - 8. Adds a "ground_plane" entity to "default_level", attaching a Mesh component & Material component. - 9. Adds a "directional_light" entity to "default_level" & adds a Directional Light component. - 10. Adds a "sphere" entity to "default_level" & adds a Mesh component with a Material component to it. - 11. Adds a "camera" entity to "default_level" & adds a Camera component with 80 degree FOV and Transform values: - Translate - x:5.5m, y:-12.0m, z:9.0m - Rotate - x:-27.0, y:-12.0, z:25.0 - 12. Finally enters game mode, takes a screenshot, & exits game mode. - :return: None - """ - import azlmbr.asset as asset - import azlmbr.bus as bus - import azlmbr.camera as camera - import azlmbr.entity as entity - import azlmbr.legacy.general as general - import azlmbr.math as math - import azlmbr.paths - import azlmbr.editor as editor - - def initial_viewport_setup(screen_width, screen_height): - general.set_viewport_size(screen_width, screen_height) - general.update_viewport() - helper.wait_for_condition( - function=lambda: helper.isclose(a=general.get_viewport_size().x, b=SCREEN_WIDTH, rel_tol=0.1) - and helper.isclose(a=general.get_viewport_size().y, b=SCREEN_HEIGHT, rel_tol=0.1), - timeout_in_seconds=4.0 - ) - result = helper.isclose(a=general.get_viewport_size().x, b=SCREEN_WIDTH, rel_tol=0.1) and helper.isclose( - a=general.get_viewport_size().y, b=SCREEN_HEIGHT, rel_tol=0.1) - general.log(general.get_viewport_size().x) - general.log(general.get_viewport_size().y) - general.log(general.get_viewport_size().z) - general.log(f"Viewport is set to the expected size: {result}") - general.run_console("r_DisplayInfo = 0") - - def after_level_load(): - """Function to call after creating/opening a level to ensure it loads.""" - # Give everything a second to initialize. - general.idle_enable(True) - general.idle_wait(1.0) - general.update_viewport() - general.idle_wait(0.5) # half a second is more than enough for updating the viewport. - - # Close out problematic windows, FPS meters, and anti-aliasing. - if general.is_helpers_shown(): # Turn off the helper gizmos if visible - general.toggle_helpers() - general.idle_wait(1.0) - if general.is_pane_visible("Error Report"): # Close Error Report windows that block focus. - general.close_pane("Error Report") - if general.is_pane_visible("Error Log"): # Close Error Log windows that block focus. - general.close_pane("Error Log") - general.idle_wait(1.0) - general.run_console("r_displayInfo=0") - general.idle_wait(1.0) - - # Wait for Editor idle loop before executing Python hydra scripts. - general.idle_enable(True) - - # Basic setup for opened level. - helper.open_level(level_name="Base") - after_level_load() - initial_viewport_setup(SCREEN_WIDTH, SCREEN_HEIGHT) - - # Create default_level entity - search_filter = azlmbr.entity.SearchFilter() - all_entities = entity.SearchBus(azlmbr.bus.Broadcast, "SearchEntities", search_filter) - editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", all_entities) - - default_level = hydra.Entity("default_level") - position = math.Vector3(0.0, 0.0, 0.0) - default_level.create_entity(position, ["Grid"]) - default_level.get_set_test(0, "Controller|Configuration|Secondary Grid Spacing", 1.0) - - # Create global_skylight entity and set the properties - global_skylight = hydra.Entity("global_skylight") - global_skylight.create_entity( - entity_position=math.Vector3(0.0, 0.0, 0.0), - components=["HDRi Skybox", "Global Skylight (IBL)"], - parent_id=default_level.id - ) - global_skylight_image_asset_path = os.path.join("LightingPresets", "default_iblskyboxcm.exr.streamingimage") - global_skylight_image_asset = asset.AssetCatalogRequestBus( - bus.Broadcast, "GetAssetIdByPath", global_skylight_image_asset_path, math.Uuid(), False) - global_skylight.get_set_test(0, "Controller|Configuration|Cubemap Texture", global_skylight_image_asset) - hydra.get_set_test(global_skylight, 1, "Controller|Configuration|Diffuse Image", global_skylight_image_asset) - hydra.get_set_test(global_skylight, 1, "Controller|Configuration|Specular Image", global_skylight_image_asset) - - # Create ground_plane entity and set the properties - ground_plane = hydra.Entity("ground_plane") - ground_plane.create_entity( - entity_position=math.Vector3(0.0, 0.0, 0.0), - components=["Material"], - parent_id=default_level.id - ) - azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalUniformScale", ground_plane.id, 32.0) - - # Work around to add the correct Atom Mesh component and asset. - mesh_type_id = azlmbr.globals.property.EditorMeshComponentTypeId - ground_plane.components.append( - editor.EditorComponentAPIBus( - bus.Broadcast, "AddComponentsOfType", ground_plane.id, [mesh_type_id] - ).GetValue()[0] - ) - ground_plane_mesh_asset_path = os.path.join("TestData", "Objects", "plane.azmodel") - ground_plane_mesh_asset = asset.AssetCatalogRequestBus( - bus.Broadcast, "GetAssetIdByPath", ground_plane_mesh_asset_path, math.Uuid(), False) - hydra.get_set_test(ground_plane, 1, "Controller|Configuration|Mesh Asset", ground_plane_mesh_asset) - - # Add Atom Material component and asset. - ground_plane_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_chrome.azmaterial") - ground_plane_material_asset = asset.AssetCatalogRequestBus( - bus.Broadcast, "GetAssetIdByPath", ground_plane_material_asset_path, math.Uuid(), False) - ground_plane.get_set_test(0, "Default Material|Material Asset", ground_plane_material_asset) - - # Create directional_light entity and set the properties - directional_light = hydra.Entity("directional_light") - directional_light.create_entity( - entity_position=math.Vector3(0.0, 0.0, 10.0), - components=["Directional Light"], - parent_id=default_level.id - ) - rotation = math.Vector3(DEGREE_RADIAN_FACTOR * -90.0, 0.0, 0.0) - azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", directional_light.id, rotation) - - # Create sphere entity and set the properties - sphere = hydra.Entity("sphere") - sphere.create_entity( - entity_position=math.Vector3(0.0, 0.0, 1.0), - components=["Material"], - parent_id=default_level.id - ) - - # Work around to add the correct Atom Mesh component and asset. - sphere.components.append( - editor.EditorComponentAPIBus( - bus.Broadcast, "AddComponentsOfType", sphere.id, [mesh_type_id] - ).GetValue()[0] - ) - sphere_mesh_asset_path = os.path.join("Models", "sphere.azmodel") - sphere_mesh_asset = asset.AssetCatalogRequestBus( - bus.Broadcast, "GetAssetIdByPath", sphere_mesh_asset_path, math.Uuid(), False) - hydra.get_set_test(sphere, 1, "Controller|Configuration|Mesh Asset", sphere_mesh_asset) - - # Add Atom Material component and asset. - sphere_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_brass_polished.azmaterial") - sphere_material_asset = asset.AssetCatalogRequestBus( - bus.Broadcast, "GetAssetIdByPath", sphere_material_asset_path, math.Uuid(), False) - sphere.get_set_test(0, "Default Material|Material Asset", sphere_material_asset) - - # Create camera component and set the properties - camera_entity = hydra.Entity("camera") - position = math.Vector3(5.5, -12.0, 9.0) - camera_entity.create_entity(components=["Camera"], entity_position=position, parent_id=default_level.id) - rotation = math.Vector3( - DEGREE_RADIAN_FACTOR * -27.0, DEGREE_RADIAN_FACTOR * -12.0, DEGREE_RADIAN_FACTOR * 25.0 - ) - azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", camera_entity.id, rotation) - camera_entity.get_set_test(0, "Controller|Configuration|Field of view", 60.0) - camera.EditorCameraViewRequestBus(azlmbr.bus.Event, "ToggleCameraAsActiveView", camera_entity.id) - - # Enter game mode, take screenshot, & exit game mode. - general.idle_wait(0.5) - general.enter_game_mode() - general.idle_wait(1.0) - helper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=2.0) - ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking(f"{'AtomBasicLevelSetup'}.ppm") - general.exit_game_mode() - helper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=2.0) - - -if __name__ == "__main__": - run() diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py deleted file mode 100644 index f69ceb2120..0000000000 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py +++ /dev/null @@ -1,261 +0,0 @@ -""" -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 -""" -import os -import sys - -import azlmbr.asset as asset -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.math as math -import azlmbr.paths -import azlmbr.legacy.general as general - -sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests")) - -import editor_python_test_tools.hydra_editor_utils as hydra -from Atom.atom_utils import atom_component_helper, atom_constants, screenshot_utils -from editor_python_test_tools.editor_test_helper import EditorTestHelper - -helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper") - -LEVEL_NAME = "Base" -LIGHT_COMPONENT = "Light" -LIGHT_TYPE_PROPERTY = 'Controller|Configuration|Light type' -DEGREE_RADIAN_FACTOR = 0.0174533 - - -def run(): - """ - Sets up the tests by making sure the required level is created & setup correctly. - It then executes 2 test cases - see each associated test function's docstring for more info. - - Finally prints the string "Light component tests completed" after completion - - Tests will fail immediately if any of these log lines are found: - 1. Trace::Assert - 2. Trace::Error - 3. Traceback (most recent call last): - - :return: None - """ - atom_component_helper.create_basic_atom_level(level_name=LEVEL_NAME) - - # Run tests. - area_light_test() - spot_light_test() - general.log("Light component tests completed.") - - -def area_light_test(): - """ - Basic test for the "Light" component attached to an "area_light" entity. - - Test Case - Light Component: Capsule, Spot (disk), and Point (sphere): - 1. Creates "area_light" entity w/ a Light component that has a Capsule Light type w/ the color set to 255, 0, 0 - 2. Enters game mode to take a screenshot for comparison, then exits game mode. - 3. Sets the Light component Intensity Mode to Lumens (default). - 4. Ensures the Light component Mode is Automatic (default). - 5. Sets the Intensity value of the Light component to 0.0 - 6. Enters game mode again, takes another screenshot for comparison, then exits game mode. - 7. Updates the Intensity value of the Light component to 1000.0 - 8. Enters game mode again, takes another screenshot for comparison, then exits game mode. - 9. Swaps the Capsule light type option to Spot (disk) light type on the Light component - 10. Updates "area_light" entity Transform rotate value to x: 90.0, y:0.0, z:0.0 - 11. Enters game mode again, takes another screenshot for comparison, then exits game mode. - 12. Swaps the Spot (disk) light type for the Point (sphere) light type in the Light component. - 13. Enters game mode again, takes another screenshot for comparison, then exits game mode. - 14. Deletes the Light component from the "area_light" entity and verifies its successful. - """ - # Create an "area_light" entity with "Light" component using Light type of "Capsule" - area_light_entity_name = "area_light" - area_light = hydra.Entity(area_light_entity_name) - area_light.create_entity(math.Vector3(-1.0, -2.0, 3.0), [LIGHT_COMPONENT]) - general.log( - f"{area_light_entity_name}_test: Component added to the entity: " - f"{hydra.has_components(area_light.id, [LIGHT_COMPONENT])}") - light_component_id_pair = hydra.attach_component_to_entity(area_light.id, LIGHT_COMPONENT) - - # Select the "Capsule" light type option. - azlmbr.editor.EditorComponentAPIBus( - azlmbr.bus.Broadcast, - 'SetComponentProperty', - light_component_id_pair, - LIGHT_TYPE_PROPERTY, - atom_constants.LIGHT_TYPES['capsule'] - ) - - # Update color and take screenshot in game mode - color = math.Color(255.0, 0.0, 0.0, 0.0) - area_light.get_set_test(0, "Controller|Configuration|Color", color) - general.idle_wait(1.0) - screenshot_utils.take_screenshot_game_mode("AreaLight_1", area_light_entity_name) - - # Update intensity value to 0.0 and take screenshot in game mode - area_light.get_set_test(0, "Controller|Configuration|Attenuation Radius|Mode", 1) - area_light.get_set_test(0, "Controller|Configuration|Intensity", 0.0) - general.idle_wait(1.0) - screenshot_utils.take_screenshot_game_mode("AreaLight_2", area_light_entity_name) - - # Update intensity value to 1000.0 and take screenshot in game mode - area_light.get_set_test(0, "Controller|Configuration|Intensity", 1000.0) - general.idle_wait(1.0) - screenshot_utils.take_screenshot_game_mode("AreaLight_3", area_light_entity_name) - - # Swap the "Capsule" light type option to "Spot (disk)" light type - azlmbr.editor.EditorComponentAPIBus( - azlmbr.bus.Broadcast, - 'SetComponentProperty', - light_component_id_pair, - LIGHT_TYPE_PROPERTY, - atom_constants.LIGHT_TYPES['spot_disk'] - ) - area_light_rotation = math.Vector3(DEGREE_RADIAN_FACTOR * 90.0, 0.0, 0.0) - azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", area_light.id, area_light_rotation) - general.idle_wait(1.0) - screenshot_utils.take_screenshot_game_mode("AreaLight_4", area_light_entity_name) - - # Swap the "Spot (disk)" light type to the "Point (sphere)" light type and take screenshot. - azlmbr.editor.EditorComponentAPIBus( - azlmbr.bus.Broadcast, - 'SetComponentProperty', - light_component_id_pair, - LIGHT_TYPE_PROPERTY, - atom_constants.LIGHT_TYPES['sphere'] - ) - general.idle_wait(1.0) - screenshot_utils.take_screenshot_game_mode("AreaLight_5", area_light_entity_name) - - editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntityById", area_light.id) - - -def spot_light_test(): - """ - Basic test for the Light component attached to a "spot_light" entity. - - Test Case - Light Component: Spot (disk) with shadows & colors: - 1. Creates "spot_light" entity w/ a Light component attached to it. - 2. Selects the "directional_light" entity already present in the level and disables it. - 3. Selects the "global_skylight" entity already present in the level and disables the HDRi Skybox component, - as well as the Global Skylight (IBL) component. - 4. Enters game mode to take a screenshot for comparison, then exits game mode. - 5. Selects the "ground_plane" entity and changes updates the material to a new material. - 6. Enters game mode to take a screenshot for comparison, then exits game mode. - 7. Selects the "spot_light" entity and increases the Light component Intensity to 800 lm - 8. Enters game mode to take a screenshot for comparison, then exits game mode. - 9. Selects the "spot_light" entity and sets the Light component Color to 47, 75, 37 - 10. Enters game mode to take a screenshot for comparison, then exits game mode. - 11. Selects the "spot_light" entity and modifies the Shutter controls to the following values: - - Enable shutters: True - - Inner Angle: 60.0 - - Outer Angle: 75.0 - 12. Enters game mode to take a screenshot for comparison, then exits game mode. - 13. Selects the "spot_light" entity and modifies the Shadow controls to the following values: - - Enable Shadow: True - - ShadowmapSize: 256 - 14. Modifies the world translate position of the "spot_light" entity to 0.7, -2.0, 1.9 (for casting shadows better) - 15. Enters game mode to take a screenshot for comparison, then exits game mode. - """ - # Disable "Directional Light" component for the "directional_light" entity - # "directional_light" entity is created by the create_basic_atom_level() function by default. - directional_light_entity_id = hydra.find_entity_by_name("directional_light") - directional_light = hydra.Entity(name='directional_light', id=directional_light_entity_id) - directional_light_component_type = azlmbr.editor.EditorComponentAPIBus( - azlmbr.bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Directional Light"], 0)[0] - directional_light_component = azlmbr.editor.EditorComponentAPIBus( - azlmbr.bus.Broadcast, 'GetComponentOfType', directional_light.id, directional_light_component_type - ).GetValue() - editor.EditorComponentAPIBus(bus.Broadcast, "DisableComponents", [directional_light_component]) - general.idle_wait(0.5) - - # Disable "Global Skylight (IBL)" and "HDRi Skybox" components for the "global_skylight" entity - global_skylight_entity_id = hydra.find_entity_by_name("global_skylight") - global_skylight = hydra.Entity(name='global_skylight', id=global_skylight_entity_id) - global_skylight_component_type = azlmbr.editor.EditorComponentAPIBus( - azlmbr.bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Global Skylight (IBL)"], 0)[0] - global_skylight_component = azlmbr.editor.EditorComponentAPIBus( - azlmbr.bus.Broadcast, 'GetComponentOfType', global_skylight.id, global_skylight_component_type - ).GetValue() - editor.EditorComponentAPIBus(bus.Broadcast, "DisableComponents", [global_skylight_component]) - hdri_skybox_component_type = azlmbr.editor.EditorComponentAPIBus( - azlmbr.bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["HDRi Skybox"], 0)[0] - hdri_skybox_component = azlmbr.editor.EditorComponentAPIBus( - azlmbr.bus.Broadcast, 'GetComponentOfType', global_skylight.id, hdri_skybox_component_type - ).GetValue() - editor.EditorComponentAPIBus(bus.Broadcast, "DisableComponents", [hdri_skybox_component]) - general.idle_wait(0.5) - - # Create a "spot_light" entity with "Light" component using Light Type of "Spot (disk)" - spot_light_entity_name = "spot_light" - spot_light = hydra.Entity(spot_light_entity_name) - spot_light.create_entity(math.Vector3(0.7, -2.0, 1.0), [LIGHT_COMPONENT]) - general.log( - f"{spot_light_entity_name}_test: Component added to the entity: " - f"{hydra.has_components(spot_light.id, [LIGHT_COMPONENT])}") - rotation = math.Vector3(DEGREE_RADIAN_FACTOR * 300.0, 0.0, 0.0) - azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", spot_light.id, rotation) - light_component_type = hydra.attach_component_to_entity(spot_light.id, LIGHT_COMPONENT) - editor.EditorComponentAPIBus( - azlmbr.bus.Broadcast, - 'SetComponentProperty', - light_component_type, - LIGHT_TYPE_PROPERTY, - atom_constants.LIGHT_TYPES['spot_disk'] - ) - - general.idle_wait(1.0) - screenshot_utils.take_screenshot_game_mode("SpotLight_1", spot_light_entity_name) - - # Change default material of ground plane entity and take screenshot - ground_plane_entity_id = hydra.find_entity_by_name("ground_plane") - ground_plane = hydra.Entity(name='ground_plane', id=ground_plane_entity_id) - ground_plane_asset_path = os.path.join("Materials", "Presets", "MacBeth", "22_neutral_5-0_0-70d.azmaterial") - ground_plane_asset_value = asset.AssetCatalogRequestBus( - bus.Broadcast, "GetAssetIdByPath", ground_plane_asset_path, math.Uuid(), False) - material_property_path = "Default Material|Material Asset" - material_component_type = azlmbr.editor.EditorComponentAPIBus( - azlmbr.bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Material"], 0)[0] - material_component = azlmbr.editor.EditorComponentAPIBus( - azlmbr.bus.Broadcast, 'GetComponentOfType', ground_plane.id, material_component_type).GetValue() - editor.EditorComponentAPIBus( - azlmbr.bus.Broadcast, - 'SetComponentProperty', - material_component, - material_property_path, - ground_plane_asset_value - ) - general.idle_wait(1.0) - screenshot_utils.take_screenshot_game_mode("SpotLight_2", spot_light_entity_name) - - # Increase intensity value of the Spot light and take screenshot in game mode - spot_light.get_set_test(0, "Controller|Configuration|Intensity", 800.0) - general.idle_wait(1.0) - screenshot_utils.take_screenshot_game_mode("SpotLight_3", spot_light_entity_name) - - # Update the Spot light color and take screenshot in game mode - color_value = math.Color(47.0 / 255.0, 75.0 / 255.0, 37.0 / 255.0, 255.0 / 255.0) - spot_light.get_set_test(0, "Controller|Configuration|Color", color_value) - general.idle_wait(1.0) - screenshot_utils.take_screenshot_game_mode("SpotLight_4", spot_light_entity_name) - - # Update the Shutter controls of the Light component and take screenshot - spot_light.get_set_test(0, "Controller|Configuration|Shutters|Enable shutters", True) - spot_light.get_set_test(0, "Controller|Configuration|Shutters|Inner angle", 60.0) - spot_light.get_set_test(0, "Controller|Configuration|Shutters|Outer angle", 75.0) - general.idle_wait(1.0) - screenshot_utils.take_screenshot_game_mode("SpotLight_5", spot_light_entity_name) - - # Update the Shadow controls, move the spot_light entity world translate position and take screenshot - spot_light.get_set_test(0, "Controller|Configuration|Shadows|Enable shadow", True) - spot_light.get_set_test(0, "Controller|Configuration|Shadows|Shadowmap size", 256.0) - azlmbr.components.TransformBus( - azlmbr.bus.Event, "SetWorldTranslation", spot_light.id, math.Vector3(0.7, -2.0, 1.9)) - general.idle_wait(1.0) - screenshot_utils.take_screenshot_game_mode("SpotLight_6", spot_light_entity_name) - - -if __name__ == "__main__": - run() diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py index 59e454479c..5b0ab0067c 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py @@ -25,7 +25,7 @@ class EditorComponent: """ EditorComponent class used to set and get the component property value using path EditorComponent object is returned from either of - EditorEntity.add_component() or Entity.add_components() or EditorEntity.get_component_objects() + EditorEntity.add_component() or Entity.add_components() or EditorEntity.get_components_of_type() which also assigns self.id and self.type_id to the EditorComponent object. """ @@ -94,6 +94,13 @@ class EditorComponent: """ return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", self.id) + def disable_component(self): + """ + Used to disable the component using its id value. + :return: None + """ + editor.EditorComponentAPIBus(bus.Broadcast, "DisableComponents", [self.id]) + @staticmethod def get_type_ids(component_names: list) -> list: """ @@ -107,7 +114,6 @@ class EditorComponent: return type_ids - def convert_to_azvector3(xyz) -> azlmbr.math.Vector3: """ Converts a vector3-like element into a azlmbr.math.Vector3 @@ -120,6 +126,7 @@ def convert_to_azvector3(xyz) -> azlmbr.math.Vector3: else: raise ValueError("vector must be a 3 element list/tuple or azlmbr.math.Vector3") + class EditorEntity: """ Entity class is used to create and interact with Editor Entities. @@ -136,10 +143,11 @@ class EditorEntity: # Creation functions @classmethod - def find_editor_entity(cls, entity_name: str, must_be_unique : bool = False) -> EditorEntity: + def find_editor_entity(cls, entity_name: str, must_be_unique: bool = False) -> EditorEntity: """ Given Entity name, outputs entity object :param entity_name: Name of entity to find + :param must_be_unique: bool that asserts the entity_name specified is unique when set to True :return: EditorEntity class object """ entities = cls.find_editor_entities([entity_name]) @@ -147,14 +155,14 @@ class EditorEntity: if must_be_unique: assert len(entities) == 1, f"Failure: Multiple entities with name: '{entity_name}' when expected only one" - entity = cls(entities[0]) + entity = entities[0] return entity @classmethod - def find_editor_entities(cls, entity_names: List[str]) -> EditorEntity: + def find_editor_entities(cls, entity_names: List[str]) -> List[EditorEntity]: """ Given Entities names, returns a list of EditorEntity - :param entity_name: Name of entity to find + :param entity_names: List of entity names to find :return: List[EditorEntity] class object """ searchFilter = azlmbr.entity.SearchFilter() @@ -438,7 +446,7 @@ class EditorEntity: def set_local_rotation(self, new_rotation) -> None: """ Sets the set the local rotation(relative to the parent) of the current entity. - :param vector3_rotation: The math.Vector3 value to use for rotation on the entity (uses radians). + :param new_rotation: The math.Vector3 value to use for rotation on the entity (uses radians). :return: None """ new_rotation = convert_to_azvector3(new_rotation) @@ -454,7 +462,7 @@ class EditorEntity: def set_local_translation(self, new_translation) -> None: """ Sets the local translation(relative to the parent) of the current entity. - :param vector3_translation: The math.Vector3 value to use for translation on the entity. + :param new_translation: The math.Vector3 value to use for translation on the entity. :return: None """ new_translation = convert_to_azvector3(new_translation) From ca771f3adc3ef4b71cf76c84c66bc93173cfbf89 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 1 Dec 2021 22:18:32 -0800 Subject: [PATCH 062/128] version upgrader in a presumed working story Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Editor/Assets/ScriptCanvasFileHandling.cpp | 5 ++--- .../Code/Editor/Components/EditorGraph.cpp | 4 ++-- .../Code/Editor/Components/GraphUpgrade.cpp | 6 ++++-- .../ScriptCanvas/Components/EditorGraph.h | 2 +- .../Windows/Tools/UpgradeTool/FileSaver.cpp | 13 ++++++++++++- .../Windows/Tools/UpgradeTool/Modifier.cpp | 18 ++++++++++-------- .../Code/Include/ScriptCanvas/Core/Core.h | 6 +++--- .../ScriptCanvas/Grammar/ParsingMetaData.cpp | 8 ++++---- 8 files changed, 38 insertions(+), 24 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp index 706c46fa75..be909e5043 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp @@ -209,7 +209,6 @@ namespace ScriptCanvasEditor AZ::Outcome LoadFromFile(AZStd::string_view path) { namespace JSRU = AZ::JsonSerializationUtils; - using namespace ScriptCanvas; auto fileStringOutcome = AZ::Utils::ReadFile(path); if (!fileStringOutcome) @@ -218,7 +217,7 @@ namespace ScriptCanvasEditor } const auto& asString = fileStringOutcome.GetValue(); - DataPtr scriptCanvasData = AZStd::make_shared(); + ScriptCanvas::DataPtr scriptCanvasData = aznew ScriptCanvas::ScriptCanvasData(); if (!scriptCanvasData) { return AZ::Failure(AZStd::string("failed to allocate ScriptCanvas::ScriptCanvasData after loading source file")); @@ -314,7 +313,7 @@ namespace ScriptCanvasEditor listener->OnSerialize(); } - auto saveOutcome = JSRU::SaveObjectToStream(graphData, stream, nullptr, &settings); + auto saveOutcome = JSRU::SaveObjectToStream(graphData.get(), stream, nullptr, &settings); if (!saveOutcome.IsSuccess()) { return AZ::Failure(AZStd::string::format("JSON serialization failed to save source: %s", saveOutcome.GetError().c_str())); diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp index 8d02e61b7d..f032bfe692 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp @@ -1069,7 +1069,7 @@ namespace ScriptCanvasEditor m_owner = &owner; } - ScriptCanvas::ScriptCanvasData* Graph::GetOwnership() const + ScriptCanvas::DataPtr Graph::GetOwnership() const { return const_cast(this)->m_owner; } @@ -1354,7 +1354,7 @@ namespace ScriptCanvasEditor void Graph::SignalDirty() { - SourceHandle handle(m_owner->shared_from_this(), {}, {}); + SourceHandle handle(m_owner, {}, {}); GeneralRequestBus::Broadcast(&GeneralRequests::SignalSceneDirty, handle); } diff --git a/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp b/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp index e64a47a753..fec813b0c1 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp @@ -438,10 +438,11 @@ namespace ScriptCanvasEditor if (nodeConfig.IsValid()) { ScriptCanvas::NodeUpdateSlotReport nodeUpdateSlotReport; + auto nodeEntity = node->GetEntityId(); auto nodeOutcome = graph->ReplaceNodeByConfig(node, nodeConfig, nodeUpdateSlotReport); if (nodeOutcome.IsSuccess()) { - ScriptCanvas::MergeUpdateSlotReport(node->GetEntityId(), sm->m_updateReport, nodeUpdateSlotReport); + ScriptCanvas::MergeUpdateSlotReport(nodeEntity, sm->m_updateReport, nodeUpdateSlotReport); sm->m_allNodes.erase(node); sm->m_outOfDateNodes.erase(node); @@ -687,7 +688,8 @@ namespace ScriptCanvasEditor void EditorGraphUpgradeMachine::OnComplete(IState::ExitStatus exitStatus) { UpgradeNotificationsBus::Broadcast(&UpgradeNotifications::OnGraphUpgradeComplete, m_asset, exitStatus == IState::ExitStatus::Skipped); - m_asset = {}; + // releasing the asset at this stage of the system tick causes a memory crash + // m_asset = {}; } ////////////////////////////////////////////////////////////////////// diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h index 319a835ba5..be8f274cd6 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h @@ -302,7 +302,7 @@ namespace ScriptCanvasEditor const GraphStatisticsHelper& GetNodeUsageStatistics() const; void MarkOwnership(ScriptCanvas::ScriptCanvasData& owner); - ScriptCanvas::ScriptCanvasData* GetOwnership() const; + ScriptCanvas::DataPtr GetOwnership() const; // Finds and returns all nodes within the graph that are of the specified type template diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp index c23a3d915b..47e43b19d3 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp @@ -76,7 +76,7 @@ namespace ScriptCanvasEditor AZ::SystemTickBus::QueueFunction([this, tmpFileName]() { FileSaveResult result; - result.fileSaveError = "Failed to move updated file from temporary location to tmpFileName destination"; + result.fileSaveError = "Failed to move updated file from temporary location to original destination."; result.tempFileRemovalError = RemoveTempFile(tmpFileName); m_onComplete(result); }); @@ -97,7 +97,16 @@ namespace ScriptCanvasEditor } else { + // #sc_editor_asset - skip save, narrow down the memory corruption + AZ::SystemTickBus::QueueFunction([this, tmpFileName]() + { + FileSaveResult result; + result.tempFileRemovalError = RemoveTempFile(tmpFileName); + m_onComplete(result); + }); + // the actual move attempt + /* auto moveResult = AZ::IO::SmartMove(tmpFileName.c_str(), target.c_str()); if (moveResult.GetResultCode() == AZ::IO::ResultCode::Success) { @@ -105,6 +114,7 @@ namespace ScriptCanvasEditor AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); // Bump the slice asset up in the asset processor's queue. AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str()); + AZ::SystemTickBus::QueueFunction([this, tmpFileName]() { FileSaveResult result; @@ -124,6 +134,7 @@ namespace ScriptCanvasEditor }); streamer->QueueRequest(flushRequest); } + **/ } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp index 242aea355e..3c8605e915 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp @@ -138,15 +138,17 @@ namespace ScriptCanvasEditor void Modifier::ModificationComplete(const ModificationResult& result) { - m_result = result; - - if (result.errorMessage.empty()) + if (!result.errorMessage.empty()) { - SaveModifiedGraph(result); + ReportModificationError(result.errorMessage); + } + else if (m_result.asset.Describe() != result.asset.Describe()) + { + ReportModificationError("Received modifiction complete notification for different result"); } else { - ReportModificationError(result.errorMessage); + SaveModifiedGraph(result); } } @@ -187,15 +189,15 @@ namespace ScriptCanvasEditor void Modifier::ReportModificationError(AZStd::string_view report) { - m_result.asset = {}; m_result.errorMessage = report; - m_results.m_failures.push_back(m_result); + m_results.m_failures.push_back({ m_result.asset.Describe(), report }); ModifyNextAsset(); } void Modifier::ReportModificationSuccess() { - m_results.m_successes.push_back(m_result.asset); + m_result.asset = m_result.asset.Describe(); + m_results.m_successes.push_back({ m_result.asset.Describe(), {} }); ModifyNextAsset(); } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h index 297ee70500..215041e1fd 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h @@ -306,8 +306,8 @@ namespace ScriptCanvas { class ScriptCanvasData; - using DataPtr = AZStd::shared_ptr; - using DataPtrConst = AZStd::shared_ptr; + using DataPtr = AZStd::intrusive_ptr; + using DataPtrConst = AZStd::intrusive_ptr; } namespace ScriptCanvasEditor @@ -372,7 +372,7 @@ namespace ScriptCanvasEditor namespace ScriptCanvas { class ScriptCanvasData - : public AZStd::enable_shared_from_this + : public AZStd::intrusive_refcount { public: diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingMetaData.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingMetaData.cpp index 476b21d0d6..681bd3b0e4 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingMetaData.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingMetaData.cpp @@ -152,19 +152,19 @@ namespace ScriptCanvas { if (azrtti_istypeof(execution->GetId().m_node)) { - return MetaDataPtr(aznew FormatStringMetaData()); + return AZStd::make_shared(); } else if (azrtti_istypeof(execution->GetId().m_node)) { - return MetaDataPtr(aznew PrintMetaData()); + return AZStd::make_shared(); } else if (azrtti_istypeof(execution->GetId().m_node)) { - return MetaDataPtr(aznew MathExpressionMetaData()); + return AZStd::make_shared(); } else if (execution->GetSymbol() == Symbol::FunctionCall) { - return MetaDataPtr(aznew FunctionCallDefaultMetaData()); + return AZStd::make_shared(); } } From 6fb284ff0ac00acc409dffe0477f3ce4e1e161ec Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 1 Dec 2021 23:04:07 -0800 Subject: [PATCH 063/128] restore file save Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Editor/Components/EditorGraph.cpp | 2 +- .../Windows/Tools/UpgradeTool/FileSaver.cpp | 22 +++++++------------ 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp index f032bfe692..8741505030 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp @@ -1051,7 +1051,7 @@ namespace ScriptCanvasEditor auto graph = entity->CreateComponent(); entity->CreateComponent(graph->GetScriptCanvasId()); - if (ScriptCanvas::DataPtr data = AZStd::make_shared()) + if (ScriptCanvas::DataPtr data = aznew ScriptCanvas::ScriptCanvasData()) { data->m_scriptCanvasEntity.reset(entity); graph->MarkOwnership(*data); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp index 47e43b19d3..57c0822b05 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp @@ -97,23 +97,15 @@ namespace ScriptCanvasEditor } else { - // #sc_editor_asset - skip save, narrow down the memory corruption - AZ::SystemTickBus::QueueFunction([this, tmpFileName]() - { - FileSaveResult result; - result.tempFileRemovalError = RemoveTempFile(tmpFileName); - m_onComplete(result); - }); - // the actual move attempt - /* auto moveResult = AZ::IO::SmartMove(tmpFileName.c_str(), target.c_str()); if (moveResult.GetResultCode() == AZ::IO::ResultCode::Success) { auto streamer = AZ::Interface::Get(); AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); // Bump the slice asset up in the asset processor's queue. - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str()); + AzFramework::AssetSystemRequestBus::Broadcast + (&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str()); AZ::SystemTickBus::QueueFunction([this, tmpFileName]() { @@ -124,17 +116,19 @@ namespace ScriptCanvasEditor } else { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to tmpFileName destination failed: %s, trying again", target.c_str()); + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false + , "moving converted file to tmpFileName destination failed: %s, trying again", target.c_str()); auto streamer = AZ::Interface::Get(); AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); - streamer->SetRequestCompleteCallback(flushRequest, [this, tmpFileName, target, remainingAttempts]([[maybe_unused]] AZ::IO::FileRequestHandle request) + streamer->SetRequestCompleteCallback(flushRequest + , [this, tmpFileName, target, remainingAttempts]([[maybe_unused]] AZ::IO::FileRequestHandle request) { // Continue saving. - AZ::SystemTickBus::QueueFunction([this, tmpFileName, target, remainingAttempts]() { PerformMove(tmpFileName, target, remainingAttempts - 1); }); + AZ::SystemTickBus::QueueFunction( + [this, tmpFileName, target, remainingAttempts]() { PerformMove(tmpFileName, target, remainingAttempts - 1); }); }); streamer->QueueRequest(flushRequest); } - **/ } } From a9b1b02b929a173d451b239935e5b149de499b1b Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 1 Dec 2021 23:55:11 -0800 Subject: [PATCH 064/128] fix mismatched file name on modification Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Editor/View/Widgets/GraphTabBar.cpp | 13 +++++++++---- .../Code/Editor/View/Widgets/GraphTabBar.h | 1 - 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp index b00e2ea3de..53b2cecabc 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp @@ -158,8 +158,7 @@ namespace ScriptCanvasEditor AZStd::string tabName; AzFramework::StringFunc::Path::GetFileName(assetId.Path().c_str(), tabName); - metaData.m_name = tabName.c_str(); - + SetTabText(tabIndex, tabName.c_str(), fileState); setTabData(tabIndex, QVariant::fromValue(metaData)); return tabIndex; @@ -350,6 +349,12 @@ namespace ScriptCanvasEditor void GraphTabBar::SetTabText(int tabIndex, const QString& path, Tracker::ScriptCanvasFileState fileState) { + QString safePath = path; + if (path.endsWith("^") || path.endsWith("*")) + { + safePath.chop(1); + } + if (tabIndex >= 0 && tabIndex < count()) { const char* fileStateTag = ""; @@ -366,7 +371,7 @@ namespace ScriptCanvasEditor break; } - setTabText(tabIndex, QString("%1%2").arg(path).arg(fileStateTag)); + setTabText(tabIndex, QString("%1%2").arg(safePath).arg(fileStateTag)); } } @@ -392,7 +397,7 @@ namespace ScriptCanvasEditor int index = FindTab(assetId); tabData->m_fileState = fileState; SetTabData(*tabData, assetId); - SetTabText(index, tabData->m_name, fileState); + SetTabText(index, tabText(index), fileState); if (index == currentIndex()) { diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h index 40b785f016..e19ceaa4ec 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h @@ -37,7 +37,6 @@ namespace ScriptCanvasEditor QWidget* m_hostWidget = nullptr; CanvasWidget* m_canvasWidget = nullptr; Tracker::ScriptCanvasFileState m_fileState = Tracker::ScriptCanvasFileState::INVALID; - QString m_name; }; class GraphTabBar From 5da820a8c27b0b6bdad5caaca45b5e91955f033d Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Thu, 2 Dec 2021 00:25:50 -0800 Subject: [PATCH 065/128] clean up WIP Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Builder/ScriptCanvasBuilder.cpp | 33 +++--- Gems/ScriptCanvas/Code/Editor/Settings.cpp | 17 ++- .../Code/Editor/SystemComponent.cpp | 93 +++++++-------- .../LoggingPanel/LoggingWindowTreeItems.cpp | 106 +++++++++--------- .../PivotTree/PivotTreeWidget.cpp | 23 ++-- .../FunctionNodePaletteTreeItemTypes.cpp | 14 ++- .../ScriptCanvasStatisticsDialog.cpp | 6 +- .../Code/Editor/View/Windows/MainWindow.cpp | 13 +-- 8 files changed, 154 insertions(+), 151 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp index 31b63e8fad..60a3687d0d 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp @@ -27,23 +27,24 @@ namespace BuildVariableOverridesCpp }; bool VersionConverter - ( [[maybe_unused]] AZ::SerializeContext& serializeContext - , [[maybe_unused]] AZ::SerializeContext::DataElementNode& rootElement) + ( AZ::SerializeContext& serializeContext + , AZ::SerializeContext::DataElementNode& rootElement) { - // #sc_editor_asset -// ScriptCanvasBuilder::BuildVariableOverrides overrides; -// overrides.m_source = SourceHandle(nullptr, assetHolder.GetAssetId().m_guid, {}); -// -// for (auto& variable : editableData.GetVariables()) -// { -// overrides.m_overrides.push_back(variable.m_graphVariable); -// } -// -// if (!rootElement.AddElementWithData(serializeContext, "runtimeDataOverrides", overrides)) -// { -// AZ_Error("ScriptCanvas", false, "EditorScriptCanvasComponent conversion failed: failed to add 'runtimeDataOverrides'"); -// return false; -// } + // #sc_editor_asset + ScriptCanvasBuilder::BuildVariableOverrides overrides; + overrides.m_source = SourceHandle(nullptr, assetHolder.GetAssetId().m_guid, {}); + + for (auto& variable : editableData.GetVariables()) + { + overrides.m_overrides.push_back(variable.m_graphVariable); + } + + if (!rootElement.AddElementWithData(serializeContext, "runtimeDataOverrides", overrides)) + { + AZ_Error("ScriptCanvas", false, "EditorScriptCanvasComponent conversion failed: failed to add 'runtimeDataOverrides'"); + return false; + } + return true; } } diff --git a/Gems/ScriptCanvas/Code/Editor/Settings.cpp b/Gems/ScriptCanvas/Code/Editor/Settings.cpp index d072e465b8..295f499e8d 100644 --- a/Gems/ScriptCanvas/Code/Editor/Settings.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Settings.cpp @@ -110,15 +110,14 @@ namespace ScriptCanvasEditor if (subElement) { -// #sc_editor_asset -// if (subElement->GetData(assetIds)) -// { -// assetSaveData.reserve(assetIds.size()); -// for (const AZ::Data::AssetId& assetId : assetIds) -// { -// assetSaveData.emplace_back(assetId); -// } -// } + if (subElement->GetData(assetIds)) + { + assetSaveData.reserve(assetIds.size()); + for (const AZ::Data::AssetId& assetId : assetIds) + { + assetSaveData.emplace_back(SourceHandle( nullptr, assetId.m_guid, "" )); + } + } } rootDataElementNode.RemoveElementByName(AZ_CRC_CE("ActiveAssetIds")); diff --git a/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp b/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp index 88ef93a4c4..0be2d564ee 100644 --- a/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp @@ -212,7 +212,7 @@ namespace ScriptCanvasEditor if (!entitiesWithScriptCanvas.empty()) { QMenu* scriptCanvasMenu = nullptr; - // QAction* action = nullptr; + QAction* action = nullptr; // For entities with script canvas component, create a context menu to open any existing script canvases within each selected entity. for (const AZ::EntityId& entityId : entitiesWithScriptCanvas) @@ -245,32 +245,33 @@ namespace ScriptCanvasEditor AZStd::unordered_set< AZ::Data::AssetId > usedIds; - //#sc_editor_asset -// for (const auto& assetId : assetIds.values) -// { -// if (!assetId.IsValid() || usedIds.count(assetId) != 0) -// { -// continue; -// } -// -// entityMenu->setEnabled(true); -// -// usedIds.insert(assetId); -// -// AZStd::string rootPath; -// AZ::Data::AssetInfo assetInfo = AssetHelpers::GetAssetInfo(assetId, rootPath); -// -// AZStd::string displayName; -// AZ::StringFunc::Path::GetFileName(assetInfo.m_relativePath.c_str(), displayName); -// -// action = entityMenu->addAction(QString("%1").arg(QString(displayName.c_str()))); -// -// QObject::connect(action, &QAction::triggered, [assetId] -// { -// AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); -// GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAsset, assetId, -1); -// }); -// } + for (const auto& assetId : assetIds.values) + { + if (!assetId.IsValid() || usedIds.count(assetId) != 0) + { + continue; + } + + entityMenu->setEnabled(true); + + usedIds.insert(assetId); + + AZStd::string rootPath; + AZ::Data::AssetInfo assetInfo = AssetHelpers::GetAssetInfo(assetId, rootPath); + + AZStd::string displayName; + AZ::StringFunc::Path::GetFileName(assetInfo.m_relativePath.c_str(), displayName); + + action = entityMenu->addAction(QString("%1").arg(QString(displayName.c_str()))); + + QObject::connect(action, &QAction::triggered, [assetId] + { + AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); + GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAsset + , SourceHandle(nullptr, assetId.m_guid, "") + , Tracker::ScriptCanvasFileState::UNMODIFIED, -1); + }); + } } } } @@ -319,24 +320,26 @@ namespace ScriptCanvasEditor { isScriptCanvasAsset = true; } - // #sc_editor_asset -// if (isScriptCanvasAsset) -// { -// auto scriptCanvasEditorCallback = []([[maybe_unused]] const char* fullSourceFileNameInCall, const AZ::Uuid& sourceUUIDInCall) -// { -// AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); -// const SourceAssetBrowserEntry* fullDetails = SourceAssetBrowserEntry::GetSourceByUuid(sourceUUIDInCall); -// if (fullDetails) -// { -// AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); -// -// AzToolsFramework::EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::OpenViewPane, "Script Canvas"); -// GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, sourceUUIDInCall, -1); -// } -// }; -// -// openers.push_back({ "O3DE_ScriptCanvasEditor", "Open In Script Canvas Editor...", QIcon(), scriptCanvasEditorCallback }); -// } + + if (isScriptCanvasAsset) + { + auto scriptCanvasEditorCallback = []([[maybe_unused]] const char* fullSourceFileNameInCall, const AZ::Uuid& sourceUUIDInCall) + { + AZ::Outcome openOutcome = AZ::Failure(AZStd::string()); + const SourceAssetBrowserEntry* fullDetails = SourceAssetBrowserEntry::GetSourceByUuid(sourceUUIDInCall); + if (fullDetails) + { + AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas); + + AzToolsFramework::EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::OpenViewPane, "Script Canvas"); + GeneralRequestBus::BroadcastResult(openOutcome + , &GeneralRequests::OpenScriptCanvasAsset + , SourceHandle(nullptr, sourceUUIDInCall, ""), Tracker::ScriptCanvasFileState::UNMODIFIED, -1); + } + }; + + openers.push_back({ "O3DE_ScriptCanvasEditor", "Open In Script Canvas Editor...", QIcon(), scriptCanvasEditorCallback }); + } } void SystemComponent::OnUserSettingsActivated() diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp index 636ee832d4..6936a0c368 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/LoggingWindowTreeItems.cpp @@ -619,51 +619,54 @@ namespace ScriptCanvasEditor void ExecutionLogTreeItem::ScrapeGraphCanvasData() { - // #sc_editor_asset -// if (!m_graphCanvasGraphId.IsValid()) -// { -// GeneralRequestBus::BroadcastResult(m_graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, GetAssetId()); -// -// if (!EditorGraphNotificationBus::Handler::BusIsConnected()) -// { -// ScriptCanvas::ScriptCanvasId scriptCanvasId; -// GeneralRequestBus::BroadcastResult(scriptCanvasId, &GeneralRequests::FindScriptCanvasIdByAssetId, GetAssetId()); -// -// EditorGraphNotificationBus::Handler::BusConnect(scriptCanvasId); -// } -// } -// -// if (m_graphCanvasGraphId.IsValid()) -// { -// if (!m_graphCanvasNodeId.IsValid()) -// { -// AssetGraphSceneBus::BroadcastResult(m_scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, GetAssetId(), m_scriptCanvasAssetNodeId); -// SceneMemberMappingRequestBus::EventResult(m_graphCanvasNodeId, m_scriptCanvasNodeId, &SceneMemberMappingRequests::GetGraphCanvasEntityId); -// } -// -// if (m_graphCanvasNodeId.IsValid()) -// { -// const bool refreshDisplayData = false; -// ResolveWrapperNode(refreshDisplayData); -// -// AZStd::string displayName; -// GraphCanvas::NodeTitleRequestBus::EventResult(displayName, m_graphCanvasNodeId, &GraphCanvas::NodeTitleRequests::GetTitle); -// -// if (!displayName.empty()) -// { -// m_displayName = displayName.c_str(); -// } -// -// GraphCanvas::NodeTitleRequestBus::Event(m_graphCanvasNodeId, &GraphCanvas::NodeTitleRequests::ConfigureIconConfiguration, m_paletteConfiguration); -// -// OnStylesLoaded(); -// -// PopulateInputSlotData(); -// PopulateOutputSlotData(); -// -// SignalDataChanged(); -// } -// } + if (!m_graphCanvasGraphId.IsValid()) + { + GeneralRequestBus::BroadcastResult(m_graphCanvasGraphId + , &GeneralRequests::FindGraphCanvasGraphIdByAssetId, SourceHandle(nullptr, GetAssetId().m_guid, "")); + + if (!EditorGraphNotificationBus::Handler::BusIsConnected()) + { + ScriptCanvas::ScriptCanvasId scriptCanvasId; + GeneralRequestBus::BroadcastResult(scriptCanvasId + , &GeneralRequests::FindScriptCanvasIdByAssetId, SourceHandle(nullptr, GetAssetId().m_guid, "")); + + EditorGraphNotificationBus::Handler::BusConnect(scriptCanvasId); + } + } + + if (m_graphCanvasGraphId.IsValid()) + { + if (!m_graphCanvasNodeId.IsValid()) + { + AssetGraphSceneBus::BroadcastResult(m_scriptCanvasNodeId + , &AssetGraphScene::FindEditorNodeIdByAssetNodeId + , SourceHandle(nullptr, GetAssetId().m_guid, ""), m_scriptCanvasAssetNodeId); + SceneMemberMappingRequestBus::EventResult(m_graphCanvasNodeId, m_scriptCanvasNodeId, &SceneMemberMappingRequests::GetGraphCanvasEntityId); + } + + if (m_graphCanvasNodeId.IsValid()) + { + const bool refreshDisplayData = false; + ResolveWrapperNode(refreshDisplayData); + + AZStd::string displayName; + GraphCanvas::NodeTitleRequestBus::EventResult(displayName, m_graphCanvasNodeId, &GraphCanvas::NodeTitleRequests::GetTitle); + + if (!displayName.empty()) + { + m_displayName = displayName.c_str(); + } + + GraphCanvas::NodeTitleRequestBus::Event(m_graphCanvasNodeId, &GraphCanvas::NodeTitleRequests::ConfigureIconConfiguration, m_paletteConfiguration); + + OnStylesLoaded(); + + PopulateInputSlotData(); + PopulateOutputSlotData(); + + SignalDataChanged(); + } + } } void ExecutionLogTreeItem::PopulateInputSlotData() @@ -805,8 +808,8 @@ namespace ScriptCanvasEditor { if (!m_graphCanvasGraphId.IsValid()) { - // #sc_editor_asset - // GeneralRequestBus::BroadcastResult(m_graphCanvasGraphId, &GeneralRequests::FindGraphCanvasGraphIdByAssetId, m_graphIdentifier.m_assetId); + GeneralRequestBus::BroadcastResult(m_graphCanvasGraphId + , &GeneralRequests::FindGraphCanvasGraphIdByAssetId, SourceHandle(nullptr, m_graphIdentifier.m_assetId.m_guid, "")); } ScrapeInputName(); @@ -828,8 +831,7 @@ namespace ScriptCanvasEditor if (m_graphCanvasGraphId.IsValid() && m_assetInputEndpoint.IsValid()) { AZ::EntityId scriptCanvasNodeId; - // #sc_editor_asset - // AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, GetAssetId(), m_assetInputEndpoint.GetNodeId()); + AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, SourceHandle(nullptr, GetAssetId().m_guid, ""), m_assetInputEndpoint.GetNodeId()); GraphCanvas::NodeId graphCanvasNodeId; SceneMemberMappingRequestBus::EventResult(graphCanvasNodeId, scriptCanvasNodeId, &SceneMemberMappingRequests::GetGraphCanvasEntityId); @@ -852,9 +854,9 @@ namespace ScriptCanvasEditor if (m_graphCanvasGraphId.IsValid() && m_assetOutputEndpoint.IsValid()) { AZ::EntityId scriptCanvasNodeId; - // #sc_editor_asset - // AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId, GetAssetId(), m_assetOutputEndpoint.GetNodeId()); - + AssetGraphSceneBus::BroadcastResult(scriptCanvasNodeId, &AssetGraphScene::FindEditorNodeIdByAssetNodeId + , SourceHandle(nullptr, GetAssetId().m_guid, ""), m_assetOutputEndpoint.GetNodeId()); + GraphCanvas::NodeId graphCanvasNodeId; SceneMemberMappingRequestBus::EventResult(graphCanvasNodeId, scriptCanvasNodeId, &SceneMemberMappingRequests::GetGraphCanvasEntityId); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/PivotTree/PivotTreeWidget.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/PivotTree/PivotTreeWidget.cpp index d085ebbbcf..b1827d7099 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/PivotTree/PivotTreeWidget.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/LoggingPanel/PivotTree/PivotTreeWidget.cpp @@ -405,18 +405,17 @@ namespace ScriptCanvasEditor { sourceIndex = proxyModel->mapToSource(modelIndex); } - // #sc_editor_asset -// PivotTreeItem* pivotTreeItem = static_cast(sourceIndex.internalPointer()); -// -// if (pivotTreeItem) -// { -// PivotTreeGraphItem* graphItem = azrtti_cast(pivotTreeItem); -// -// if (graphItem) -// { -// GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId, graphItem->GetAssetId()); -// } -// } + + if (PivotTreeItem* pivotTreeItem = static_cast(sourceIndex.internalPointer())) + { + if (PivotTreeGraphItem* graphItem = azrtti_cast(pivotTreeItem)) + { + GeneralRequestBus::Broadcast + ( &GeneralRequests::OpenScriptCanvasAssetId + , SourceHandle(nullptr, graphItem->GetAssetId().m_guid, "") + , Tracker::ScriptCanvasFileState::UNMODIFIED); + } + } } #include diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/FunctionNodePaletteTreeItemTypes.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/FunctionNodePaletteTreeItemTypes.cpp index 6473dcbb40..b2db9508b1 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/FunctionNodePaletteTreeItemTypes.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/FunctionNodePaletteTreeItemTypes.cpp @@ -129,8 +129,10 @@ namespace ScriptCanvasEditor { if (row == NodePaletteTreeItem::Column::Customization) { - // #sc_editor_asset - // GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAsset, GetSourceAssetId(), -1); + GeneralRequestBus::Broadcast + ( &GeneralRequests::OpenScriptCanvasAssetId + , SourceHandle(nullptr, GetSourceAssetId().m_guid, "") + , Tracker::ScriptCanvasFileState::UNMODIFIED); } } @@ -138,9 +140,11 @@ namespace ScriptCanvasEditor { if (row != NodePaletteTreeItem::Column::Customization) { - // #sc_editor_asset - // GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAsset, GetSourceAssetId(), -1); - // return true; + GeneralRequestBus::Broadcast + ( &GeneralRequests::OpenScriptCanvasAssetId + , SourceHandle(nullptr, GetSourceAssetId().m_guid, "") + , Tracker::ScriptCanvasFileState::UNMODIFIED); + return true; } return false; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/StatisticsDialog/ScriptCanvasStatisticsDialog.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/StatisticsDialog/ScriptCanvasStatisticsDialog.cpp index 9538a5732a..4a0905c17c 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/StatisticsDialog/ScriptCanvasStatisticsDialog.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/StatisticsDialog/ScriptCanvasStatisticsDialog.cpp @@ -257,8 +257,10 @@ namespace ScriptCanvasEditor if (treeItem->GetAssetId().IsValid()) { - // #sc_editor_asset - // GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAssetId, treeItem->GetAssetId()); + GeneralRequestBus::Broadcast + ( &GeneralRequests::OpenScriptCanvasAssetId + , SourceHandle(nullptr, treeItem->GetAssetId().m_guid, "") + , Tracker::ScriptCanvasFileState::UNMODIFIED); } } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index 666467001c..8508ac1bc9 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -2671,10 +2671,8 @@ namespace ScriptCanvasEditor } } - void MainWindow::CopyPathToClipboard(int /*index*/) + void MainWindow::CopyPathToClipboard(int index) { - // #sc_editor_asset - /* QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) @@ -2682,20 +2680,15 @@ namespace ScriptCanvasEditor QClipboard* clipBoard = QGuiApplication::clipboard(); auto assetId = tabdata.value(); - - ScriptCanvasMemoryAsset::pointer memoryAsset; - AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, assetId); - - if (memoryAsset) + if (!assetId.m_assetId.Path().empty()) { - clipBoard->setText(memoryAsset->GetAbsolutePath().c_str()); + clipBoard->setText(assetId.m_assetId.Path().c_str()); } else { clipBoard->setText(m_tabBar->tabText(index)); } } - */ } void MainWindow::OnActiveFileStateChanged() From a8539a7b03fa389226b538e2da85f26e8144e266 Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Thu, 2 Dec 2021 15:35:46 +0000 Subject: [PATCH 066/128] Added default material return when no mapping is assigned. Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- .../TerrainPhysicsColliderComponent.cpp | 35 +++++++++++++--- .../TerrainPhysicsColliderComponent.h | 3 +- .../Tests/TerrainPhysicsColliderTests.cpp | 40 ++++++++++++++++--- 3 files changed, 66 insertions(+), 12 deletions(-) diff --git a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp index 6572b008b3..1299403659 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp @@ -284,7 +284,18 @@ namespace Terrain } } - uint8_t TerrainPhysicsColliderComponent::FindSurfaceTagIndex(const SurfaceData::SurfaceTag tag) const + uint8_t TerrainPhysicsColliderComponent::GetMaterialIdIndex(const Physics::MaterialId& materialId, const AZStd::vector& materialList) const + { + const auto& materialIter = AZStd::find(materialList.begin(), materialList.end(), materialId); + if (materialIter != materialList.end()) + { + return static_cast(materialIter - materialList.begin()); + } + + return 0; + } + + Physics::MaterialId TerrainPhysicsColliderComponent::FindMaterialIdForSurfaceTag(const SurfaceData::SurfaceTag tag) const { uint8_t index = 0; @@ -292,12 +303,13 @@ namespace Terrain { if (mapping.m_surfaceTag == tag) { - return index; + return mapping.m_materialId; } index++; } - return InvalidSurfaceTagIndex; + // If this surface isn't mapped, use the default material. + return Physics::MaterialId(); } void TerrainPhysicsColliderComponent::GenerateHeightsAndMaterialsInBounds( @@ -317,6 +329,8 @@ namespace Terrain heightMaterials.clear(); heightMaterials.reserve(gridWidth * gridHeight); + AZStd::vector materialList = GetMaterialList(); + for (int32_t row = 0; row < gridHeight; row++) { const float y = row * gridResolution.GetY() + worldSize.GetMin().GetY(); @@ -346,7 +360,10 @@ namespace Terrain Physics::HeightMaterialPoint point; point.m_height = height - worldCenterZ; point.m_quadMeshType = terrainExists ? Physics::QuadMeshType::SubdivideUpperLeftToBottomRight : Physics::QuadMeshType::Hole; - point.m_materialIndex = FindSurfaceTagIndex(surfaceWeight.m_surfaceType); + + Physics::MaterialId materialId = FindMaterialIdForSurfaceTag(surfaceWeight.m_surfaceType); + point.m_materialIndex = GetMaterialIdIndex(materialId, materialList); + heightMaterials.emplace_back(point); } } @@ -391,11 +408,17 @@ namespace Terrain AZStd::vector TerrainPhysicsColliderComponent::GetMaterialList() const { AZStd::vector materialList; - materialList.reserve(m_configuration.m_surfaceMaterialMappings.size()); + + // Ensure the list contains the default material as the first entry. + materialList.emplace_back(Physics::MaterialId()); for (auto& mapping : m_configuration.m_surfaceMaterialMappings) { - materialList.emplace_back(mapping.m_materialId); + const auto& existingInstance = AZStd::find(materialList.begin(), materialList.end(), mapping.m_materialId); + if (existingInstance == materialList.end()) + { + materialList.emplace_back(mapping.m_materialId); + } } return materialList; diff --git a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h index 79acca7e71..1a7fbf9c72 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h +++ b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h @@ -92,7 +92,8 @@ namespace Terrain bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override; bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override; - uint8_t FindSurfaceTagIndex(const SurfaceData::SurfaceTag tag) const; + uint8_t GetMaterialIdIndex(const Physics::MaterialId& materialId, const AZStd::vector& materialList) const; + Physics::MaterialId FindMaterialIdForSurfaceTag(const SurfaceData::SurfaceTag tag) const; void GenerateHeightsInBounds(AZStd::vector& heights) const; void GenerateHeightsAndMaterialsInBounds(AZStd::vector& heightMaterials) const; diff --git a/Gems/Terrain/Code/Tests/TerrainPhysicsColliderTests.cpp b/Gems/Terrain/Code/Tests/TerrainPhysicsColliderTests.cpp index b0eb5399cf..340acfbaac 100644 --- a/Gems/Terrain/Code/Tests/TerrainPhysicsColliderTests.cpp +++ b/Gems/Terrain/Code/Tests/TerrainPhysicsColliderTests.cpp @@ -327,10 +327,39 @@ TEST_F(TerrainPhysicsColliderComponentTest, TerrainPhysicsColliderReturnsMateria Physics::HeightfieldProviderRequestsBus::EventResult( materialList, m_entity->GetId(), &Physics::HeightfieldProviderRequestsBus::Events::GetMaterialList); - EXPECT_EQ(materialList.size(), 2); + // The materialList should be 3 items long: the two materials we've added, plus a default material. + EXPECT_EQ(materialList.size(), 3); - EXPECT_EQ(materialList[0], mat1); - EXPECT_EQ(materialList[1], mat2); + Physics::MaterialId defaultMaterial = Physics::MaterialId(); + EXPECT_EQ(materialList[0], defaultMaterial); + EXPECT_EQ(materialList[1], mat1); + EXPECT_EQ(materialList[2], mat2); + + m_entity.reset(); +} + +TEST_F(TerrainPhysicsColliderComponentTest, TerrainPhysicsColliderReturnsMaterialsWhenNotMapped) +{ + // Check that the TerrainPhysicsCollider returns a default material when no surfaces are mapped. + CreateEntity(); + + m_boxComponent = m_entity->CreateComponent(); + m_app.RegisterComponentDescriptor(m_boxComponent->CreateDescriptor()); + + m_colliderComponent = m_entity->CreateComponent(); + m_app.RegisterComponentDescriptor(m_colliderComponent->CreateDescriptor()); + + m_entity->Activate(); + + AZStd::vector materialList; + Physics::HeightfieldProviderRequestsBus::EventResult( + materialList, m_entity->GetId(), &Physics::HeightfieldProviderRequestsBus::Events::GetMaterialList); + + // The materialList should be 1 items long: which should be the default material. + EXPECT_EQ(materialList.size(), 1); + + Physics::MaterialId defaultMaterial = Physics::MaterialId(); + EXPECT_EQ(materialList[0], defaultMaterial); m_entity.reset(); } @@ -412,12 +441,13 @@ TEST_F(TerrainPhysicsColliderComponentTest, TerrainPhysicsColliderGetHeightsAndM const float expectedHeightValue = 16384.0f; + // // Check an entry from the first half of the returned list. - EXPECT_EQ(heightsAndMaterials[0].m_materialIndex, 0); + EXPECT_EQ(heightsAndMaterials[0].m_materialIndex, 1); EXPECT_NEAR(heightsAndMaterials[0].m_height, expectedHeightValue, 0.01f); // Check an entry from the second half of the list - EXPECT_EQ(heightsAndMaterials[256 * 128].m_materialIndex, 1); + EXPECT_EQ(heightsAndMaterials[256 * 128].m_materialIndex, 2); EXPECT_NEAR(heightsAndMaterials[256 * 128].m_height, expectedHeightValue, 0.01f); m_entity.reset(); From 5a0ab6814d693344752b671528a0db918acf3790 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Thu, 2 Dec 2021 09:17:05 -0800 Subject: [PATCH 067/128] finish last of pre-PR clean up, including saving over previsouly opened tabs Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Builder/ScriptCanvasBuilder.cpp | 36 ++- .../Code/Editor/View/Widgets/GraphTabBar.cpp | 38 +++ .../Code/Editor/View/Widgets/GraphTabBar.h | 2 + .../Code/Editor/View/Windows/MainWindow.cpp | 258 ++++++------------ .../Code/Editor/View/Windows/MainWindow.h | 2 - 5 files changed, 154 insertions(+), 182 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp index 60a3687d0d..00df5ad07b 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp @@ -20,6 +20,7 @@ namespace BuildVariableOverridesCpp { enum Version { + Original = 1, EditorAssetRedux, // add description above @@ -30,19 +31,29 @@ namespace BuildVariableOverridesCpp ( AZ::SerializeContext& serializeContext , AZ::SerializeContext::DataElementNode& rootElement) { - // #sc_editor_asset - ScriptCanvasBuilder::BuildVariableOverrides overrides; - overrides.m_source = SourceHandle(nullptr, assetHolder.GetAssetId().m_guid, {}); - - for (auto& variable : editableData.GetVariables()) + if (rootElement.GetVersion() < BuildVariableOverridesCpp::Version::EditorAssetRedux) { - overrides.m_overrides.push_back(variable.m_graphVariable); - } - - if (!rootElement.AddElementWithData(serializeContext, "runtimeDataOverrides", overrides)) - { - AZ_Error("ScriptCanvas", false, "EditorScriptCanvasComponent conversion failed: failed to add 'runtimeDataOverrides'"); - return false; + auto sourceIndex = rootElement.FindElement(AZ_CRC_CE("source")); + if (sourceIndex == -1) + { + AZ_Error("ScriptCanvas", false, "BuildVariableOverrides coversion failed: 'source' was missing"); + return false; + } + + auto& sourceElement = rootElement.GetSubElement(sourceIndex); + AZ::Data::Asset asset; + if (!sourceElement.GetData(asset)) + { + AZ_Error("ScriptCanvas", false, "BuildVariableOverrides coversion failed: could not retrieve 'source' data"); + return false; + } + + ScriptCanvasEditor::SourceHandle sourceHandle(nullptr, asset.GetId().m_guid, {}); + if (!rootElement.AddElementWithData(serializeContext, "source", sourceHandle)) + { + AZ_Error("ScriptCanvas", false, "BuildVariableOverrides coversion failed: could not add updated 'source' data"); + return false; + } } return true; @@ -136,7 +147,6 @@ namespace ScriptCanvasBuilder return m_variables.empty() && m_entityIds.empty() && m_dependencies.empty(); } - // #sc_editor_asset THIS MUST GET VERSIONED! void BuildVariableOverrides::Reflect(AZ::ReflectContext* reflectContext) { if (auto serializeContext = azrtti_cast(reflectContext)) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp index 53b2cecabc..4e9398fdcf 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.cpp @@ -175,6 +175,7 @@ namespace ScriptCanvasEditor setCurrentIndex(tabIndex); return true; } + return false; } @@ -192,6 +193,43 @@ namespace ScriptCanvasEditor } } } + + return -1; + } + + int GraphTabBar::FindTab(ScriptCanvasEditor::GraphPtrConst graph) const + { + for (int tabIndex = 0; tabIndex < count(); ++tabIndex) + { + QVariant tabDataVariant = tabData(tabIndex); + if (tabDataVariant.isValid()) + { + auto tabAssetId = tabDataVariant.value(); + if (tabAssetId.m_assetId.Get() == graph) + { + return tabIndex; + } + } + } + + return -1; + } + + int GraphTabBar::FindSaveOverMatch(ScriptCanvasEditor::SourceHandle assetId) const + { + for (int tabIndex = 0; tabIndex < count(); ++tabIndex) + { + QVariant tabDataVariant = tabData(tabIndex); + if (tabDataVariant.isValid()) + { + auto tabAssetId = tabDataVariant.value(); + if (tabAssetId.m_assetId.Get() != assetId.Get() && tabAssetId.m_assetId.PathEquals(assetId)) + { + return tabIndex; + } + } + } + return -1; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h index e19ceaa4ec..939fb7c8f4 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/GraphTabBar.h @@ -62,6 +62,8 @@ namespace ScriptCanvasEditor bool SelectTab(ScriptCanvasEditor::SourceHandle assetId); int FindTab(ScriptCanvasEditor::SourceHandle assetId) const; + int FindTab(ScriptCanvasEditor::GraphPtrConst graph) const; + int FindSaveOverMatch(ScriptCanvasEditor::SourceHandle assetId) const; ScriptCanvasEditor::SourceHandle FindTabByPath(AZStd::string_view path) const; ScriptCanvasEditor::SourceHandle FindAssetId(int tabIndex); ScriptCanvas::ScriptCanvasId FindScriptCanvasIdFromGraphCanvasId(const GraphCanvas::GraphId& graphCanvasGraphId) const; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index 8508ac1bc9..3535fa34cf 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -908,19 +908,10 @@ namespace ScriptCanvasEditor return; } - AssetTrackerRequests::AssetList unsavedAssets; - AssetTrackerRequestBus::BroadcastResult(unsavedAssets, &AssetTrackerRequests::GetUnsavedAssets); - for (int tabCounter = 0; tabCounter < m_tabBar->count(); ++tabCounter) { ScriptCanvasEditor::SourceHandle assetId = m_tabBar->FindAssetId(tabCounter); - auto resultIterator = m_processedClosedAssetIds.insert(assetId); - if (!resultIterator.second) - { - continue; - } - const Tracker::ScriptCanvasFileState& fileState = GetAssetFileState(assetId); if (fileState == Tracker::ScriptCanvasFileState::UNMODIFIED) @@ -936,30 +927,13 @@ namespace ScriptCanvasEditor if (shouldSaveResults == UnsavedChangesOptions::SAVE) { - // #sc_editor_asset -// Callbacks::OnSave saveCB = [this](bool isSuccessful, AZ::Data::AssetPtr, ScriptCanvasEditor::SourceHandle) -// { -// if (isSuccessful) -// { -// // Continue closing. -// qobject_cast(parent())->close(); -// } -// else -// { -// // Abort closing. -// QMessageBox::critical(this, QString(), QObject::tr("Failed to save.")); -// m_processedClosedAssetIds.clear(); -// } -// }; -// ActivateAndSaveAsset(assetId, saveCB); + SaveAssetImpl(assetId, Save::InPlace); event->ignore(); return; } else if (shouldSaveResults == UnsavedChangesOptions::CANCEL_WITHOUT_SAVING) { - m_processedClosedAssetIds.clear(); event->ignore(); - return; } else if (shouldSaveResults == UnsavedChangesOptions::CONTINUE_WITHOUT_SAVING && @@ -971,20 +945,6 @@ namespace ScriptCanvasEditor } m_workspace->Save(); - - // Close all files. -// -// AssetTrackerRequests::AssetList allAssets; -// AssetTrackerRequestBus::BroadcastResult(allAssets, &AssetTrackerRequests::GetAssets); -// -// for (auto trackedAsset : allAssets) -// { -// const ScriptCanvasEditor::SourceHandle& assetId = trackedAsset->GetAsset().GetId(); -// CloseScriptCanvasAsset(assetId); -// } - - m_processedClosedAssetIds.clear(); - event->accept(); } @@ -1364,10 +1324,9 @@ namespace ScriptCanvasEditor return createdNewAsset; } - bool MainWindow::IsScriptCanvasAssetOpen(const ScriptCanvasEditor::SourceHandle& /*assetId*/) const + bool MainWindow::IsScriptCanvasAssetOpen(const ScriptCanvasEditor::SourceHandle& assetId) const { - // #sc_editor_asset - return false; + return m_tabBar->FindTab(assetId) >= 0; } const CategoryInformation* MainWindow::FindNodePaletteCategoryInformation(AZStd::string_view categoryPath) const @@ -1535,7 +1494,7 @@ namespace ScriptCanvasEditor void MainWindow::OnFileNew() { - int scriptCanvasEditorDefaultNewNameCount = 0; + static int scriptCanvasEditorDefaultNewNameCount = 0; AZStd::string assetPath; @@ -1783,8 +1742,6 @@ namespace ScriptCanvasEditor if (saveSuccess) { - // #sc_editor_asset find a tab with the same path name and close non focused old ones with the same name - // Update the editor with the new information about this asset. ScriptCanvasEditor::SourceHandle& fileAssetId = memoryAsset; int currentTabIndex = m_tabBar->currentIndex(); @@ -1797,13 +1754,26 @@ namespace ScriptCanvasEditor const bool assetIdHasChanged = assetInfo.m_assetId.m_guid != fileAssetId.Id(); fileAssetId = SourceHandle(fileAssetId, assetInfo.m_assetId.m_guid, fileAssetId.Path()); - // #sc_editor_asset // check for saving a graph over another graph with an open tab + for (;;) { - // find the saved tab by graph* - // find all tabs that match old path, and close them - // update the save tab index - // and the current index + auto graph = fileAssetId.Get(); + int tabIndexByGraph = m_tabBar->FindTab(graph); + if (tabIndexByGraph == -1) + { + AZ_Warning("ScriptCanvas", false, "unable to find graph just saved"); + break; + } + + int saveOverMatch = m_tabBar->FindSaveOverMatch(fileAssetId); + if (saveOverMatch < 0) + { + saveTabIndex = tabIndexByGraph; + currentTabIndex = m_tabBar->currentIndex(); + break; + } + + m_tabBar->CloseTab(saveOverMatch); } // this path is questionable, this is a save request that is not the current graph @@ -1816,22 +1786,7 @@ namespace ScriptCanvasEditor saveTabIndex = -1; } - // #sc_editor_asset clean up these actions as well, save and close, save as and close, just save, etc - if (saveTabIndex < 0) - { - // This asset had not been saved yet, we will need to use the in memory asset Id to get the index. - // saveTabIndex = m_tabBar->FindTab(memoryAsset->GetId()); - - if (saveTabIndex < 0) - { - // Finally, we may have Saved-As and we need the previous file asset Id to find the tab - //saveTabIndex = m_tabBar->FindTab(previousFileAssetId); - } - } - AzFramework::StringFunc::Path::GetFileName(memoryAsset.Path().c_str(), tabName); - // Update the tab's assetId to the file asset Id (necessary when saving a new asset) - // #sc_editor_asset used to be configure tab...sets the name and file state if (assetIdHasChanged) { @@ -2316,34 +2271,6 @@ namespace ScriptCanvasEditor GraphCanvas::ViewRequestBus::Event(viewId, &GraphCanvas::ViewRequests::CenterOnEndOfChain); } - // #sc_editor_asset - void MainWindow::UpdateWorkspaceStatus(const ScriptCanvasMemoryAsset& /*memoryAsset*/) - { - // only occurs on file open, do it there, if necessary - /* - ScriptCanvasEditor::SourceHandle fileAssetId = memoryAsset.GetFileAssetId(); - - size_t eraseCount = m_loadingAssets.erase(fileAssetId); - - if (eraseCount > 0) - { - AZStd::string rootFilePath; - AZ::Data::AssetInfo assetInfo = AssetHelpers::GetAssetInfo(fileAssetId, rootFilePath); - - // Don't want to use the join since I don't want the normalized path - if (!rootFilePath.empty() && !assetInfo.m_relativePath.empty()) - { - eraseCount = m_loadingWorkspaceAssets.erase(fileAssetId); - - if (eraseCount == 0) - { - AZStd::string fullPath = AZStd::string::format("%s/%s", rootFilePath.c_str(), assetInfo.m_relativePath.c_str()); - } - } - } - */ - } - void MainWindow::OnCanUndoChanged(bool canUndo) { ui->action_Undo->setEnabled(canUndo); @@ -3600,25 +3527,24 @@ namespace ScriptCanvasEditor return findChild(elementName); } - AZ::EntityId MainWindow::FindEditorNodeIdByAssetNodeId(const ScriptCanvasEditor::SourceHandle& /*assetId*/, AZ::EntityId /*assetNodeId*/) const + AZ::EntityId MainWindow::FindEditorNodeIdByAssetNodeId(const ScriptCanvasEditor::SourceHandle& assetId, AZ::EntityId assetNodeId) const { - // #sc_editor_asset - return AZ::EntityId{}; - // AZ::EntityId editorEntityId; - // AssetTrackerRequestBus::BroadcastResult(editorEntityId, &AssetTrackerRequests::GetEditorEntityIdFromSceneEntityId, assetId, assetNodeId); - //return AZ::EntityId{};// editorEntityId; + AZ::EntityId editorEntityId; + AssetTrackerRequestBus::BroadcastResult + ( editorEntityId, &AssetTrackerRequests::GetEditorEntityIdFromSceneEntityId, assetId.Id(), assetNodeId); + return editorEntityId; } - AZ::EntityId MainWindow::FindAssetNodeIdByEditorNodeId(const ScriptCanvasEditor::SourceHandle& /*assetId*/, AZ::EntityId /*editorNodeId*/) const + AZ::EntityId MainWindow::FindAssetNodeIdByEditorNodeId(const ScriptCanvasEditor::SourceHandle& assetId, AZ::EntityId editorNodeId) const { - // #sc_editor_asset - return AZ::EntityId{}; - // AZ::EntityId sceneEntityId; - // AssetTrackerRequestBus::BroadcastResult(sceneEntityId, &AssetTrackerRequests::GetSceneEntityIdFromEditorEntityId, assetId, editorNodeId); - // return sceneEntityId; + AZ::EntityId sceneEntityId; + AssetTrackerRequestBus::BroadcastResult + ( sceneEntityId, &AssetTrackerRequests::GetSceneEntityIdFromEditorEntityId, assetId.Id(), editorNodeId); + return sceneEntityId; } - GraphCanvas::Endpoint MainWindow::CreateNodeForProposalWithGroup(const AZ::EntityId& connectionId, const GraphCanvas::Endpoint& endpoint, const QPointF& scenePoint, const QPoint& screenPoint, AZ::EntityId groupTarget) + GraphCanvas::Endpoint MainWindow::CreateNodeForProposalWithGroup(const AZ::EntityId& connectionId + , const GraphCanvas::Endpoint& endpoint, const QPointF& scenePoint, const QPoint& screenPoint, AZ::EntityId groupTarget) { PushPreventUndoStateUpdate(); @@ -4070,65 +3996,63 @@ namespace ScriptCanvasEditor void MainWindow::OnAssignToSelectedEntities() { - // #sc_editor_asset consider cutting -// Tracker::ScriptCanvasFileState fileState; -// AssetTrackerRequestBus::BroadcastResult(fileState, &AssetTrackerRequests::GetFileState, m_activeGraph); -// -// bool isDocumentOpen = false; -// AzToolsFramework::EditorRequests::Bus::BroadcastResult(isDocumentOpen, &AzToolsFramework::EditorRequests::IsLevelDocumentOpen); -// -// if (fileState == Tracker::ScriptCanvasFileState::NEW || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED || !isDocumentOpen) -// { -// return; -// } -// -// AzToolsFramework::EntityIdList selectedEntityIds; -// AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(selectedEntityIds, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities); -// -// auto selectedEntityIdIter = selectedEntityIds.begin(); -// -// bool isLayerAmbiguous = false; -// AZ::EntityId targetLayer; -// -// while (selectedEntityIdIter != selectedEntityIds.end()) -// { -// bool isLayerEntity = false; -// AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(isLayerEntity, (*selectedEntityIdIter), &AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer); -// -// if (isLayerEntity) -// { -// if (targetLayer.IsValid()) -// { -// isLayerAmbiguous = true; -// } -// -// targetLayer = (*selectedEntityIdIter); -// -// selectedEntityIdIter = selectedEntityIds.erase(selectedEntityIdIter); -// } -// else -// { -// ++selectedEntityIdIter; -// } -// } -// -// if (selectedEntityIds.empty()) -// { -// AZ::EntityId createdId; -// AzToolsFramework::EditorRequests::Bus::BroadcastResult(createdId, &AzToolsFramework::EditorRequests::CreateNewEntity, AZ::EntityId()); -// -// selectedEntityIds.emplace_back(createdId); -// -// if (targetLayer.IsValid() && !isLayerAmbiguous) -// { -// AZ::TransformBus::Event(createdId, &AZ::TransformBus::Events::SetParent, targetLayer); -// } -// } -// -// for (const AZ::EntityId& entityId : selectedEntityIds) -// { -// AssignGraphToEntityImpl(entityId); -// } + Tracker::ScriptCanvasFileState fileState = GetAssetFileState(m_activeGraph);; + + bool isDocumentOpen = false; + AzToolsFramework::EditorRequests::Bus::BroadcastResult(isDocumentOpen, &AzToolsFramework::EditorRequests::IsLevelDocumentOpen); + + if (fileState == Tracker::ScriptCanvasFileState::NEW || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED || !isDocumentOpen) + { + return; + } + + AzToolsFramework::EntityIdList selectedEntityIds; + AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(selectedEntityIds, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities); + + auto selectedEntityIdIter = selectedEntityIds.begin(); + + bool isLayerAmbiguous = false; + AZ::EntityId targetLayer; + + while (selectedEntityIdIter != selectedEntityIds.end()) + { + bool isLayerEntity = false; + AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(isLayerEntity, (*selectedEntityIdIter), &AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer); + + if (isLayerEntity) + { + if (targetLayer.IsValid()) + { + isLayerAmbiguous = true; + } + + targetLayer = (*selectedEntityIdIter); + + selectedEntityIdIter = selectedEntityIds.erase(selectedEntityIdIter); + } + else + { + ++selectedEntityIdIter; + } + } + + if (selectedEntityIds.empty()) + { + AZ::EntityId createdId; + AzToolsFramework::EditorRequests::Bus::BroadcastResult(createdId, &AzToolsFramework::EditorRequests::CreateNewEntity, AZ::EntityId()); + + selectedEntityIds.emplace_back(createdId); + + if (targetLayer.IsValid() && !isLayerAmbiguous) + { + AZ::TransformBus::Event(createdId, &AZ::TransformBus::Events::SetParent, targetLayer); + } + } + + for (const AZ::EntityId& entityId : selectedEntityIds) + { + AssignGraphToEntityImpl(entityId); + } } void MainWindow::OnAssignToEntity(const AZ::EntityId& entityId) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h index 68488238ec..80117b84fe 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h @@ -532,8 +532,6 @@ namespace ScriptCanvasEditor void DisconnectEndpoints(const AZ::EntityId& sceneId, const AZStd::vector& endpoints) override; ///////////////////////////////////////////////////////////////////////////////////////////// - void UpdateWorkspaceStatus(const ScriptCanvasMemoryAsset& scriptCanvasAsset); - GraphCanvas::Endpoint HandleProposedConnection(const GraphCanvas::GraphId& graphId, const GraphCanvas::ConnectionId& connectionId, const GraphCanvas::Endpoint& endpoint, const GraphCanvas::NodeId& proposedNode, const QPoint& screenPoint); //! UndoNotificationBus From ab76f8cb6289ad9a10c25e46694b929a09785288 Mon Sep 17 00:00:00 2001 From: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> Date: Thu, 2 Dec 2021 12:28:58 -0600 Subject: [PATCH 068/128] Combined tests under NoAutoTestMode test class. Updated prefab name in test due to conflict running in parallel. Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> --- .../Prefab/TestSuite_Main_Optimized.py | 38 ++++++++----------- .../DetachPrefab_UnderAnotherPrefab.py | 4 +- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main_Optimized.py index 881fc46a93..bf67b2c661 100644 --- a/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main_Optimized.py @@ -10,33 +10,12 @@ import pytest from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite -@pytest.mark.SUITE_main -@pytest.mark.parametrize("launcher_platform", ['windows_editor']) -@pytest.mark.parametrize("project", ["AutomatedTesting"]) -class TestAutomationAutoTestMode(EditorTestSuite): - - class test_OpenLevel_ContainingTwoEntities(EditorSharedTest): - from .tests.open_level import OpenLevel_ContainingTwoEntities as test_module - - class test_CreatePrefab_WithSingleEntity(EditorSharedTest): - from .tests.create_prefab import CreatePrefab_WithSingleEntity as test_module - - class test_InstantiatePrefab_ContainingASingleEntity(EditorSharedTest): - from .tests.instantiate_prefab import InstantiatePrefab_ContainingASingleEntity as test_module - - class test_DeletePrefab_ContainingASingleEntity(EditorSharedTest): - from .tests.delete_prefab import DeletePrefab_ContainingASingleEntity as test_module - - class test_DuplicatePrefab_ContainingASingleEntity(EditorSharedTest): - from .tests.duplicate_prefab import DuplicatePrefab_ContainingASingleEntity as test_module - - @pytest.mark.SUITE_main @pytest.mark.parametrize("launcher_platform", ['windows_editor']) @pytest.mark.parametrize("project", ["AutomatedTesting"]) class TestAutomationNoAutoTestMode(EditorTestSuite): - # Enable only -BatchMode for these tests. Tests cannot run in -autotest_mode due to UI interactions + # Enable only -BatchMode for these tests. Some tests cannot run in -autotest_mode due to UI interactions global_extra_cmdline_args = ["-BatchMode"] class test_CreatePrefab_UnderAnEntity(EditorSharedTest): @@ -56,3 +35,18 @@ class TestAutomationNoAutoTestMode(EditorTestSuite): class test_DetachPrefab_UnderAnotherPrefab(EditorSharedTest): from .tests.detach_prefab import DetachPrefab_UnderAnotherPrefab as test_module + + class test_OpenLevel_ContainingTwoEntities(EditorSharedTest): + from .tests.open_level import OpenLevel_ContainingTwoEntities as test_module + + class test_CreatePrefab_WithSingleEntity(EditorSharedTest): + from .tests.create_prefab import CreatePrefab_WithSingleEntity as test_module + + class test_InstantiatePrefab_ContainingASingleEntity(EditorSharedTest): + from .tests.instantiate_prefab import InstantiatePrefab_ContainingASingleEntity as test_module + + class test_DeletePrefab_ContainingASingleEntity(EditorSharedTest): + from .tests.delete_prefab import DeletePrefab_ContainingASingleEntity as test_module + + class test_DuplicatePrefab_ContainingASingleEntity(EditorSharedTest): + from .tests.duplicate_prefab import DuplicatePrefab_ContainingASingleEntity as test_module \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/tests/detach_prefab/DetachPrefab_UnderAnotherPrefab.py b/AutomatedTesting/Gem/PythonTests/Prefab/tests/detach_prefab/DetachPrefab_UnderAnotherPrefab.py index 5c97f0b032..69dbcfc89c 100644 --- a/AutomatedTesting/Gem/PythonTests/Prefab/tests/detach_prefab/DetachPrefab_UnderAnotherPrefab.py +++ b/AutomatedTesting/Gem/PythonTests/Prefab/tests/detach_prefab/DetachPrefab_UnderAnotherPrefab.py @@ -7,8 +7,8 @@ SPDX-License-Identifier: Apache-2.0 OR MIT def DetachPrefab_UnderAnotherPrefab(): - CAR_PREFAB_FILE_NAME = 'car_prefab' - WHEEL_PREFAB_FILE_NAME = 'wheel_prefab' + CAR_PREFAB_FILE_NAME = 'car_prefab2' + WHEEL_PREFAB_FILE_NAME = 'wheel_prefab2' import editor_python_test_tools.pyside_utils as pyside_utils From d158d36ce41a20fa5dc5c5563046cbed6ec6381f Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Thu, 2 Dec 2021 13:14:48 -0800 Subject: [PATCH 069/128] add the test steps to the docstring for the AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages() function Signed-off-by: jromnoa <80134229+jromnoa@users.noreply.github.com> --- .../hydra_AtomGPU_SpotLightScreenshotTest.py | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py index 9b1c88a4fc..e1cbbbc613 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py @@ -74,8 +74,23 @@ def AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages(): Test Steps: 1. Find the Directional Light entity then disable its Directional Light component. - 2. Disable Global Skylight (IBL) and HDRi Skybox components on the Global Skylight entity. - + 2. Disable Global Skylight (IBL) component on the Global Skylight (IBL) entity. + 3. Disable HDRi Skybox component on the Global Skylight (IBL) entity. + 4. Create a Spot Light entity and rotate it. + 5. Attach a Light component to the Spot Light entity. + 6. Set the Light component Light Type to Spot (disk). + 7. Enter game mode and take a screenshot then exit game mode. + 8. Change the default material asset for the Ground Plane entity. + 9. Enter game mode and take a screenshot then exit game mode. + 10. Increase the Intensity value of the Light component. + 11. Enter game mode and take a screenshot then exit game mode. + 12. Change the Light component Color property value. + 13. Enter game mode and take a screenshot then exit game mode. + 14. Change the Light component Enable shutters, Inner angle, and Outer angle property values. + 15. Enter game mode and take a screenshot then exit game mode. + 16. Change the Light component Enable shadow and Shadowmap size property values then move Spot Light entity. + 17. Enter game mode and take a screenshot then exit game mode. + 18. Look for errors. :return: None """ @@ -124,7 +139,7 @@ def AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages(): global_skylight_component.disable_component() Report.critical_result(Tests.global_skylight_component_disabled, not global_skylight_component.is_enabled()) - # 3. Disable HDRi Skybox component on the Global Skylight (IBL) entity + # 3. Disable HDRi Skybox component on the Global Skylight (IBL) entity. hdri_skybox_name = AtomComponentProperties.hdri_skybox() hdri_skybox_component = global_skylight_entity.get_components_of_type([hdri_skybox_name])[0] hdri_skybox_component.disable_component() From e53295526542fdb16a1e12d395dc06228b1770e4 Mon Sep 17 00:00:00 2001 From: carlitosan <82187351+carlitosan@users.noreply.github.com> Date: Thu, 2 Dec 2021 10:31:51 -0800 Subject: [PATCH 070/128] Delete $tmp29198_Test_LY_79396.scriptcanvas Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../$tmp29198_Test_LY_79396.scriptcanvas | 69 ------------------- 1 file changed, 69 deletions(-) delete mode 100644 Gems/ScriptCanvasTesting/Assets/ScriptCanvas/Tests/$tmp29198_Test_LY_79396.scriptcanvas diff --git a/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/Tests/$tmp29198_Test_LY_79396.scriptcanvas b/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/Tests/$tmp29198_Test_LY_79396.scriptcanvas deleted file mode 100644 index 278d74c28d..0000000000 --- a/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/Tests/$tmp29198_Test_LY_79396.scriptcanvas +++ /dev/null @@ -1,69 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "ScriptCanvasData", - "ClassData": { - "m_scriptCanvas": { - "Id": { - "id": 32884619828465 - }, - "Name": "Script Canvas Graph", - "Components": { - "Component_[14322649685925277086]": { - "$type": "EditorGraphVariableManagerComponent", - "Id": 14322649685925277086, - "m_variableData": { - "m_nameVariableMap": [ - { - "Key": { - "m_id": "{142C0457-38E5-496E-A4F2-67E91852CBCB}" - }, - "Value": { - "Datum": { - "isOverloadedStorage": false, - "scriptCanvasType": { - "m_type": 4, - "m_azType": "{5CBE5640-DF5C-5A49-9195-D790881A0747}" - }, - "isNullPointer": false, - "$type": "{5CBE5640-DF5C-5A49-9195-D790881A0747} AZStd::vector", - "value": [ - [ - 0.0, - 0.0, - -498814079205376.0, - 0.0 - ], - [ - 0.0, - 0.0, - 1.1865528051967005e38, - 0.0 - ] - ], - "label": "Variable 7" - }, - "VariableId": { - "m_id": "{142C0457-38E5-496E-A4F2-67E91852CBCB}" - }, - "VariableName": "Variable 7" - } - }, - { - "Key": { - "m_id": "{21DD2B3D-ADC9-46E1-B44C-965A6E2AE543}" - }, - "Value": { - "Datum": { - "isOverloadedStorage": false, - "scriptCanvasType": { - "m_type": 4, - "m_azType": "{9ABF5933-C8FC-53CD-A518-B6AF433CF496}" - }, - "isNullPointer": false, - "$type": "{9ABF5933-C8FC-53CD-A518-B6AF433CF496} AZStd::unordered_map", - "value": [ - { - "Key": true, - "Value": { - "roll": \ No newline at end of file From 7dc03485b66efebf825a984c7c50b5a1545ba937 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Thu, 2 Dec 2021 13:08:03 -0800 Subject: [PATCH 071/128] remove uneeded files/comments Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Builder/ScriptCanvasBuilderWorker.cpp | 1 - .../Code/Builder/ScriptCanvasBuilderWorker.h | 2 +- .../ScriptCanvas/Assets/ScriptCanvasFileHandling.h | 1 - .../Assets/ScriptCanvasSourceFileHandle.cpp | 9 --------- .../ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.h | 10 ---------- .../ScriptCanvas/Code/Editor/View/Windows/MainWindow.h | 1 - .../Code/scriptcanvasgem_editor_files.cmake | 2 -- 7 files changed, 1 insertion(+), 25 deletions(-) delete mode 100644 Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.cpp delete mode 100644 Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.h diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp index bf98e62b71..ac7bd4406a 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h index 77b90df3e0..817fe5d294 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h @@ -59,7 +59,7 @@ namespace ScriptCanvasBuilder PrefabIntegration, CorrectGraphVariableVersion, ReflectEntityIdNodes, - FixExecutionStateNodeableConstrution, + FixExecutionStateNodeableConstruction, // add new entries above Current, diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h index dd0e7aeb62..bd3d2b9f0a 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h @@ -12,7 +12,6 @@ #include #include #include -#include namespace AZ { diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.cpp b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.cpp deleted file mode 100644 index 258a862a19..0000000000 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.cpp +++ /dev/null @@ -1,9 +0,0 @@ -/* - * 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 diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.h deleted file mode 100644 index 1d14b9b21b..0000000000 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - * 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 - diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h index 80117b84fe..fed4f28f4f 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include diff --git a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake index 449298097f..77ccf7fda9 100644 --- a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake +++ b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake @@ -28,8 +28,6 @@ set(FILES Editor/Include/ScriptCanvas/Assets/ScriptCanvasAssetBus.h Editor/Include/ScriptCanvas/Assets/ScriptCanvasAssetTypes.h Editor/Include/ScriptCanvas/Assets/ScriptCanvasFileHandling.h - Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.h - Editor/Include/ScriptCanvas/Assets/ScriptCanvasSourceFileHandle.cpp Editor/Include/ScriptCanvas/Assets/ScriptCanvasAssetHandler.h Editor/Assets/ScriptCanvasFileHandling.cpp Editor/Assets/ScriptCanvasAssetHandler.cpp From 1005ec970084ac96a47c46f794740b7c8f464660 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Thu, 2 Dec 2021 13:08:34 -0800 Subject: [PATCH 072/128] remove uneeded files/comments Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h index be8f274cd6..a969187743 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h @@ -387,7 +387,7 @@ namespace ScriptCanvasEditor bool m_saveFormatConverted = true; ScriptCanvasEditor::SourceHandle m_assetId; - // #sc_editor_asset temporary step in cleaning up the graph / asset class structure. This reference is deliberately weak. + // temporary step in cleaning up the graph / asset class structure. This reference is deliberately weak. ScriptCanvas::ScriptCanvasData* m_owner; }; } From 9b0df63505faeadb0f4f1956c227d1c5abf75087 Mon Sep 17 00:00:00 2001 From: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> Date: Thu, 2 Dec 2021 15:39:17 -0600 Subject: [PATCH 073/128] Testing crash log retrieval on Linux Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> --- .../tests/create_prefab/CreatePrefab_WithSingleEntity.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/tests/create_prefab/CreatePrefab_WithSingleEntity.py b/AutomatedTesting/Gem/PythonTests/Prefab/tests/create_prefab/CreatePrefab_WithSingleEntity.py index 80f4c0e596..136f00a9bf 100644 --- a/AutomatedTesting/Gem/PythonTests/Prefab/tests/create_prefab/CreatePrefab_WithSingleEntity.py +++ b/AutomatedTesting/Gem/PythonTests/Prefab/tests/create_prefab/CreatePrefab_WithSingleEntity.py @@ -23,7 +23,8 @@ def CreatePrefab_WithSingleEntity(): # Creates a prefab from the new entity Prefab.create_prefab(car_prefab_entities, CAR_PREFAB_FILE_NAME) - + azlmbr.legacy.general.run_console("sys_crashtest 1") + if __name__ == "__main__": from editor_python_test_tools.utils import Report Report.start_test(CreatePrefab_WithSingleEntity) From 97cd722ac16c18253f12517b7199cb7bd35ef1a6 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Thu, 2 Dec 2021 14:42:37 -0800 Subject: [PATCH 074/128] remove shadowmap size calls to fix test, clean up some property value assignments for component tests Signed-off-by: jromnoa <80134229+jromnoa@users.noreply.github.com> --- .../PythonTests/Atom/atom_utils/atom_constants.py | 1 - .../tests/hydra_AtomGPU_SpotLightScreenshotTest.py | 14 ++++---------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py index 559f4aebee..59a07cf7bc 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py @@ -263,7 +263,6 @@ class AtomComponentProperties: 'Intensity': 'Controller|Configuration|Intensity', 'Light type': 'Controller|Configuration|Light type', 'Outer angle': 'Controller|Configuration|Shutters|Outer angle', - 'Shadowmap size': 'Controller|Configuration|Shadows|Shadowmap size', } return properties[property] diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py index e1cbbbc613..dd2470e8b2 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py @@ -46,9 +46,6 @@ class Tests: light_component_outer_angle_property_set = ( "Outer angle property was set", "Outer angle property was not set") - light_component_shadowmap_size_property_set = ( - "Shadowmap size was set", - "Shadowmap size was not set") material_component_material_asset_property_set = ( "Material Asset property was set", "Material Asset property was not set") @@ -186,7 +183,8 @@ def AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages(): AtomComponentProperties.material('Material Asset'), ground_plane_material_asset.id) Report.result( Tests.material_component_material_asset_property_set, - light_component.get_component_property_value(AtomComponentProperties.material('Material Asset'))) + ground_plane_material_component.get_component_property_value( + AtomComponentProperties.material('Material Asset')) == ground_plane_material_asset.id) # 9. Enter game mode and take a screenshot then exit game mode. TestHelper.enter_game_mode(Tests.enter_game_mode) @@ -248,16 +246,12 @@ def AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages(): TestHelper.exit_game_mode(Tests.exit_game_mode) TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) - # 16. Change the Light component Enable shadow and Shadowmap size property values then move Spot Light entity. + # 16. Change the Light component Enable shadow and slightly move Spot Light entity. light_component.set_component_property_value(AtomComponentProperties.light('Enable shadow'), True) - light_component.set_component_property_value(AtomComponentProperties.light('Shadowmap size'), 256.0) - spot_light_entity.set_world_rotation(azlmbr.math.Vector3(0.7, -2.0, 1.9)) Report.result( Tests.light_component_enable_shadow_property_set, light_component.get_component_property_value(AtomComponentProperties.light('Enable shadow')) is True) - Report.result( - Tests.light_component_shadowmap_size_property_set, - light_component.get_component_property_value(AtomComponentProperties.light('Shadowmap size')) == 256.0) + spot_light_entity.set_world_rotation(azlmbr.math.Vector3(0.7, -2.0, 1.9)) # 17. Enter game mode and take a screenshot then exit game mode. TestHelper.enter_game_mode(Tests.enter_game_mode) From 37ae47dda1ee9b00860fc5b0c117c5cae82050a1 Mon Sep 17 00:00:00 2001 From: carlitosan <82187351+carlitosan@users.noreply.github.com> Date: Thu, 2 Dec 2021 16:02:29 -0800 Subject: [PATCH 075/128] fix linux build error Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com> --- .../Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp | 3 +-- .../Code/Editor/Assets/ScriptCanvasMemoryAsset.h | 1 - .../Code/Editor/View/Widgets/CanvasWidget.cpp | 13 ------------- 3 files changed, 1 insertion(+), 16 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp index 01595e0702..992b33889b 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp @@ -19,8 +19,7 @@ namespace ScriptCanvasEditor { ScriptCanvasMemoryAsset::ScriptCanvasMemoryAsset() - : m_isSaving(false) - , m_sourceInError(false) + : m_sourceInError(false) { m_undoState = AZStd::make_unique(this); } diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.h b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.h index 6eecc5e04f..45647eba1b 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.h +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.h @@ -321,7 +321,6 @@ namespace ScriptCanvasEditor //! The undo helper is an object that implements the Undo behaviors AZStd::unique_ptr m_undoHelper; - bool m_isSaving; bool m_sourceInError; AZ::Data::AssetId m_sourceUuid; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp index aa427b2629..69fe4053fe 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp @@ -69,28 +69,15 @@ namespace ScriptCanvasEditor void CanvasWidget::ShowScene(const ScriptCanvas::ScriptCanvasId& scriptCanvasId) { EditorGraphRequests* editorGraphRequests = EditorGraphRequestBus::FindFirstHandler(scriptCanvasId); - - // #sc-editor-asset check if needed: editorGraphRequests->SetAssetId(m_assetId); - editorGraphRequests->CreateGraphCanvasScene(); - AZ::EntityId graphCanvasSceneId = editorGraphRequests->GetGraphCanvasGraphId(); - m_graphicsView->SetScene(graphCanvasSceneId); - m_scriptCanvasId = scriptCanvasId; } void CanvasWidget::SetAssetId(const ScriptCanvasEditor::SourceHandle& assetId) { m_assetId = assetId; - // #sc-editor-asset check if needed: - /* - if (EditorGraphRequests* editorGraphRequests = EditorGraphRequestBus::FindFirstHandler(m_scriptCanvasId)) - { - editorGraphRequests->SetAssetId(m_assetId); - } - */ } const GraphCanvas::ViewId& CanvasWidget::GetViewId() const From e6fb876682f7d8487b12dd9aff98b9942860c8e7 Mon Sep 17 00:00:00 2001 From: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> Date: Thu, 2 Dec 2021 18:24:26 -0600 Subject: [PATCH 076/128] Updating error log handling for Linux Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> --- .../Gem/PythonTests/automatedtesting_shared/base.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/base.py b/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/base.py index 4543888a7c..c0c0c4a48a 100755 --- a/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/base.py +++ b/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/base.py @@ -8,7 +8,7 @@ SPDX-License-Identifier: Apache-2.0 OR MIT import os import logging -import subprocess +import sys import pytest import time @@ -128,7 +128,11 @@ class TestAutomationBase: errors.append(TestRunError("FAILED TEST", error_str)) if return_code and return_code != TestAutomationBase.TEST_FAIL_RETCODE: # Crashed crash_info = "-- No crash log available --" - crash_log = os.path.join(workspace.paths.project_log(), 'error.log') + if sys.platform.startswith('linux'): + crash_log = os.path.join(workspace.paths.project_log(), 'crash.log') + else: + crash_log = os.path.join(workspace.paths.project_log(), 'error.log') + try: waiter.wait_for(lambda: os.path.exists(crash_log), timeout=TestAutomationBase.WAIT_FOR_CRASH_LOG) except AssertionError: From 1f51e186fba52966f37e0fe67c6dc79326fe5cbb Mon Sep 17 00:00:00 2001 From: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> Date: Thu, 2 Dec 2021 18:51:59 -0600 Subject: [PATCH 077/128] Removing intentional crash used for testing from CreatePrefab_WithSingleEntity.py Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> --- .../Prefab/tests/create_prefab/CreatePrefab_WithSingleEntity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/tests/create_prefab/CreatePrefab_WithSingleEntity.py b/AutomatedTesting/Gem/PythonTests/Prefab/tests/create_prefab/CreatePrefab_WithSingleEntity.py index 136f00a9bf..eb8a262a69 100644 --- a/AutomatedTesting/Gem/PythonTests/Prefab/tests/create_prefab/CreatePrefab_WithSingleEntity.py +++ b/AutomatedTesting/Gem/PythonTests/Prefab/tests/create_prefab/CreatePrefab_WithSingleEntity.py @@ -23,7 +23,7 @@ def CreatePrefab_WithSingleEntity(): # Creates a prefab from the new entity Prefab.create_prefab(car_prefab_entities, CAR_PREFAB_FILE_NAME) - azlmbr.legacy.general.run_console("sys_crashtest 1") + if __name__ == "__main__": from editor_python_test_tools.utils import Report From 4dbce4275bd2b797c14414bb76ea577eae11d835 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Thu, 2 Dec 2021 17:46:07 -0800 Subject: [PATCH 078/128] Refactor the interface after some chatting with @amazon-employee-dm Signed-off-by: Nicholas Van Sickle --- .../AzCore/DOM/Backends/JSON/JsonBackend.h | 23 ++++++------ .../Backends/JSON/JsonSerializationUtils.h | 17 ++++----- .../AzCore/AzCore/DOM/DomBackend.cpp | 36 ++----------------- Code/Framework/AzCore/AzCore/DOM/DomBackend.h | 20 ++++------- .../AzCore/AzCore/azcore_files.cmake | 2 ++ .../AzCore/Tests/DOM/DomJsonBenchmarks.cpp | 5 +-- .../AzCore/Tests/DOM/DomJsonTests.cpp | 11 +++--- 7 files changed, 43 insertions(+), 71 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h index ace21d9be8..1c8f4eb607 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h @@ -8,31 +8,34 @@ #pragma once -#include #include +#include namespace AZ::Dom { //! A DOM backend for serializing and deserializing JSON <=> UTF-8 text //! \param ParseFlags Controls how deserialized JSON is parsed. //! \param WriteFormat Controls how serialized JSON is formatted. - template + template< + Json::ParseFlags ParseFlags = Json::ParseFlags::ParseComments, + Json::OutputFormatting WriteFormat = Json::OutputFormatting::PrettyPrintedJson> class JsonBackend final : public Backend { public: - Visitor::Result ReadFromStringInPlace(AZStd::string& buffer, Visitor& visitor) override + Visitor::Result ReadFromBuffer(const char* buffer, size_t size, AZ::Dom::Lifetime lifetime, Visitor& visitor) override + { + return Json::VisitSerializedJson({ buffer, size }, lifetime, visitor); + } + + Visitor::Result ReadFromBufferInPlace(char* buffer, Visitor& visitor) override { return Json::VisitSerializedJsonInPlace(buffer, visitor); } - Visitor::Result ReadFromString(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor) override + Visitor::Result WriteToStream(AZ::IO::GenericStream& stream, WriteCallback callback) override { - return Json::VisitSerializedJson(buffer, lifetime, visitor); - } - - AZStd::unique_ptr CreateStreamWriter(AZ::IO::GenericStream& stream) override - { - return Json::CreateJsonStreamWriter(stream, WriteFormat); + AZStd::unique_ptr visitor = Json::CreateJsonStreamWriter(stream, WriteFormat); + return callback(*visitor.get()); } }; } // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h index 88c6c42978..db43395475 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h @@ -115,17 +115,17 @@ namespace AZ::Dom::Json //! rapidjson stream wrapper for AZStd::string suitable for in-situ parsing //! Faster than rapidjson::MemoryStream for reading from AZStd::string / AZStd::string_view (because it requires a null terminator) //! \note This needs to be inlined for performance reasons. - struct AzStringStream + struct NullDelimitedStringStream { using Ch = char; //(buffer.data()); @@ -193,6 +193,7 @@ namespace AZ::Dom::Json //! \return The aggregate result specifying whether the visitor operations were successful. template Visitor::Result VisitSerializedJson(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor); + //! Reads serialized JSON from a string in-place and applies it to a visitor. //! \param buffer The UTF-8 serialized JSON to read. This buffer will be modified as part of the deserialization process to //! apply null terminators. @@ -201,7 +202,7 @@ namespace AZ::Dom::Json //! \param parseFlags (template) Settings for adjusting parser behavior. //! \return The aggregate result specifying whether the visitor operations were successful. template - Visitor::Result VisitSerializedJsonInPlace(AZStd::string& buffer, Visitor& visitor); + Visitor::Result VisitSerializedJsonInPlace(char* buffer, Visitor& visitor); //! Takes a visitor specified by a callback and produces a rapidjson::Document. //! \param writeCallback A callback specifying a visitor to accept to build the resulting document. @@ -231,7 +232,7 @@ namespace AZ::Dom::Json // If the string is null terminated, we can use the faster AzStringStream path - otherwise we fall back on rapidjson::MemoryStream if (buffer.data()[buffer.size()] == '\0') { - AzStringStream stream(buffer); + NullDelimitedStringStream stream(buffer); reader.Parse(parseFlags)>(stream, handler); } else @@ -243,10 +244,10 @@ namespace AZ::Dom::Json } template - Visitor::Result VisitSerializedJsonInPlace(AZStd::string& buffer, Visitor& visitor) + Visitor::Result VisitSerializedJsonInPlace(char* buffer, Visitor& visitor) { rapidjson::Reader reader; - AzStringStream stream(buffer); + NullDelimitedStringStream stream(buffer); RapidJsonReadHandler handler(&visitor, Lifetime::Persistent); reader.Parse(parseFlags) | rapidjson::kParseInsituFlag>(stream, handler); diff --git a/Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp b/Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp index 258975eff3..8ff0e8a0bb 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp @@ -8,40 +8,10 @@ #include -#include -#include -#include - namespace AZ::Dom { - Visitor::Result Backend::ReadFromStream(AZ::IO::GenericStream* stream, Visitor& visitor, size_t maxSize) + Visitor::Result Backend::ReadFromBufferInPlace(char* buffer, Visitor& visitor) { - size_t length = stream->GetLength(); - if (length > maxSize) - { - return AZ::Failure(VisitorError(VisitorErrorCode::InternalError, "Stream is too large.")); - } - AZStd::string buffer; - buffer.resize(length); - stream->Read(length, buffer.data()); - return ReadFromString(buffer, Lifetime::Temporary, visitor); + return ReadFromBuffer(buffer, strlen(buffer), AZ::Dom::Lifetime::Persistent, visitor); } - - Visitor::Result Backend::ReadFromStringInPlace(AZStd::string& buffer, Visitor& visitor) - { - return ReadFromString(buffer, Lifetime::Persistent, visitor); - } - - Visitor::Result Backend::WriteToStream(AZ::IO::GenericStream& stream, WriteCallback callback) - { - AZStd::unique_ptr writer = CreateStreamWriter(stream); - return callback(*writer.get()); - } - - Visitor::Result Backend::WriteToString(AZStd::string& buffer, WriteCallback callback) - { - AZ::IO::ByteContainerStream stream{&buffer}; - AZStd::unique_ptr writer = CreateStreamWriter(stream); - return callback(*writer.get()); - } -} +} // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/DomBackend.h b/Code/Framework/AzCore/AzCore/DOM/DomBackend.h index d1eee5d676..c70af72652 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomBackend.h +++ b/Code/Framework/AzCore/AzCore/DOM/DomBackend.h @@ -22,28 +22,22 @@ namespace AZ::Dom public: virtual ~Backend() = default; - //! Attempt to read this format from the given stream into the target Visitor. - //! The base implementation reads the stream into memory and calls ReadFromString. - virtual Visitor::Result ReadFromStream( - AZ::IO::GenericStream* stream, Visitor& visitor, size_t maxSize = AZStd::numeric_limits::max()); + //! Attempt to read this format from the given buffer into the target Visitor. + virtual Visitor::Result ReadFromBuffer( + const char* buffer, size_t size, AZ::Dom::Lifetime lifetime, Visitor& visitor) = 0; //! Attempt to read this format from a mutable string into the target Visitor. This enables some backends to //! parse without making additional string allocations. + //! This string must be null terminated. //! This string may be modified and read in place without being copied, so when calling this please ensure that: //! - The string won't be deallocated until the visitor no longer needs the values and //! - The string is safe to modify in place. - //! The base implementation simply calls ReadFromString. - virtual Visitor::Result ReadFromStringInPlace(AZStd::string& buffer, Visitor& visitor); - //! Attempt to read this format from an immutable buffer in memory into the target Visitor. - virtual Visitor::Result ReadFromString(AZStd::string_view buffer, Lifetime lifetime, Visitor& visitor) = 0; + //! The base implementation simply calls ReadFromBuffer. + virtual Visitor::Result ReadFromBufferInPlace(char* buffer, Visitor& visitor); - //! Acquire a visitor interface for writing to the target output file. - virtual AZStd::unique_ptr CreateStreamWriter(AZ::IO::GenericStream& stream) = 0; //! A callback that accepts a Visitor, making DOM calls to inform the serializer, and returns an //! aggregate error code to indicate whether or not the operation succeeded. using WriteCallback = AZStd::function; //! Attempt to write a value to a stream using a write callback. - Visitor::Result WriteToStream(AZ::IO::GenericStream& stream, WriteCallback callback); - //! Attempt to write a value to a string using a write callback. - Visitor::Result WriteToString(AZStd::string& buffer, WriteCallback callback); + virtual Visitor::Result WriteToStream(AZ::IO::GenericStream& stream, WriteCallback callback) = 0; }; } // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index 8557773c93..ef6c7434cc 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -127,6 +127,8 @@ set(FILES Debug/TraceReflection.h DOM/DomBackend.cpp DOM/DomBackend.h + DOM/DomUtils.cpp + DOM/DomUtils.h DOM/DomVisitor.cpp DOM/DomVisitor.h DOM/Backends/JSON/JsonBackend.h diff --git a/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp b/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp index ea72092001..0baa4aeb53 100644 --- a/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp +++ b/Code/Framework/AzCore/Tests/DOM/DomJsonBenchmarks.cpp @@ -8,6 +8,7 @@ #if defined(HAVE_BENCHMARK) +#include #include #include #include @@ -132,7 +133,7 @@ namespace Benchmark auto result = AZ::Dom::Json::WriteToRapidJsonDocument( [&](AZ::Dom::Visitor& visitor) { - return backend.ReadFromStringInPlace(payloadCopy, visitor); + return AZ::Dom::Utils::ReadFromStringInPlace(backend, payloadCopy, visitor); }); benchmark::DoNotOptimize(result.GetValue()); @@ -152,7 +153,7 @@ namespace Benchmark auto result = AZ::Dom::Json::WriteToRapidJsonDocument( [&](AZ::Dom::Visitor& visitor) { - return backend.ReadFromString(serializedPayload, AZ::Dom::Lifetime::Temporary, visitor); + return AZ::Dom::Utils::ReadFromString(backend, serializedPayload, AZ::Dom::Lifetime::Temporary, visitor); }); benchmark::DoNotOptimize(result.GetValue()); diff --git a/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp b/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp index cde5e2eb3f..a416bcf86b 100644 --- a/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp +++ b/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -70,7 +71,7 @@ namespace AZ::Dom::Tests { AZStd::string serializedDocument; JsonBackend backend; - auto result = backend.WriteToString(serializedDocument, visitDocumentFn); + auto result = Dom::Utils::WriteToString(backend, serializedDocument, visitDocumentFn); EXPECT_TRUE(result.IsSuccess()); EXPECT_EQ(canonicalSerializedDocument, serializedDocument); } @@ -81,7 +82,7 @@ namespace AZ::Dom::Tests [&canonicalSerializedDocument](AZ::Dom::Visitor& visitor) { JsonBackend backend; - return backend.ReadFromString(canonicalSerializedDocument, AZ::Dom::Lifetime::Temporary, visitor); + return Dom::Utils::ReadFromString(backend, canonicalSerializedDocument, Dom::Lifetime::Persistent, visitor); }); EXPECT_TRUE(result.IsSuccess()); EXPECT_EQ(AZ::JsonSerialization::Compare(*m_document, result.GetValue()), JsonSerializerCompareResult::Equal); @@ -91,11 +92,11 @@ namespace AZ::Dom::Tests { AZStd::string serializedDocument; JsonBackend backend; - auto result = backend.WriteToString( - serializedDocument, + auto result = Dom::Utils::WriteToString( + backend, serializedDocument, [&backend, &canonicalSerializedDocument](AZ::Dom::Visitor& visitor) { - return backend.ReadFromString(canonicalSerializedDocument, AZ::Dom::Lifetime::Temporary, visitor); + return Dom::Utils::ReadFromString(backend, canonicalSerializedDocument, Dom::Lifetime::Persistent, visitor); }); EXPECT_TRUE(result.IsSuccess()); EXPECT_EQ(canonicalSerializedDocument, serializedDocument); From 59a22165847e58925541654cad308fc420ffdf19 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Thu, 2 Dec 2021 17:49:29 -0800 Subject: [PATCH 079/128] Fix a build issue Signed-off-by: Nicholas Van Sickle --- Code/Framework/AzCore/AzCore/DOM/DomVisitor.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h index c0da56036e..26fb2aa063 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h +++ b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h @@ -233,9 +233,9 @@ namespace AZ::Dom //! Helper method, constructs a failure \ref Result with the specified code and supplemental info specified by a format string //! and its arguments. template - static Result VisitorFailure(VisitorErrorCode code, TArgs... formatArgs) + static Result VisitorFailure(VisitorErrorCode code, const char* formatString, TArgs... formatArgs) { - return AZ::Failure(VisitorError(code, AZStd::string::format(formatArgs...))); + return AZ::Failure(VisitorError(code, AZStd::string::format(formatString, formatArgs...))); } //! Helper method, constructs a success \ref Result. From db798bdbc78a9ef16b4afe25471b0e4cb6c76a81 Mon Sep 17 00:00:00 2001 From: carlitosan <82187351+carlitosan@users.noreply.github.com> Date: Thu, 2 Dec 2021 18:18:06 -0800 Subject: [PATCH 080/128] fix linux build error, change translation system errors to warnings Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com> --- Gems/GraphCanvas/Code/Source/Translation/TranslationAsset.cpp | 2 +- .../Code/Source/Translation/TranslationSerializer.cpp | 2 +- Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Gems/GraphCanvas/Code/Source/Translation/TranslationAsset.cpp b/Gems/GraphCanvas/Code/Source/Translation/TranslationAsset.cpp index a461866c46..3b026b4579 100644 --- a/Gems/GraphCanvas/Code/Source/Translation/TranslationAsset.cpp +++ b/Gems/GraphCanvas/Code/Source/Translation/TranslationAsset.cpp @@ -195,7 +195,7 @@ namespace GraphCanvas } else { - AZ_Error("TranslationAsset", false, "Serialization of the TranslationFormat failed for: %s", asset.GetHint().c_str()); + AZ_Warning("TranslationAsset", false, "Serialization of the TranslationFormat failed for: %s", asset.GetHint().c_str()); } } } diff --git a/Gems/GraphCanvas/Code/Source/Translation/TranslationSerializer.cpp b/Gems/GraphCanvas/Code/Source/Translation/TranslationSerializer.cpp index 80e488f3dc..5f8d8bc3f1 100644 --- a/Gems/GraphCanvas/Code/Source/Translation/TranslationSerializer.cpp +++ b/Gems/GraphCanvas/Code/Source/Translation/TranslationSerializer.cpp @@ -146,7 +146,7 @@ namespace GraphCanvas AZStd::string baseKey = contextStr; if (keyStr.empty()) { - AZ_Error("TranslationDatabase", false, "Every entry in the Translation data must have a key: %s", baseKey.c_str()); + AZ_Warning("TranslationDatabase", false, "Every entry in the Translation data must have a key: %s", baseKey.c_str()); return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported, "Every entry in the Translation data must have a key"); } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index 06877a5659..146c563ea7 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -256,7 +256,6 @@ namespace ScriptCanvasEditor EditorSettings::EditorWorkspace::WorkspaceAssetSaveData assetSaveData; assetSaveData.m_assetId = sourceId; - ScriptCanvas::ScriptCanvasId scriptCanvasId = m_mainWindow->FindScriptCanvasIdByAssetId(assetId); activeAssets.push_back(assetSaveData); } } From f7547a4cbdb821519b92f576e8b1cef130075780 Mon Sep 17 00:00:00 2001 From: carlitosan <82187351+carlitosan@users.noreply.github.com> Date: Thu, 2 Dec 2021 19:55:27 -0800 Subject: [PATCH 081/128] fixed string_view printf error caught by linux compiler Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com> --- Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index 146c563ea7..7a0834bb26 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -1571,7 +1571,7 @@ namespace ScriptCanvasEditor if (outTabIndex == -1) { - return AZ::Failure(AZStd::string::format("Script Canvas Asset %.*s is not open in a tab", assetPath.data())); + return AZ::Failure(AZStd::string::format("Script Canvas Asset %.*s is not open in a tab", assetPath.size(), assetPath.data())); } SetActiveAsset(handle); From c218fd9b770b9ac59b70861d1b23e35bc142dcb4 Mon Sep 17 00:00:00 2001 From: carlitosan <82187351+carlitosan@users.noreply.github.com> Date: Thu, 2 Dec 2021 20:17:36 -0800 Subject: [PATCH 082/128] fixed another string_view printf error caught by linux compiler Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com> --- Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index 7a0834bb26..fa13681879 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -1571,7 +1571,8 @@ namespace ScriptCanvasEditor if (outTabIndex == -1) { - return AZ::Failure(AZStd::string::format("Script Canvas Asset %.*s is not open in a tab", assetPath.size(), assetPath.data())); + return AZ::Failure(AZStd::string::format("Script Canvas Asset %.*s is not open in a tab" + , static_cast(assetPath.size()), assetPath.data())); } SetActiveAsset(handle); From 701fd7f0d0c64e17194e54fd3fdcc502974960e6 Mon Sep 17 00:00:00 2001 From: Olex Lozitskiy <5432499+AMZN-Olex@users.noreply.github.com> Date: Fri, 3 Dec 2021 13:46:28 -0500 Subject: [PATCH 083/128] Multiplayer benchmark cleanup Signed-off-by: Olex Lozitskiy <5432499+AMZN-Olex@users.noreply.github.com> --- .../Code/Tests/CommonBenchmarkSetup.h | 50 ++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h b/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h index c352dc2bbf..380a344f6d 100644 --- a/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h +++ b/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h @@ -198,7 +198,7 @@ namespace Multiplayer } }; - class BenchmarkNetworkEntityManager : public MockNetworkEntityManager + class BenchmarkNetworkEntityManager : public Multiplayer::INetworkEntityManager { public: BenchmarkNetworkEntityManager() : m_authorityTracker(*this) {} @@ -235,6 +235,54 @@ namespace Multiplayer return InvalidNetEntityId; } + void Initialize([[maybe_unused]] const HostId& hostId, [[maybe_unused]] AZStd::unique_ptr entityDomain) override {} + bool IsInitialized() const override { return false; } + IEntityDomain* GetEntityDomain() const override { return nullptr; } + EntityList CreateEntitiesImmediate( + [[maybe_unused]] const PrefabEntityId& prefabEntryId, + [[maybe_unused]] NetEntityRole netEntityRole, + [[maybe_unused]] const AZ::Transform& transform, + [[maybe_unused]] AutoActivate autoActivate) override { + return {}; + } + EntityList CreateEntitiesImmediate( + [[maybe_unused]] const PrefabEntityId& prefabEntryId, + [[maybe_unused]] NetEntityId netEntityId, + [[maybe_unused]] NetEntityRole netEntityRole, + [[maybe_unused]] AutoActivate autoActivate, + [[maybe_unused]] const AZ::Transform& transform) override { + return {}; + } + [[nodiscard]] AZStd::unique_ptr RequestNetSpawnableInstantiation( + [[maybe_unused]] const AZ::Data::Asset& netSpawnable, + [[maybe_unused]] const AZ::Transform& transform) override { + return {}; + } + void SetupNetEntity([[maybe_unused]] AZ::Entity* netEntity, [[maybe_unused]] PrefabEntityId prefabEntityId, [[maybe_unused]] NetEntityRole netEntityRole) override {} + uint32_t GetEntityCount() const override { + return 0; + } + void MarkForRemoval([[maybe_unused]] const ConstNetworkEntityHandle& entityHandle) override {} + bool IsMarkedForRemoval([[maybe_unused]] const ConstNetworkEntityHandle& entityHandle) const override { + return false; + } + void ClearEntityFromRemovalList([[maybe_unused]] const ConstNetworkEntityHandle& entityHandle) override {} + void ClearAllEntities() override {} + void AddEntityMarkedDirtyHandler([[maybe_unused]] AZ::Event<>::Handler& entityMarkedDirtyHandle) override {} + void AddEntityNotifyChangesHandler([[maybe_unused]] AZ::Event<>::Handler& entityNotifyChangesHandle) override {} + void AddEntityExitDomainHandler([[maybe_unused]] EntityExitDomainEvent::Handler& entityExitDomainHandler) override {} + void AddControllersActivatedHandler([[maybe_unused]] ControllersActivatedEvent::Handler& controllersActivatedHandler) override {} + void AddControllersDeactivatedHandler([[maybe_unused]] ControllersDeactivatedEvent::Handler& controllersDeactivatedHandler) override {} + void NotifyEntitiesDirtied() override {} + void NotifyEntitiesChanged() override {} + void NotifyControllersActivated([[maybe_unused]] const ConstNetworkEntityHandle& entityHandle, [[maybe_unused]] EntityIsMigrating entityIsMigrating) override {} + void NotifyControllersDeactivated([[maybe_unused]] const ConstNetworkEntityHandle& entityHandle, [[maybe_unused]] EntityIsMigrating entityIsMigrating) override {} + void HandleLocalRpcMessage([[maybe_unused]] NetworkEntityRpcMessage& message) override {} + void HandleEntitiesExitDomain([[maybe_unused]] const NetEntityIdSet& entitiesNotInDomain) override {} + void ForceAssumeAuthority([[maybe_unused]] const ConstNetworkEntityHandle& entityHandle) override {} + void SetMigrateTimeoutTimeMs([[maybe_unused]] AZ::TimeMs timeoutTimeMs) override {} + void DebugDraw() const override {} + NetworkEntityTracker m_tracker; NetworkEntityAuthorityTracker m_authorityTracker; MultiplayerComponentRegistry m_multiplayerComponentRegistry; From 7657caf6d2ca0c23e3b75b041a18a1180e9cdce3 Mon Sep 17 00:00:00 2001 From: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> Date: Fri, 3 Dec 2021 13:15:17 -0600 Subject: [PATCH 084/128] Added helpers to resource locators for finding the platform specific crash logs Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> --- .../Gem/PythonTests/automatedtesting_shared/base.py | 5 +---- .../ly_test_tools/_internal/managers/platforms/linux.py | 6 ++++++ .../ly_test_tools/_internal/managers/platforms/mac.py | 6 ++++++ .../ly_test_tools/_internal/managers/platforms/windows.py | 6 ++++++ 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/base.py b/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/base.py index c0c0c4a48a..88188aa6c0 100755 --- a/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/base.py +++ b/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/base.py @@ -128,10 +128,7 @@ class TestAutomationBase: errors.append(TestRunError("FAILED TEST", error_str)) if return_code and return_code != TestAutomationBase.TEST_FAIL_RETCODE: # Crashed crash_info = "-- No crash log available --" - if sys.platform.startswith('linux'): - crash_log = os.path.join(workspace.paths.project_log(), 'crash.log') - else: - crash_log = os.path.join(workspace.paths.project_log(), 'error.log') + crash_log = workspace.paths.crash_log() try: waiter.wait_for(lambda: os.path.exists(crash_log), timeout=TestAutomationBase.WAIT_FOR_CRASH_LOG) diff --git a/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py b/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py index 151a4a3e2b..ec88dce7c3 100644 --- a/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py +++ b/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py @@ -53,6 +53,12 @@ class _LinuxResourceManager(AbstractResourceLocator): """ return os.path.join(self.project_log(), "Editor.log") + def crash_log(self): + """ + Return path to the project's crash log dir using the builds project and platform + :return: path to Crash.log + """ + return os.path.join(self.project_log(), "crash.log") class LinuxWorkspaceManager(AbstractWorkspaceManager): """ diff --git a/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/mac.py b/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/mac.py index 4a187b188c..673bfa5050 100755 --- a/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/mac.py +++ b/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/mac.py @@ -62,6 +62,12 @@ class _MacResourceLocator(AbstractResourceLocator): """ return os.path.join(self.project_log(), "Editor.log") + def crash_log(self): + """ + Return path to the project's crash log dir using the builds project and platform + :return: path to crash.log + """ + return os.path.join(self.project_log(), "crash.log") class MacWorkspaceManager(AbstractWorkspaceManager): """ diff --git a/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/windows.py b/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/windows.py index 29289166d4..b31cc6bb5c 100755 --- a/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/windows.py +++ b/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/windows.py @@ -68,6 +68,12 @@ class _WindowsResourceLocator(AbstractResourceLocator): """ return os.path.join(self.project_log(), "Editor.log") + def crash_log(self): + """ + Return path to the project's crash log dir using the builds project and platform + :return: path to Error.log + """ + return os.path.join(self.project_log(), "error.log") class WindowsWorkspaceManager(AbstractWorkspaceManager): """ From 016e261f368121f445faf99ee5ad3b53b4ff3668 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Fri, 3 Dec 2021 11:25:15 -0800 Subject: [PATCH 085/128] Add DomUtils Signed-off-by: Nicholas Van Sickle --- Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp | 30 +++++++++++++++++++ Code/Framework/AzCore/AzCore/DOM/DomUtils.h | 19 ++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp create mode 100644 Code/Framework/AzCore/AzCore/DOM/DomUtils.h diff --git a/Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp b/Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp new file mode 100644 index 0000000000..3c5d4eb668 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp @@ -0,0 +1,30 @@ +/* + * 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 + +namespace AZ::Dom::Utils +{ + Visitor::Result ReadFromString(Backend& backend, AZStd::string_view string, AZ::Dom::Lifetime lifetime, Visitor& visitor) + { + return backend.ReadFromBuffer(string.data(), string.length(), lifetime, visitor); + } + + Visitor::Result ReadFromStringInPlace(Backend& backend, AZStd::string& string, Visitor& visitor) + { + return backend.ReadFromBufferInPlace(string.data(), visitor); + } + + Visitor::Result WriteToString(Backend& backend, AZStd::string& buffer, Backend::WriteCallback writeCallback) + { + AZ::IO::ByteContainerStream stream{ &buffer }; + return backend.WriteToStream(stream, writeCallback); + } +} diff --git a/Code/Framework/AzCore/AzCore/DOM/DomUtils.h b/Code/Framework/AzCore/AzCore/DOM/DomUtils.h new file mode 100644 index 0000000000..cd64d2e107 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/DomUtils.h @@ -0,0 +1,19 @@ +/* + * 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 + +namespace AZ::Dom::Utils +{ + Visitor::Result ReadFromString(Backend& backend, AZStd::string_view string, AZ::Dom::Lifetime lifetime, Visitor& visitor); + Visitor::Result ReadFromStringInPlace(Backend& backend, AZStd::string& string, Visitor& visitor); + + Visitor::Result WriteToString(Backend& backend, AZStd::string& buffer, Backend::WriteCallback writeCallback); +} // namespace AZ::Dom::Utils From 954642c1ce0ea6f8bec96cebcc7947ca41e1b6f8 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Fri, 3 Dec 2021 13:40:07 -0600 Subject: [PATCH 086/128] Updated Entity Inspector to changed behavior when an Entity has been marked as read-only. Signed-off-by: Chris Galvan --- .../PropertyEditor/EntityPropertyEditor.cpp | 39 ++++++++++++++++++- .../PropertyEditor/EntityPropertyEditor.hxx | 4 ++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp index fa419d5f14..69368814f7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp @@ -45,6 +45,7 @@ AZ_POP_DISABLE_WARNING #include #include #include +#include #include #include #include @@ -497,6 +498,9 @@ namespace AzToolsFramework m_prefabPublicInterface = AZ::Interface::Get(); AZ_Assert(m_prefabPublicInterface != nullptr, "EntityPropertyEditor requires a PrefabPublicInterface instance on Initialize."); + m_readOnlyEntityPublicInterface = AZ::Interface::Get(); + AZ_Assert(m_readOnlyEntityPublicInterface != nullptr, "EntityPropertyEditor requires a ReadOnlyEntityPublicInterface instance on Initialize."); + setObjectName("EntityPropertyEditor"); setAcceptDrops(true); @@ -973,7 +977,7 @@ namespace AzToolsFramework m_gui->m_entityDetailsLabel->setVisible(false); // If we're in edit mode, make the name field editable. - m_gui->m_entityNameEditor->setReadOnly(!m_gui->m_componentListContents->isEnabled()); + m_gui->m_entityNameEditor->setReadOnly(!m_gui->m_componentListContents->isEnabled() || m_entityIsReadOnly); // get the name of the entity. auto entity = GetSelectedEntityById(entityId); @@ -1062,6 +1066,12 @@ namespace AzToolsFramework bool EntityPropertyEditor::CanAddComponentsToSelection(const SelectionEntityTypeInfo& selectionEntityTypeInfo) const { + if (m_entityIsReadOnly) + { + // Can't add components if there is a read only entity in the selection + return false; + } + if (selectionEntityTypeInfo == SelectionEntityTypeInfo::Mixed || selectionEntityTypeInfo == SelectionEntityTypeInfo::None) { @@ -1126,6 +1136,17 @@ namespace AzToolsFramework m_selectedEntityIds.clear(); GetSelectedEntities(m_selectedEntityIds); + // Check if any of the selected entities are marked as read only + m_entityIsReadOnly = false; + for (const auto& entityId : m_selectedEntityIds) + { + if (m_readOnlyEntityPublicInterface->IsReadOnly(entityId)) + { + m_entityIsReadOnly = true; + break; + } + } + SourceControlFileInfo scFileInfo; ToolsApplicationRequests::Bus::BroadcastResult(scFileInfo, &ToolsApplicationRequests::GetSceneSourceControlInfo); @@ -1681,6 +1702,12 @@ namespace AzToolsFramework componentEditor->UpdateExpandability(); componentEditor->InvalidateAll(!componentInFilter ? m_filterString.c_str() : nullptr); + // If we are in read only mode, then show the components as disabled + if (m_entityIsReadOnly) + { + componentEditor->mockDisabledState(true); + } + if (!componentEditor->GetPropertyEditor()->HasFilteredOutNodes() || componentEditor->GetPropertyEditor()->HasVisibleNodes()) { for (AZ::Component* componentInstance : componentInstances) @@ -3077,6 +3104,7 @@ namespace AzToolsFramework } } + m_gui->m_statusComboBox->setDisabled(m_entityIsReadOnly); m_gui->m_statusComboBox->setVisible(!m_isSystemEntityEditor && !m_isLevelEntityEditor); m_gui->m_statusComboBox->style()->unpolish(m_gui->m_statusComboBox); m_gui->m_statusComboBox->style()->polish(m_gui->m_statusComboBox); @@ -3304,7 +3332,8 @@ namespace AzToolsFramework const auto& componentsToEdit = GetSelectedComponents(); const bool hasComponents = !m_selectedEntityIds.empty() && !componentsToEdit.empty(); - const bool allowRemove = hasComponents && AreComponentsRemovable(componentsToEdit); + // Don't allow components to be removed/cut/enabled/disabled if read only + const bool allowRemove = hasComponents && AreComponentsRemovable(componentsToEdit) && !m_entityIsReadOnly; const bool allowCopy = hasComponents && AreComponentsCopyable(componentsToEdit); m_actionToDeleteComponents->setEnabled(allowRemove); @@ -3366,6 +3395,12 @@ namespace AzToolsFramework return false; } + if (m_entityIsReadOnly) + { + // Can't paste components if there is a read only entity in the selection + return false; + } + // Grab component data from clipboard, if exists const QMimeData* mimeData = ComponentMimeData::GetComponentMimeDataFromClipboard(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx index 8dd0ffc4ee..3d62d6fe10 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx @@ -62,6 +62,7 @@ namespace AzToolsFramework class ComponentPaletteWidget; class ComponentModeCollectionInterface; struct SourceControlFileInfo; + class ReadOnlyEntityPublicInterface; namespace AssetBrowser { @@ -623,6 +624,9 @@ namespace AzToolsFramework Prefab::PrefabPublicInterface* m_prefabPublicInterface = nullptr; bool m_prefabsAreEnabled = false; + ReadOnlyEntityPublicInterface* m_readOnlyEntityPublicInterface = nullptr; + bool m_entityIsReadOnly = false; + // Reordering row widgets within the RPE. static constexpr float MoveFadeSeconds = 0.5f; From da06c84d5ed952d8e8e5429c00620e9cd2a09546 Mon Sep 17 00:00:00 2001 From: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> Date: Fri, 3 Dec 2021 13:46:42 -0600 Subject: [PATCH 087/128] Adding crash_log() to base resource locator class Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> --- .../_internal/managers/abstract_resource_locator.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py b/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py index d11980658d..4514e5d812 100755 --- a/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py +++ b/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py @@ -384,3 +384,14 @@ class AbstractResourceLocator(object): "editor_log() is not implemented on the base AbstractResourceLocator() class. " "It must be defined by the inheriting class - " "i.e. _WindowsResourceLocator(AbstractResourceLocator).editor_log()") + + @abstractmethod + def crash_log(self): + """ + Return path to the project's crash log dir using the builds project and platform + :return: path to error.log/crash.log + """ + raise NotImplementedError( + "crash_log() is not implemented on the base AbstractResourceLocator() class. " + "It must be defined by the inheriting class - " + "i.e. _WindowsResourceLocator(AbstractResourceLocator).crash_log()") From be607521e75e91b3b5291635c107574c8e24af8d Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Fri, 3 Dec 2021 14:15:41 -0600 Subject: [PATCH 088/128] Optimizations to graph canvas translation json serializer A handful of places in tight loops were looking up JSON and map entries multiple times in a row Moving and reusing string variables in tight loops Deferring string creation, copying, assignment until needed Signed-off-by: Guthrie Adams --- .../Translation/TranslationSerializer.cpp | 71 ++++++++----------- 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/Gems/GraphCanvas/Code/Source/Translation/TranslationSerializer.cpp b/Gems/GraphCanvas/Code/Source/Translation/TranslationSerializer.cpp index 80e488f3dc..754267b27d 100644 --- a/Gems/GraphCanvas/Code/Source/Translation/TranslationSerializer.cpp +++ b/Gems/GraphCanvas/Code/Source/Translation/TranslationSerializer.cpp @@ -15,39 +15,39 @@ namespace GraphCanvas void AddEntryToDatabase(const AZStd::string& baseKey, const AZStd::string& name, const rapidjson::Value& it, TranslationFormat* translationFormat) { - AZStd::string finalKey = baseKey; if (it.IsString()) { - if (translationFormat->m_database.find(finalKey) == translationFormat->m_database.end()) + auto translationDbItr = translationFormat->m_database.find(baseKey); + if (translationDbItr == translationFormat->m_database.end()) { - translationFormat->m_database[finalKey] = it.GetString(); + translationFormat->m_database[baseKey] = it.GetString(); } else { - AZStd::string existingValue = translationFormat->m_database[finalKey.c_str()]; + const AZStd::string& existingValue = translationDbItr->second; // There is a name collision - AZStd::string error = AZStd::string::format("Unable to store key: %s with value: %s because that key already exists with value: %s (proposed: %s)", finalKey.c_str(), it.GetString(), existingValue.c_str(), it.GetString()); + const AZStd::string error = AZStd::string::format("Unable to store key: %s with value: %s because that key already exists with value: %s (proposed: %s)", baseKey.c_str(), it.GetString(), existingValue.c_str(), it.GetString()); AZ_Error("TranslationSerializer", false, error.c_str()); } } else if (it.IsObject()) { + AZStd::string finalKey = baseKey; if (!name.empty()) { finalKey.append("."); finalKey.append(name); } - AZStd::string itemKey = finalKey; + AZStd::string itemKey; for (auto objIt = it.MemberBegin(); objIt != it.MemberEnd(); ++objIt) { + itemKey = finalKey; itemKey.append("."); itemKey.append(objIt->name.GetString()); AddEntryToDatabase(itemKey, name, objIt->value, translationFormat); - - itemKey = finalKey; } } @@ -60,18 +60,21 @@ namespace GraphCanvas key.append(name); } - AZStd::string itemKey = key; + AZStd::string itemKey; const rapidjson::Value& array = it; for (rapidjson::SizeType i = 0; i < array.Size(); ++i) { + itemKey = key; + // if there is a "base" member within the object, then use it, otherwise use the index - if (array[i].IsObject()) + const auto& element = array[i]; + if (element.IsObject()) { - if (array[i].HasMember(Schema::Field::key)) + rapidjson::Value::ConstMemberIterator innerKeyItr = element.FindMember(Schema::Field::key); + if (innerKeyItr != element.MemberEnd()) { - AZStd::string innerKey = array[i].FindMember(Schema::Field::key)->value.GetString(); - itemKey.append(AZStd::string::format(".%s", innerKey.c_str())); + itemKey.append(AZStd::string::format(".%s", innerKeyItr->value.GetString())); } else { @@ -79,9 +82,7 @@ namespace GraphCanvas } } - AddEntryToDatabase(itemKey, "", array[i], translationFormat); - - itemKey = key; + AddEntryToDatabase(itemKey, "", element, translationFormat); } } } @@ -114,42 +115,32 @@ namespace GraphCanvas { const rapidjson::Value::ConstMemberIterator entries = inputValue.FindMember(Schema::Field::entries); + AZStd::string keyStr; + AZStd::string contextStr; + AZStd::string variantStr; + AZStd::string baseKey; + rapidjson::SizeType entryCount = entries->value.Size(); for (rapidjson::SizeType i = 0; i < entryCount; ++i) { const rapidjson::Value& entry = entries->value[i]; - AZStd::string keyStr; - rapidjson::Value::ConstMemberIterator keyValue; - if (entry.HasMember(Schema::Field::key)) - { - keyValue = entry.FindMember(Schema::Field::key); - keyStr = keyValue->value.GetString(); - } + rapidjson::Value::ConstMemberIterator keyItr = entry.FindMember(Schema::Field::key); + keyStr = keyItr != entry.MemberEnd() ? keyItr->value.GetString() : ""; - AZStd::string contextStr; - rapidjson::Value::ConstMemberIterator contextValue; - if (entry.HasMember(Schema::Field::context)) - { - contextValue = entry.FindMember(Schema::Field::context); - contextStr = contextValue->value.GetString(); - } + rapidjson::Value::ConstMemberIterator contextItr = entry.FindMember(Schema::Field::context); + contextStr = contextItr != entry.MemberEnd() ? contextItr->value.GetString() : ""; - AZStd::string variantStr; - rapidjson::Value::ConstMemberIterator variantValue; - if (entry.HasMember(Schema::Field::variant)) - { - variantValue = entry.FindMember(Schema::Field::variant); - variantStr = variantValue->value.GetString(); - } + rapidjson::Value::ConstMemberIterator variantItr = entry.FindMember(Schema::Field::variant); + variantStr = variantItr != entry.MemberEnd() ? variantItr->value.GetString() : ""; - AZStd::string baseKey = contextStr; if (keyStr.empty()) { - AZ_Error("TranslationDatabase", false, "Every entry in the Translation data must have a key: %s", baseKey.c_str()); + AZ_Error("TranslationDatabase", false, "Every entry in the Translation data must have a key: %s", contextStr.c_str()); return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported, "Every entry in the Translation data must have a key"); } + baseKey = contextStr; if (!baseKey.empty()) { baseKey.append("."); @@ -167,7 +158,7 @@ namespace GraphCanvas for (auto it = entry.MemberBegin(); it != entry.MemberEnd(); ++it) { // Skip the fixed elements - if (it == keyValue || it == contextValue || it == variantValue) + if (it == keyItr || it == contextItr || it == variantItr) { continue; } From f2f7dad97219c63dfedfd86504c030c90b571a57 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Fri, 3 Dec 2021 12:26:19 -0800 Subject: [PATCH 089/128] Remove FormatVisitorErrorMessage Signed-off-by: Nicholas Van Sickle --- .../DOM/Backends/JSON/JsonSerializationUtils.cpp | 14 +++++++++----- Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp | 5 +++++ Code/Framework/AzCore/AzCore/DOM/DomVisitor.h | 10 ++-------- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp index 66851f1a40..4adf0bdd21 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp @@ -103,8 +103,10 @@ namespace AZ::Dom::Json if (m_entryStack.front().m_entryCount != attributeCount) { return VisitorFailure( - VisitorErrorCode::InternalError, "EndObject: Expected %lu attributes but received %lu attributes instead", attributeCount, - m_entryStack.front().m_entryCount); + VisitorErrorCode::InternalError, + AZStd::string::format( + "EndObject: Expected %lu attributes but received %lu attributes instead", attributeCount, + m_entryStack.front().m_entryCount)); } m_entryStack.pop_front(); @@ -155,8 +157,9 @@ namespace AZ::Dom::Json if (m_entryStack.front().m_entryCount != elementCount) { return VisitorFailure( - VisitorErrorCode::InternalError, "EndArray: Expected %lu elements but received %lu elements instead", elementCount, - m_entryStack.front().m_entryCount); + VisitorErrorCode::InternalError, + AZStd::string::format( + "EndArray: Expected %lu elements but received %lu elements instead", elementCount, m_entryStack.front().m_entryCount)); } m_entryStack.pop_front(); @@ -507,7 +510,8 @@ namespace AZ::Dom::Json for (auto it = currentValue.MemberEnd(); it != currentValue.MemberBegin(); --it) { auto entry = (it - 1); - const AZStd::string_view key(entry->name.GetString(), aznumeric_cast(entry->name.GetStringLength())); + const AZStd::string_view key( + entry->name.GetString(), aznumeric_cast(entry->name.GetStringLength())); entryStack.push(&entry->value); entryStack.push(key); } diff --git a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp index d5190cbbac..ad314da385 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp @@ -60,6 +60,11 @@ namespace AZ::Dom return AZ::Failure(VisitorError(code)); } + Visitor::Result Visitor::VisitorFailure(VisitorErrorCode code, AZStd::string additionalInfo) + { + return AZ::Failure(VisitorError(code, AZStd::move(additionalInfo))); + } + Visitor::Result Visitor::VisitorFailure(VisitorError error) { return AZ::Failure(error); diff --git a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h index 26fb2aa063..bbe78131c3 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h +++ b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h @@ -227,17 +227,11 @@ namespace AZ::Dom //! Helper method, constructs a failure \ref Result with the specified code. static Result VisitorFailure(VisitorErrorCode code); + //! Helper method, constructs a failure \ref Result with the specified code and supplemental info. + static Result VisitorFailure(VisitorErrorCode code, AZStd::string additionalInfo); //! Helper method, constructs a failure \ref Result with the specified error. static Result VisitorFailure(VisitorError error); - //! Helper method, constructs a failure \ref Result with the specified code and supplemental info specified by a format string - //! and its arguments. - template - static Result VisitorFailure(VisitorErrorCode code, const char* formatString, TArgs... formatArgs) - { - return AZ::Failure(VisitorError(code, AZStd::string::format(formatString, formatArgs...))); - } - //! Helper method, constructs a success \ref Result. static Result VisitorSuccess(); }; From 037a93406ac3d3cbd04960b7fa43b1bdb364fa5f Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Fri, 3 Dec 2021 12:40:52 -0800 Subject: [PATCH 090/128] Fix a couple format string issues Signed-off-by: Nicholas Van Sickle --- .../AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp index 4adf0bdd21..e1db5be29e 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp @@ -105,7 +105,7 @@ namespace AZ::Dom::Json return VisitorFailure( VisitorErrorCode::InternalError, AZStd::string::format( - "EndObject: Expected %lu attributes but received %lu attributes instead", attributeCount, + "EndObject: Expected %llu attributes but received %llu attributes instead", attributeCount, m_entryStack.front().m_entryCount)); } @@ -159,7 +159,7 @@ namespace AZ::Dom::Json return VisitorFailure( VisitorErrorCode::InternalError, AZStd::string::format( - "EndArray: Expected %lu elements but received %lu elements instead", elementCount, m_entryStack.front().m_entryCount)); + "EndArray: Expected %llu elements but received %llu elements instead", elementCount, m_entryStack.front().m_entryCount)); } m_entryStack.pop_front(); From d56cfa40dd81e3b15c4d6cb8dfa7aa7ff56e8656 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 2 Dec 2021 16:29:55 -0600 Subject: [PATCH 091/128] Changing trace logger to clear log file when opened Also switched the log message sink from a vector to a list so the entire container does not have to be rebuilt every time and entry is added. Signed-off-by: Guthrie Adams --- .../AzToolsFramework/AzToolsFramework/Logger/TraceLogger.cpp | 4 ++-- .../AzToolsFramework/AzToolsFramework/Logger/TraceLogger.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Logger/TraceLogger.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Logger/TraceLogger.cpp index ce73826388..386f5ea179 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Logger/TraceLogger.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Logger/TraceLogger.cpp @@ -73,7 +73,7 @@ namespace AzToolsFramework AZStd::string logPath; StringFunc::Path::Join(logDirectory.c_str(), logFileName.c_str(), logPath); - m_logFile.reset(aznew LogFile(logPath.c_str())); + m_logFile.reset(aznew LogFile(logPath.c_str(), true)); if (m_logFile) { m_logFile->SetMachineReadable(false); @@ -81,7 +81,7 @@ namespace AzToolsFramework { m_logFile->AppendLog(LogFile::SEV_NORMAL, message.window.c_str(), message.message.c_str()); } - m_startupLogSink = {}; + m_startupLogSink.clear(); m_logFile->FlushLog(); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Logger/TraceLogger.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Logger/TraceLogger.h index 10708e3239..dafd3becc8 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Logger/TraceLogger.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Logger/TraceLogger.h @@ -55,7 +55,8 @@ namespace AzToolsFramework AZStd::string window; AZStd::string message; }; - AZStd::vector m_startupLogSink; + + AZStd::list m_startupLogSink; AZStd::unordered_set m_windowFilters; AZStd::unordered_set m_messageFilters; AZStd::unique_ptr m_logFile; From af75b3a52aa290595768b27d586608f7b913f0ef Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Fri, 3 Dec 2021 15:25:54 -0600 Subject: [PATCH 092/128] Made clearing the log file optional and renamed the function Signed-off-by: Guthrie Adams --- .../AzToolsFramework/AzToolsFramework/Logger/TraceLogger.cpp | 4 ++-- .../AzToolsFramework/AzToolsFramework/Logger/TraceLogger.h | 2 +- .../Code/Source/Application/AtomToolsApplication.cpp | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Logger/TraceLogger.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Logger/TraceLogger.cpp index 386f5ea179..8c7150f027 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Logger/TraceLogger.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Logger/TraceLogger.cpp @@ -50,7 +50,7 @@ namespace AzToolsFramework return false; } - void TraceLogger::PrepareLogFile(const AZStd::string& logFileName) + void TraceLogger::OpenLogFile(const AZStd::string& logFileName, bool clearLogFile) { using namespace AzFramework; @@ -73,7 +73,7 @@ namespace AzToolsFramework AZStd::string logPath; StringFunc::Path::Join(logDirectory.c_str(), logFileName.c_str(), logPath); - m_logFile.reset(aznew LogFile(logPath.c_str(), true)); + m_logFile.reset(aznew LogFile(logPath.c_str(), clearLogFile)); if (m_logFile) { m_logFile->SetMachineReadable(false); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Logger/TraceLogger.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Logger/TraceLogger.h index dafd3becc8..639674f69e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Logger/TraceLogger.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Logger/TraceLogger.h @@ -23,7 +23,7 @@ namespace AzToolsFramework ~TraceLogger(); //! Open log file and dump log sink into it - void PrepareLogFile(const AZStd::string& logFileName); + void OpenLogFile(const AZStd::string& logFileName, bool clearLogFile); //! Add filter to ignore messages for windows with matching names void AddWindowFilter(const AZStd::string& filter); diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp index 0f21dcb70e..ec365d7a6a 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp @@ -175,7 +175,8 @@ namespace AtomToolsFramework Base::StartCommon(systemEntity); - m_traceLogger.PrepareLogFile(GetBuildTargetName() + ".log"); + const bool clearLogFile = GetSettingOrDefault("/O3DE/AtomToolsFramework/Application/ClearLogOnStart", false); + m_traceLogger.OpenLogFile(GetBuildTargetName() + ".log", clearLogFile); AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler::BusConnect(); AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotificationBus::Broadcast( From 8165f54c05ee4babe5b2585e5ef6e02fb1d9cb1f Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Fri, 3 Dec 2021 13:52:16 -0800 Subject: [PATCH 093/128] Use temporary lifetimes for test Signed-off-by: Nicholas Van Sickle --- Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp b/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp index a416bcf86b..b408cd2466 100644 --- a/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp +++ b/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp @@ -57,7 +57,7 @@ namespace AZ::Dom::Tests auto visitDocumentFn = [this](AZ::Dom::Visitor& visitor) { - return Json::VisitRapidJsonValue(*m_document, visitor, Lifetime::Persistent); + return Json::VisitRapidJsonValue(*m_document, visitor, Lifetime::Temporary); }; // Document -> Document @@ -82,7 +82,7 @@ namespace AZ::Dom::Tests [&canonicalSerializedDocument](AZ::Dom::Visitor& visitor) { JsonBackend backend; - return Dom::Utils::ReadFromString(backend, canonicalSerializedDocument, Dom::Lifetime::Persistent, visitor); + return Dom::Utils::ReadFromString(backend, canonicalSerializedDocument, Lifetime::Temporary, visitor); }); EXPECT_TRUE(result.IsSuccess()); EXPECT_EQ(AZ::JsonSerialization::Compare(*m_document, result.GetValue()), JsonSerializerCompareResult::Equal); @@ -96,7 +96,7 @@ namespace AZ::Dom::Tests backend, serializedDocument, [&backend, &canonicalSerializedDocument](AZ::Dom::Visitor& visitor) { - return Dom::Utils::ReadFromString(backend, canonicalSerializedDocument, Dom::Lifetime::Persistent, visitor); + return Dom::Utils::ReadFromString(backend, canonicalSerializedDocument, Lifetime::Temporary, visitor); }); EXPECT_TRUE(result.IsSuccess()); EXPECT_EQ(canonicalSerializedDocument, serializedDocument); From 273fb87eebbd5bae61dd67c1670d7b0c8e61f8fa Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Fri, 3 Dec 2021 16:21:31 -0600 Subject: [PATCH 094/128] Renamed variable to be more descriptive. Signed-off-by: Chris Galvan --- .../UI/PropertyEditor/EntityPropertyEditor.cpp | 16 ++++++++-------- .../UI/PropertyEditor/EntityPropertyEditor.hxx | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp index 69368814f7..f69aa84709 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp @@ -977,7 +977,7 @@ namespace AzToolsFramework m_gui->m_entityDetailsLabel->setVisible(false); // If we're in edit mode, make the name field editable. - m_gui->m_entityNameEditor->setReadOnly(!m_gui->m_componentListContents->isEnabled() || m_entityIsReadOnly); + m_gui->m_entityNameEditor->setReadOnly(!m_gui->m_componentListContents->isEnabled() || m_selectionContainsReadOnlyEntity); // get the name of the entity. auto entity = GetSelectedEntityById(entityId); @@ -1066,7 +1066,7 @@ namespace AzToolsFramework bool EntityPropertyEditor::CanAddComponentsToSelection(const SelectionEntityTypeInfo& selectionEntityTypeInfo) const { - if (m_entityIsReadOnly) + if (m_selectionContainsReadOnlyEntity) { // Can't add components if there is a read only entity in the selection return false; @@ -1137,12 +1137,12 @@ namespace AzToolsFramework GetSelectedEntities(m_selectedEntityIds); // Check if any of the selected entities are marked as read only - m_entityIsReadOnly = false; + m_selectionContainsReadOnlyEntity = false; for (const auto& entityId : m_selectedEntityIds) { if (m_readOnlyEntityPublicInterface->IsReadOnly(entityId)) { - m_entityIsReadOnly = true; + m_selectionContainsReadOnlyEntity = true; break; } } @@ -1703,7 +1703,7 @@ namespace AzToolsFramework componentEditor->InvalidateAll(!componentInFilter ? m_filterString.c_str() : nullptr); // If we are in read only mode, then show the components as disabled - if (m_entityIsReadOnly) + if (m_selectionContainsReadOnlyEntity) { componentEditor->mockDisabledState(true); } @@ -3104,7 +3104,7 @@ namespace AzToolsFramework } } - m_gui->m_statusComboBox->setDisabled(m_entityIsReadOnly); + m_gui->m_statusComboBox->setDisabled(m_selectionContainsReadOnlyEntity); m_gui->m_statusComboBox->setVisible(!m_isSystemEntityEditor && !m_isLevelEntityEditor); m_gui->m_statusComboBox->style()->unpolish(m_gui->m_statusComboBox); m_gui->m_statusComboBox->style()->polish(m_gui->m_statusComboBox); @@ -3333,7 +3333,7 @@ namespace AzToolsFramework const bool hasComponents = !m_selectedEntityIds.empty() && !componentsToEdit.empty(); // Don't allow components to be removed/cut/enabled/disabled if read only - const bool allowRemove = hasComponents && AreComponentsRemovable(componentsToEdit) && !m_entityIsReadOnly; + const bool allowRemove = hasComponents && AreComponentsRemovable(componentsToEdit) && !m_selectionContainsReadOnlyEntity; const bool allowCopy = hasComponents && AreComponentsCopyable(componentsToEdit); m_actionToDeleteComponents->setEnabled(allowRemove); @@ -3395,7 +3395,7 @@ namespace AzToolsFramework return false; } - if (m_entityIsReadOnly) + if (m_selectionContainsReadOnlyEntity) { // Can't paste components if there is a read only entity in the selection return false; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx index 3d62d6fe10..bf8cac8968 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx @@ -625,7 +625,7 @@ namespace AzToolsFramework bool m_prefabsAreEnabled = false; ReadOnlyEntityPublicInterface* m_readOnlyEntityPublicInterface = nullptr; - bool m_entityIsReadOnly = false; + bool m_selectionContainsReadOnlyEntity = false; // Reordering row widgets within the RPE. static constexpr float MoveFadeSeconds = 0.5f; From b470f917caae150589aa22b9eecc48e21c3bfcd9 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Fri, 3 Dec 2021 16:37:35 -0600 Subject: [PATCH 095/128] Listen to read-only entity state changes so we can refresh if the read-only state changes on one of our selected entities. Signed-off-by: Chris Galvan --- .../UI/PropertyEditor/EntityPropertyEditor.cpp | 15 +++++++++++++++ .../UI/PropertyEditor/EntityPropertyEditor.hxx | 5 +++++ 2 files changed, 20 insertions(+) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp index f69aa84709..0b9420a629 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp @@ -569,6 +569,12 @@ namespace AzToolsFramework AZ::EntitySystemBus::Handler::BusConnect(); EntityPropertyEditorRequestBus::Handler::BusConnect(); EditorWindowUIRequestBus::Handler::BusConnect(); + + AzFramework::EntityContextId editorEntityContextId = AzFramework::EntityContextId::CreateNull(); + EditorEntityContextRequestBus::BroadcastResult( + editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId); + ReadOnlyEntityPublicNotificationBus::Handler::BusConnect(editorEntityContextId); + m_spacer = nullptr; m_emptyIcon = QIcon(); @@ -618,6 +624,7 @@ namespace AzToolsFramework { qApp->removeEventFilter(this); + ReadOnlyEntityPublicNotificationBus::Handler::BusDisconnect(); EditorWindowUIRequestBus::Handler::BusDisconnect(); EntityPropertyEditorRequestBus::Handler::BusDisconnect(); ToolsApplicationEvents::Bus::Handler::BusDisconnect(); @@ -5762,6 +5769,14 @@ namespace AzToolsFramework SaveComponentEditorState(); } + void EntityPropertyEditor::OnReadOnlyEntityStatusChanged(const AZ::EntityId& entityId, [[maybe_unused]] bool readOnly) + { + if (IsEntitySelected(entityId)) + { + UpdateContents(); + } + } + void EntityPropertyEditor::OnEditorModeActivated( [[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx index bf8cac8968..254b70996b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -117,6 +118,7 @@ namespace AzToolsFramework , public AZ::EntitySystemBus::Handler , public AZ::TickBus::Handler , private EditorWindowUIRequestBus::Handler + , private ReadOnlyEntityPublicNotificationBus::Handler { Q_OBJECT; public: @@ -254,6 +256,9 @@ namespace AzToolsFramework // EditorWindowRequestBus overrides void SetEditorUiEnabled(bool enable) override; + // ReadOnlyEntityPublicNotificationBus overrides ... + void OnReadOnlyEntityStatusChanged(const AZ::EntityId& entityId, bool readOnly) override; + bool IsEntitySelected(const AZ::EntityId& id) const; bool IsSingleEntitySelected(const AZ::EntityId& id) const; From 87fb6be96413c533f53b4e3529c840045ba3907e Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Fri, 3 Dec 2021 15:38:29 -0800 Subject: [PATCH 096/128] Fixes to Procedural Prefab instantiation - ensure the container of the procprefab has the correct editor components, and remove limitation to instantiating at the root. (#6147) Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../Prefab/PrefabSystemScriptingHandler.cpp | 7 ++++++- .../UI/Prefab/PrefabIntegrationManager.cpp | 8 ++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp index 9d0d0547ae..93dfca3f13 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp @@ -8,10 +8,12 @@ #include #include +#include #include +#include +#include #include #include -#include #include #include @@ -72,6 +74,9 @@ namespace AzToolsFramework::Prefab entities, commonRoot, &topLevelEntities); auto containerEntity = AZStd::make_unique(); + containerEntity->CreateComponent(); + containerEntity->CreateComponent(); + containerEntity->CreateComponent(); containerEntity->CreateComponent(); for (AZ::Entity* entity : topLevelEntities) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index aa6d82e634..bc6700aca5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -565,9 +565,7 @@ namespace AzToolsFramework EditorRequestBus::BroadcastResult(position, &EditorRequestBus::Events::GetWorldPositionAtViewportCenter); } - // Instantiating from context menu always puts the instance at the root level auto createPrefabOutcome = s_prefabPublicInterface->InstantiatePrefab(prefabFilePath, parentId, position); - if (!createPrefabOutcome.IsSuccess()) { WarnUserOfError("Prefab Instantiation Error",createPrefabOutcome.GetError()); @@ -594,15 +592,13 @@ namespace AzToolsFramework } else { - // otherwise return since it needs to be inside an authored prefab - return; + EditorRequestBus::BroadcastResult(position, &EditorRequestBus::Events::GetWorldPositionAtViewportCenter); } - // Instantiating from context menu always puts the instance at the root level auto createPrefabOutcome = s_prefabPublicInterface->InstantiatePrefab(prefabAssetPath, parentId, position); if (!createPrefabOutcome.IsSuccess()) { - WarnUserOfError("Prefab Instantiation Error", createPrefabOutcome.GetError()); + WarnUserOfError("Procedural Prefab Instantiation Error", createPrefabOutcome.GetError()); } } } From fc8fd89ff9703c100db7572dc0c84adfa7c4db6c Mon Sep 17 00:00:00 2001 From: gusmccallum Date: Fri, 3 Dec 2021 21:46:16 -0500 Subject: [PATCH 097/128] Updated android launcher to remove confusing branding Signed-off-by: gusmccallum --- Code/LauncherUnified/Platform/Android/Launcher_Android.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/LauncherUnified/Platform/Android/Launcher_Android.cpp b/Code/LauncherUnified/Platform/Android/Launcher_Android.cpp index de548a49d7..0890b5a193 100644 --- a/Code/LauncherUnified/Platform/Android/Launcher_Android.cpp +++ b/Code/LauncherUnified/Platform/Android/Launcher_Android.cpp @@ -299,7 +299,7 @@ void android_main(android_app* appState) { // Adding a start up banner so you can see when the game is starting up in amongst the logcat spam LOGI("****************************************************************"); - LOGI("* Amazon Lumberyard - Launching Game... *"); + LOGI("* Launching Game... *"); LOGI("****************************************************************"); // setup the system command handler which are guaranteed to be called on the same From 09c9548ba4049fb182be8c95a32a0b5ad8a89ec4 Mon Sep 17 00:00:00 2001 From: amzn-sean <75276488+amzn-sean@users.noreply.github.com> Date: Mon, 6 Dec 2021 11:23:52 +0000 Subject: [PATCH 098/128] Automated testing create_backup and restore_backup respects file flags. (#6062) * Automated testing create_backup and restore_backup respects file flags. Example: If the file that is to be backed-up is readonly, when restored that file will be readonly. If the file that is to be backed-up is not readonly, when restored that file will be not readonly. Fixes an issue that would mark physics setreg files to readonly after running AutomatedTesting when restoring from the backup. * update LyTestTools tests that use create/restore backup to expect copy2 instead of copy Signed-off-by: amzn-sean <75276488+amzn-sean@users.noreply.github.com> --- .../Physics/utils/FileManagement.py | 55 ++++++++----------- .../ly_test_tools/environment/file_system.py | 40 +++++++++----- .../tests/unit/test_file_system.py | 14 ++--- 3 files changed, 56 insertions(+), 53 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Physics/utils/FileManagement.py b/AutomatedTesting/Gem/PythonTests/Physics/utils/FileManagement.py index 017bb672a4..03287d0542 100644 --- a/AutomatedTesting/Gem/PythonTests/Physics/utils/FileManagement.py +++ b/AutomatedTesting/Gem/PythonTests/Physics/utils/FileManagement.py @@ -98,38 +98,32 @@ class FileManagement: """ file_map = FileManagement._load_file_map() backup_path = FileManagement.backup_folder_path - backup_file_name = "{}.bak".format(file_name) - backup_file = os.path.join(backup_path, backup_file_name) # If backup directory DNE, make one if not os.path.exists(backup_path): os.mkdir(backup_path) - # If "traditional" backup file exists, delete it (myFile.txt.bak) - if os.path.exists(backup_file): - fs.delete([backup_file], True, False) - # Find my next storage name (myFile_1.txt.bak) - backup_storage_file_name = FileManagement._next_available_name(backup_file_name, file_map) - if backup_storage_file_name is None: + + # Find my next storage name (myFile_1.txt) + backup_file_name = FileManagement._next_available_name(file_name, file_map) + if backup_file_name is None: # If _next_available_name returns None, we have backed up MAX_BACKUPS of files name [file_name] raise Exception( "FileManagement class ran out of backups per name. Max: {}".format(FileManagement.MAX_BACKUPS) ) - backup_storage_file = os.path.join(backup_path, backup_storage_file_name) + + # If this backup file already exists, delete it. + backup_storage_file = "{}.bak".format(os.path.normpath(os.path.join(backup_path, backup_file_name))) if os.path.exists(backup_storage_file): - # This file should not exists, but if it does it's about to get clobbered! - fs.unlock_file(backup_storage_file) - # Create "traditional" backup file (myFile.txt.bak) - fs.create_backup(os.path.join(file_path, file_name), backup_path) - # Copy "traditional" backup file into storage backup (myFile_1.txt.bak) - FileManagement._copy_file(backup_file_name, backup_path, backup_storage_file_name, backup_path) - fs.lock_file(backup_storage_file) - # Delete "traditional" back up file - fs.unlock_file(backup_file) - fs.delete([backup_file], True, False) + fs.delete([backup_storage_file], True, False) + + # Create backup file (myFile_1.txt.bak) + original_file = os.path.normpath(os.path.join(file_path, file_name)) + fs.create_backup(original_file, backup_path, backup_file_name) + # Update file map with new file - file_map[os.path.join(file_path, file_name)] = backup_storage_file_name + file_map[original_file] = backup_file_name FileManagement._save_file_map(file_map) # Unlock original file to get it ready to be edited by the test - fs.unlock_file(os.path.join(file_path, file_name)) + fs.unlock_file(original_file) @staticmethod def _restore_file(file_name, file_path): @@ -143,20 +137,15 @@ class FileManagement: """ file_map = FileManagement._load_file_map() backup_path = FileManagement.backup_folder_path - src_file = os.path.join(file_path, file_name) + src_file = os.path.normpath(os.path.join(file_path, file_name)) if src_file in file_map: - backup_file = os.path.join(backup_path, file_map[src_file]) - if os.path.exists(backup_file): - fs.unlock_file(backup_file) - fs.unlock_file(src_file) - # Make temporary copy of backed up file to restore from - temp_file = "{}.bak".format(file_name) - FileManagement._copy_file(file_map[src_file], backup_path, temp_file, backup_path) - fs.restore_backup(src_file, backup_path) - fs.lock_file(src_file) - # Delete backup file - fs.delete([os.path.join(backup_path, temp_file)], True, False) + backup_file_name = file_map[src_file] + backup_file = "{}.bak".format(os.path.join(backup_path, backup_file_name)) + + fs.unlock_file(src_file) + if fs.restore_backup(src_file, backup_path, backup_file_name): fs.delete([backup_file], True, False) + # Remove from file map del file_map[src_file] FileManagement._save_file_map(file_map) diff --git a/Tools/LyTestTools/ly_test_tools/environment/file_system.py b/Tools/LyTestTools/ly_test_tools/environment/file_system.py index c67ecc5b23..e8fb1d13cf 100755 --- a/Tools/LyTestTools/ly_test_tools/environment/file_system.py +++ b/Tools/LyTestTools/ly_test_tools/environment/file_system.py @@ -293,61 +293,75 @@ def delete(file_list, del_files, del_dirs): return True -def create_backup(source, backup_dir): +def create_backup(source, backup_dir, backup_name=None): """ Creates a backup of a single source file by creating a copy of it with the same name + '.bak' in backup_dir e.g.: foo.txt is stored as backup_dir/foo.txt.bak + If backup_name is provided, it will create a copy of the source file named "backup_name + .bak" instead. :param source: Full path to file to backup :param backup_dir: Path to the directory to store backup. + :param backup_name: [Optional] Name of the backed up file to use instead or the source name. """ if not backup_dir or not os.path.isdir(backup_dir): logger.error(f'Cannot create backup due to invalid backup directory {backup_dir}') - return + return False if not os.path.exists(source): logger.warning(f'Source file {source} does not exist, aborting backup creation.') - return + return False - source_filename = os.path.basename(source) - dest = os.path.join(backup_dir, f'{source_filename}.bak') + dest = None + if backup_name is None: + source_filename = os.path.basename(source) + dest = os.path.join(backup_dir, f'{source_filename}.bak') + else: + dest = os.path.join(backup_dir, f'{backup_name}.bak') logger.info(f'Saving backup of {source} in {dest}') if os.path.exists(dest): logger.warning(f'Backup file already exists at {dest}, it will be overwritten.') try: - shutil.copy(source, dest) + shutil.copy2(source, dest) except Exception: # intentionally broad logger.warning('Could not create backup, exception occurred while copying.', exc_info=True) + return False + return True -def restore_backup(original_file, backup_dir): +def restore_backup(original_file, backup_dir, backup_name=None): """ Restores a backup file to its original location. Works with a single file only. :param original_file: Full path to file to overwrite. :param backup_dir: Path to the directory storing the backup. + :param backup_name: [Optional] Provide if the backup file name is different from source. eg backup file = myFile_1.txt.bak original file = myfile.txt """ if not backup_dir or not os.path.isdir(backup_dir): logger.error(f'Cannot restore backup due to invalid or nonexistent directory {backup_dir}.') - return + return False - source_filename = os.path.basename(original_file) - backup = os.path.join(backup_dir, f'{source_filename}.bak') + backup = None + if backup_name is None: + source_filename = os.path.basename(original_file) + backup = os.path.join(backup_dir, f'{source_filename}.bak') + else: + backup = os.path.join(backup_dir, f'{backup_name}.bak') if not os.path.exists(backup): logger.warning(f'Backup file {backup} does not exist, aborting backup restoration.') - return + return False logger.info(f'Restoring backup of {original_file} from {backup}') try: - shutil.copy(backup, original_file) + shutil.copy2(backup, original_file) except Exception: # intentionally broad logger.warning('Could not restore backup, exception occurred while copying.', exc_info=True) - + return False + return True def delete_oldest(path_glob, keep_num, del_files=True, del_dirs=False): """ Delete oldest builds, keeping a specific number """ diff --git a/Tools/LyTestTools/tests/unit/test_file_system.py b/Tools/LyTestTools/tests/unit/test_file_system.py index 2ddd3f8934..2fdcf8131e 100755 --- a/Tools/LyTestTools/tests/unit/test_file_system.py +++ b/Tools/LyTestTools/tests/unit/test_file_system.py @@ -751,7 +751,7 @@ class TestFileBackup(unittest.TestCase): self._dummy_file = 'dummy.txt' self._dummy_backup_file = os.path.join(self._dummy_dir, '{}.bak'.format(self._dummy_file)) - @mock.patch('shutil.copy') + @mock.patch('shutil.copy2') @mock.patch('os.path.exists') @mock.patch('os.path.isdir') def test_BackupSettings_SourceExists_BackupCreated(self, mock_path_isdir, mock_backup_exists, mock_copy): @@ -763,7 +763,7 @@ class TestFileBackup(unittest.TestCase): mock_copy.assert_called_with(self._dummy_file, self._dummy_backup_file) @mock.patch('ly_test_tools.environment.file_system.logger.warning') - @mock.patch('shutil.copy') + @mock.patch('shutil.copy2') @mock.patch('os.path.exists') @mock.patch('os.path.isdir') def test_BackupSettings_BackupExists_WarningLogged(self, mock_path_isdir, mock_backup_exists, mock_copy, mock_logger_warning): @@ -776,7 +776,7 @@ class TestFileBackup(unittest.TestCase): mock_logger_warning.assert_called_once() @mock.patch('ly_test_tools.environment.file_system.logger.warning') - @mock.patch('shutil.copy') + @mock.patch('shutil.copy2') @mock.patch('os.path.exists') @mock.patch('os.path.isdir') def test_BackupSettings_SourceNotExists_WarningLogged(self, mock_path_isdir, mock_backup_exists, mock_copy, mock_logger_warning): @@ -789,7 +789,7 @@ class TestFileBackup(unittest.TestCase): mock_logger_warning.assert_called_once() @mock.patch('ly_test_tools.environment.file_system.logger.warning') - @mock.patch('shutil.copy') + @mock.patch('shutil.copy2') @mock.patch('os.path.exists') @mock.patch('os.path.isdir') def test_BackupSettings_CannotCopy_WarningLogged(self, mock_path_isdir, mock_backup_exists, mock_copy, mock_logger_warning): @@ -821,7 +821,7 @@ class TestFileBackupRestore(unittest.TestCase): self._dummy_file = 'dummy.txt' self._dummy_backup_file = os.path.join(self._dummy_dir, '{}.bak'.format(self._dummy_file)) - @mock.patch('shutil.copy') + @mock.patch('shutil.copy2') @mock.patch('os.path.exists') @mock.patch('os.path.isdir') def test_RestoreSettings_BackupRestore_Success(self, mock_path_isdir, mock_exists, mock_copy): @@ -832,7 +832,7 @@ class TestFileBackupRestore(unittest.TestCase): mock_copy.assert_called_with(self._dummy_backup_file, self._dummy_file) @mock.patch('ly_test_tools.environment.file_system.logger.warning') - @mock.patch('shutil.copy') + @mock.patch('shutil.copy2') @mock.patch('os.path.exists') @mock.patch('os.path.isdir') def test_RestoreSettings_CannotCopy_WarningLogged(self, mock_path_isdir, mock_exists, mock_copy, mock_logger_warning): @@ -846,7 +846,7 @@ class TestFileBackupRestore(unittest.TestCase): mock_logger_warning.assert_called_once() @mock.patch('ly_test_tools.environment.file_system.logger.warning') - @mock.patch('shutil.copy') + @mock.patch('shutil.copy2') @mock.patch('os.path.exists') @mock.patch('os.path.isdir') def test_RestoreSettings_BackupNotExists_WarningLogged(self, mock_path_isdir, mock_exists, mock_copy, mock_logger_warning): From dc8f9dc233b3819a5c4e6c2e0de273e635213c60 Mon Sep 17 00:00:00 2001 From: moraaar Date: Mon, 6 Dec 2021 13:26:23 +0000 Subject: [PATCH 099/128] Add additional check to check material library is loaded when trying to retrieve names (#6165) * Add additional check to ensure material library is loaded when trying to retrieve names. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Mark physmaterial assets as critical Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Co-authored-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Signed-off-by: moraaar moraaar@amazon.com --- Gems/PhysX/Code/Source/Pipeline/MeshGroup.cpp | 3 ++- Registry/AssetProcessorPlatformConfig.setreg | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Gems/PhysX/Code/Source/Pipeline/MeshGroup.cpp b/Gems/PhysX/Code/Source/Pipeline/MeshGroup.cpp index d0ff4008b2..24bfeef1be 100644 --- a/Gems/PhysX/Code/Source/Pipeline/MeshGroup.cpp +++ b/Gems/PhysX/Code/Source/Pipeline/MeshGroup.cpp @@ -864,7 +864,8 @@ namespace PhysX { if (auto* physicsSystem = AZ::Interface::Get()) { - if (const auto* physicsConfiguration = physicsSystem->GetConfiguration()) + if (const auto* physicsConfiguration = physicsSystem->GetConfiguration(); + physicsConfiguration && physicsConfiguration->m_materialLibraryAsset) { const auto& materials = physicsConfiguration->m_materialLibraryAsset->GetMaterialsData(); diff --git a/Registry/AssetProcessorPlatformConfig.setreg b/Registry/AssetProcessorPlatformConfig.setreg index ddc465c201..7c52feb10b 100644 --- a/Registry/AssetProcessorPlatformConfig.setreg +++ b/Registry/AssetProcessorPlatformConfig.setreg @@ -442,6 +442,7 @@ "RC physmaterial": { "glob": "*.physmaterial", "params": "copy", + "critical": "true", "productAssetType": "{9E366D8C-33BB-4825-9A1F-FA3ADBE11D0F}" }, "RC ocm": { From c5615f812ccc9d235747a1c5ba396ac2e9a23690 Mon Sep 17 00:00:00 2001 From: Mikhail Naumov <82239319+AMZN-mnaumov@users.noreply.github.com> Date: Mon, 6 Dec 2021 08:46:47 -0600 Subject: [PATCH 100/128] Fixing pivot offset when performing undo on Transform component (#6150) * Fixing undo offest on transform component Signed-off-by: Mikhail Naumov * Fixining possible issue with firing an unnecessary OnTransformChanged event when entity is manually disabled/enabled Signed-off-by: Mikhail Naumov * Adding better comments Signed-off-by: Mikhail Naumov * Unit tests Signed-off-by: Mikhail Naumov * Cherrupicking changes Signed-off-by: Mikhail Naumov --- .../ToolsComponents/TransformComponent.cpp | 20 ++--- .../ToolsComponents/TransformComponent.h | 3 + .../Tests/Prefab/PrefabTestFixture.cpp | 81 ++++++++++++++++++- .../Tests/Prefab/PrefabTestFixture.h | 15 +++- .../Tests/TransformComponent.cpp | 66 +++++++++++++++ .../Tests/UI/EntityOutlinerTests.cpp | 75 ++--------------- 6 files changed, 181 insertions(+), 79 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp index 7ab7dfdfe4..1f056729d7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp @@ -860,18 +860,20 @@ namespace AzToolsFramework return; } - bool isDuringUndoRedo = false; - EBUS_EVENT_RESULT(isDuringUndoRedo, AzToolsFramework::ToolsApplicationRequests::Bus, IsDuringUndoRedo); - if (!isDuringUndoRedo) + bool suppressTransformChangedEvent = m_suppressTransformChangedEvent; + // temporarily disable calling OnTransformChanged, because CheckApplyCachedWorldTransform is not guaranteed + // to call it when m_cachedWorldTransform is identity. We send it manually later. + m_suppressTransformChangedEvent = false; + // When parent comes online, compute local TM from world TM. + CheckApplyCachedWorldTransform(parentTransform->GetWorldTM()); + if (!m_initialized) { - // When parent comes online, compute local TM from world TM. - CheckApplyCachedWorldTransform(parentTransform->GetWorldTM()); - } - else - { - // During undo operations, just apply our local TM. + m_initialized = true; + // If this is the first time this entity is being activated, manually compute OnTransformChanged + // this can occur when either the entity first created or undo/redo command is performed OnTransformChanged(AZ::Transform::Identity(), parentTransform->GetWorldTM()); } + m_suppressTransformChangedEvent = suppressTransformChangedEvent; auto& parentChildIds = GetParentTransformComponent()->m_childrenEntityIds; if (parentChildIds.end() == AZStd::find(parentChildIds.begin(), parentChildIds.end(), GetEntityId())) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.h index 931d3b48d6..08d1392d74 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.h @@ -242,6 +242,9 @@ namespace AzToolsFramework // element is used rather than a data element. bool m_addNonUniformScaleButton = false; + // Used to check whether entity was just created vs manually reactivated. Set true after OnEntityActivated is called the first time. + bool m_initialized = false; + // Deprecated AZ::InterpolationMode m_interpolatePosition; AZ::InterpolationMode m_interpolateRotation; diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestFixture.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestFixture.cpp index ed30de09c4..3c58f9df4e 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestFixture.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestFixture.cpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include @@ -50,6 +52,15 @@ namespace UnitTest GetApplication()->RegisterComponentDescriptor(PrefabTestComponent::CreateDescriptor()); GetApplication()->RegisterComponentDescriptor(PrefabTestComponentWithUnReflectedTypeMember::CreateDescriptor()); + + AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult( + m_undoStack, &AzToolsFramework::ToolsApplicationRequestBus::Events::GetUndoStack); + AZ_Assert(m_undoStack, "Failed to look up undo stack from tools application"); + } + + void PrefabTestFixture::TearDownEditorFixtureImpl() + { + m_undoStack = nullptr; } AZStd::unique_ptr PrefabTestFixture::CreateTestApplication() @@ -57,7 +68,20 @@ namespace UnitTest return AZStd::make_unique("PrefabTestApplication"); } - AZ::Entity* PrefabTestFixture::CreateEntity(const char* entityName, const bool shouldActivate) + void PrefabTestFixture::CreateRootPrefab() + { + auto entityOwnershipService = AZ::Interface::Get(); + ASSERT_TRUE(entityOwnershipService != nullptr); + entityOwnershipService->CreateNewLevelPrefab("UnitTestRoot.prefab", ""); + auto rootEntityReference = entityOwnershipService->GetRootPrefabInstance()->get().GetContainerEntity(); + ASSERT_TRUE(rootEntityReference.has_value()); + auto& rootEntity = rootEntityReference->get(); + rootEntity.Deactivate(); + rootEntity.CreateComponent(); + rootEntity.Activate(); + } + + AZ::Entity* PrefabTestFixture::CreateEntity(AZStd::string entityName, const bool shouldActivate) { // Circumvent the EntityContext system and generate a new entity with a transformcomponent AZ::Entity* newEntity = aznew AZ::Entity(entityName); @@ -71,8 +95,43 @@ namespace UnitTest return newEntity; } + AZ::EntityId PrefabTestFixture::CreateEntityUnderRootPrefab(AZStd::string name, AZ::EntityId parentId) + { + auto createResult = m_prefabPublicInterface->CreateEntity(parentId, AZ::Vector3()); + AZ_Assert(createResult.IsSuccess(), "Failed to create entity: %s", createResult.GetError().c_str()); + AZ::EntityId entityId = createResult.GetValue(); + + AZ::Entity* entity = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId); + + entity->Deactivate(); + + entity->SetName(name); + + // Normally, in invalid parent ID should automatically parent us to the root prefab, but currently in the unit test + // environment entities aren't created with a default transform component, so CreateEntity won't correctly parent. + // We get the actual target parent ID here, then create our missing transform component. + if (!parentId.IsValid()) + { + auto prefabEditorEntityOwnershipInterface = AZ::Interface::Get(); + parentId = prefabEditorEntityOwnershipInterface->GetRootPrefabInstance()->get().GetContainerEntityId(); + } + + auto transform = aznew AzToolsFramework::Components::TransformComponent; + transform->SetParent(parentId); + entity->AddComponent(transform); + + entity->Activate(); + + // Update our undo cache entry to include the rename / reparent as one atomic operation. + m_prefabPublicInterface->GenerateUndoNodesForEntityChangeAndUpdateCache(entityId, m_undoStack->GetTop()); + m_prefabSystemComponent->OnSystemTick(); + + return entityId; + } + void PrefabTestFixture::CompareInstances(const AzToolsFramework::Prefab::Instance& instanceA, - const AzToolsFramework::Prefab::Instance& instanceB, bool shouldCompareLinkIds, bool shouldCompareContainerEntities) + const AzToolsFramework::Prefab::Instance& instanceB, bool shouldCompareLinkIds, bool shouldCompareContainerEntities) { AzToolsFramework::Prefab::TemplateId templateAId = instanceA.GetTemplateId(); AzToolsFramework::Prefab::TemplateId templateBId = instanceB.GetTemplateId(); @@ -125,4 +184,22 @@ namespace UnitTest EXPECT_EQ(entityInInstance->GetState(), AZ::Entity::State::Active); } } + + void PrefabTestFixture::ProcessDeferredUpdates() + { + // Force a prefab propagation for updates that are deferred to the next tick. + m_prefabSystemComponent->OnSystemTick(); + } + + void PrefabTestFixture::Undo() + { + m_undoStack->Undo(); + ProcessDeferredUpdates(); + } + + void PrefabTestFixture::Redo() + { + m_undoStack->Redo(); + ProcessDeferredUpdates(); + } } diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestFixture.h b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestFixture.h index 0a78ded1a6..84409397dc 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestFixture.h +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabTestFixture.h @@ -49,10 +49,13 @@ namespace UnitTest inline static const char* CarPrefabMockFilePath = "SomePathToCar"; void SetUpEditorFixtureImpl() override; + void TearDownEditorFixtureImpl() override; AZStd::unique_ptr CreateTestApplication() override; - AZ::Entity* CreateEntity(const char* entityName, const bool shouldActivate = true); + void CreateRootPrefab(); + AZ::Entity* CreateEntity(AZStd::string entityName, const bool shouldActivate = true); + AZ::EntityId CreateEntityUnderRootPrefab(AZStd::string name, AZ::EntityId parentId = AZ::EntityId()); void CompareInstances(const Instance& instanceA, const Instance& instanceB, bool shouldCompareLinkIds = true, bool shouldCompareContainerEntities = true); @@ -62,10 +65,20 @@ namespace UnitTest //! Validates that all entities within a prefab instance are in 'Active' state. void ValidateInstanceEntitiesActive(Instance& instance); + // Kicks off any updates scheduled for the next tick + virtual void ProcessDeferredUpdates(); + + // Performs an undo operation and ensures the tick-scheduled updates happen + void Undo(); + + // Performs a redo operation and ensures the tick-scheduled updates happen + void Redo(); + PrefabSystemComponent* m_prefabSystemComponent = nullptr; PrefabLoaderInterface* m_prefabLoaderInterface = nullptr; PrefabPublicInterface* m_prefabPublicInterface = nullptr; InstanceUpdateExecutorInterface* m_instanceUpdateExecutorInterface = nullptr; InstanceToTemplateInterface* m_instanceToTemplateInterface = nullptr; + AzToolsFramework::UndoSystem::UndoStack* m_undoStack = nullptr; }; } diff --git a/Code/Framework/AzToolsFramework/Tests/TransformComponent.cpp b/Code/Framework/AzToolsFramework/Tests/TransformComponent.cpp index 4fbebc8526..3849ed23c9 100644 --- a/Code/Framework/AzToolsFramework/Tests/TransformComponent.cpp +++ b/Code/Framework/AzToolsFramework/Tests/TransformComponent.cpp @@ -18,7 +18,10 @@ #include #include +#include #include +#include +#include #include @@ -1063,4 +1066,67 @@ R"DELIMITER( } } } + + // Fixture provides a root prefab with Transform component and listens for TransformNotificationBus. + class TransformComponentActivationTest + : public PrefabTestFixture + , public TransformNotificationBus::Handler + { + protected: + void SetUpEditorFixtureImpl() override + { + PrefabTestFixture::SetUpEditorFixtureImpl(); + + CreateRootPrefab(); + } + + void TearDownEditorFixtureImpl() override + { + BusDisconnect(); + + PrefabTestFixture::TearDownEditorFixtureImpl(); + } + + void OnTransformChanged(const Transform& /*local*/, const Transform& /*world*/) override + { + m_transformUpdated = true; + } + + void MoveEntity(AZ::EntityId entityId) + { + AzToolsFramework::ScopedUndoBatch undoBatch("Move Entity"); + TransformBus::Event(entityId, &TransformInterface::SetWorldTranslation, Vector3(1.f, 0.f, 0.f)); + } + + bool m_transformUpdated = false; + }; + + TEST_F(TransformComponentActivationTest, TransformChangedEventIsSentWhenEntityIsActivatedViaUndoRedo) + { + AZ::EntityId entityId = CreateEntityUnderRootPrefab("Entity"); + MoveEntity(entityId); + BusConnect(entityId); + + // verify that undoing/redoing move operations fires TransformChanged event + Undo(); + EXPECT_TRUE(m_transformUpdated); + m_transformUpdated = false; + + Redo(); + EXPECT_TRUE(m_transformUpdated); + m_transformUpdated = false; + } + + TEST_F(TransformComponentActivationTest, TransformChangedEventIsNotSentWhenEntityIsDeactivatedAndActivated) + { + AZ::EntityId entityId = CreateEntityUnderRootPrefab("Entity"); + BusConnect(entityId); + + // verify that simply activating/deactivating an entity does not fire TransformChanged event + Entity* entity = nullptr; + ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId); + entity->Deactivate(); + entity->Activate(); + EXPECT_FALSE(m_transformUpdated); + } } // namespace UnitTest diff --git a/Code/Framework/AzToolsFramework/Tests/UI/EntityOutlinerTests.cpp b/Code/Framework/AzToolsFramework/Tests/UI/EntityOutlinerTests.cpp index fa8de64c62..0035b26b2a 100644 --- a/Code/Framework/AzToolsFramework/Tests/UI/EntityOutlinerTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/UI/EntityOutlinerTests.cpp @@ -37,16 +37,11 @@ namespace UnitTest m_model->Initialize(); m_modelTester = AZStd::make_unique(m_model.get(), QAbstractItemModelTester::FailureReportingMode::Fatal); - - AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult( - m_undoStack, &AzToolsFramework::ToolsApplicationRequestBus::Events::GetUndoStack); - AZ_Assert(m_undoStack, "Failed to look up undo stack from tools application"); - + // Create a new root prefab - the synthetic "NewLevel.prefab" that comes in by default isn't suitable for outliner tests // because it's created before the EditorEntityModel that our EntityOutlinerListModel subscribes to, and we want to // recreate it as part of the fixture regardless. - auto entityOwnershipService = AZ::Interface::Get(); - entityOwnershipService->CreateNewLevelPrefab("UnitTestRoot.prefab", ""); + CreateRootPrefab(); } void TearDownEditorFixtureImpl() override @@ -56,45 +51,7 @@ namespace UnitTest m_model.reset(); PrefabTestFixture::TearDownEditorFixtureImpl(); } - - // Creates an entity with a given name as one undoable operation - // Parents to parentId, or the root prefab container entity if parentId is invalid - AZ::EntityId CreateNamedEntity(AZStd::string name, AZ::EntityId parentId = AZ::EntityId()) - { - auto createResult = m_prefabPublicInterface->CreateEntity(parentId, AZ::Vector3()); - AZ_Assert(createResult.IsSuccess(), "Failed to create entity: %s", createResult.GetError().c_str()); - AZ::EntityId entityId = createResult.GetValue(); - - AZ::Entity* entity = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId); - - entity->Deactivate(); - - entity->SetName(name); - - // Normally, in invalid parent ID should automatically parent us to the root prefab, but currently in the unit test - // environment entities aren't created with a default transform component, so CreateEntity won't correctly parent. - // We get the actual target parent ID here, then create our missing transform component. - if (!parentId.IsValid()) - { - auto prefabEditorEntityOwnershipInterface = AZ::Interface::Get(); - parentId = prefabEditorEntityOwnershipInterface->GetRootPrefabInstance()->get().GetContainerEntityId(); - } - - auto transform = aznew AzToolsFramework::Components::TransformComponent; - transform->SetParent(parentId); - entity->AddComponent(transform); - - entity->Activate(); - - // Update our undo cache entry to include the rename / reparent as one atomic operation. - m_prefabPublicInterface->GenerateUndoNodesForEntityChangeAndUpdateCache(entityId, m_undoStack->GetTop()); - - ProcessDeferredUpdates(); - - return entityId; - } - + // Helper to visualize debug state void PrintModel() { @@ -125,32 +82,16 @@ namespace UnitTest } // Kicks off any updates scheduled for the next tick - void ProcessDeferredUpdates() + void ProcessDeferredUpdates() override { - // Force a prefab propagation for updates that are deferred to the next tick. - m_prefabSystemComponent->OnSystemTick(); + PrefabTestFixture::ProcessDeferredUpdates(); // Ensure the model process its entity update queue m_model->ProcessEntityUpdates(); } - - // Performs an undo operation and ensures the tick-scheduled updates happen - void Undo() - { - m_undoStack->Undo(); - ProcessDeferredUpdates(); - } - - // Performs a redo operation and ensures the tick-scheduled updates happen - void Redo() - { - m_undoStack->Redo(); - ProcessDeferredUpdates(); - } - + AZStd::unique_ptr m_model; AZStd::unique_ptr m_modelTester; - AzToolsFramework::UndoSystem::UndoStack* m_undoStack = nullptr; }; TEST_F(EntityOutlinerTest, TestCreateFlatHierarchyUndoAndRedoWorks) @@ -159,7 +100,7 @@ namespace UnitTest for (size_t i = 0; i < entityCount; ++i) { - CreateNamedEntity(AZStd::string::format("Entity%zu", i)); + CreateEntityUnderRootPrefab(AZStd::string::format("Entity%zu", i)); EXPECT_EQ(m_model->rowCount(GetRootIndex()), i + 1); } @@ -195,7 +136,7 @@ namespace UnitTest AZ::EntityId parentId; for (int i = 0; i < depth; i++) { - parentId = CreateNamedEntity(AZStd::string::format("EntityDepth%i", i), parentId); + parentId = CreateEntityUnderRootPrefab(AZStd::string::format("EntityDepth%i", i), parentId); EXPECT_EQ(modelDepth(), i + 1); } From 969dbf407a8aa4fdd30a16fc992f1bd8ff9b31be Mon Sep 17 00:00:00 2001 From: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> Date: Mon, 6 Dec 2021 14:53:45 +0000 Subject: [PATCH 101/128] Add tests for planar manipulator draw when dealing with scaling (#6164) * add support to add a custom debug display request interface for manipulator test framework Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * wip changes to support tests for manipulator view drawing Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * add test for planar manipulator draw when dealing with scaling Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * additional comments for added context Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * small updates/fixes after PR feedback Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * fix for missing NullDebugDisplayRequests Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> --- .../UnitTest/TestDebugDisplayRequests.h | 7 ++ .../AzManipulatorTestFrameworkTestHelpers.h | 3 +- .../DirectManipulatorViewportInteraction.h | 5 +- .../IndirectManipulatorViewportInteraction.h | 2 +- .../ViewportInteraction.h | 11 ++- .../DirectManipulatorViewportInteraction.cpp | 5 +- ...IndirectManipulatorViewportInteraction.cpp | 5 +- .../Source/ViewportInteraction.cpp | 13 +-- .../Tests/GridSnappingTest.cpp | 3 +- .../Tests/ViewportInteractionTest.cpp | 3 +- .../Tests/WorldSpaceBuilderTest.cpp | 6 +- .../Manipulators/AngularManipulator.cpp | 4 +- .../LineSegmentSelectionManipulator.cpp | 4 +- .../Manipulators/LinearManipulator.cpp | 4 +- .../Manipulators/ManipulatorManager.cpp | 2 +- .../Manipulators/ManipulatorSpace.cpp | 15 ++-- .../Manipulators/ManipulatorSpace.h | 2 + .../Manipulators/ManipulatorView.cpp | 9 ++- .../Manipulators/ManipulatorView.h | 3 +- .../Manipulators/MultiLinearManipulator.cpp | 4 +- .../Manipulators/PlanarManipulator.cpp | 4 +- .../Manipulators/SelectionManipulator.cpp | 4 +- .../SplineSelectionManipulator.cpp | 4 +- .../Manipulators/SurfaceManipulator.cpp | 4 +- .../Manipulators/TranslationManipulators.cpp | 80 ++++++++++++++----- .../Manipulators/TranslationManipulators.h | 42 ++++++++-- .../UnitTest/AzToolsFrameworkTestHelpers.h | 9 +++ .../Tests/ManipulatorViewTests.cpp | 80 +++++++++++++++---- .../JointsSubComponentModeAngleCone.cpp | 5 +- .../Code/Tests/WhiteBoxComponentTest.cpp | 8 +- 30 files changed, 244 insertions(+), 106 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/UnitTest/TestDebugDisplayRequests.h b/Code/Framework/AzFramework/AzFramework/UnitTest/TestDebugDisplayRequests.h index 72b15c1a69..b71d10c751 100644 --- a/Code/Framework/AzFramework/AzFramework/UnitTest/TestDebugDisplayRequests.h +++ b/Code/Framework/AzFramework/AzFramework/UnitTest/TestDebugDisplayRequests.h @@ -13,6 +13,13 @@ namespace UnitTest { + //! Null implementation of DebugDisplayRequests for dummy draw calls. + class NullDebugDisplayRequests : public AzFramework::DebugDisplayRequests + { + public: + virtual ~NullDebugDisplayRequests() = default; + }; + //! Minimal implementation of DebugDisplayRequests to support testing shapes. //! Stores a list of points based on received draw calls to delineate the exterior of the object requested to be drawn. class TestDebugDisplayRequests : public AzFramework::DebugDisplayRequests diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h index f87f83c1b2..63392eb82f 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h @@ -29,7 +29,8 @@ namespace UnitTest void SetUpEditorFixtureImpl() override { ToolsApplicationFixtureT::SetUpEditorFixtureImpl(); - m_viewportManipulatorInteraction = AZStd::make_unique(); + m_viewportManipulatorInteraction = + AZStd::make_unique(ToolsApplicationFixtureT::CreateDebugDisplayRequests()); m_actionDispatcher = AZStd::make_unique(*m_viewportManipulatorInteraction); m_cameraState = AzFramework::CreateIdentityDefaultCamera(AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize); diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/DirectManipulatorViewportInteraction.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/DirectManipulatorViewportInteraction.h index 7cef7b635d..33afee695b 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/DirectManipulatorViewportInteraction.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/DirectManipulatorViewportInteraction.h @@ -17,11 +17,10 @@ namespace AzManipulatorTestFramework class ViewportInteraction; //! Implementation of manipulator viewport interaction that manipulates the manager directly. - class DirectCallManipulatorViewportInteraction - : public ManipulatorViewportInteraction + class DirectCallManipulatorViewportInteraction : public ManipulatorViewportInteraction { public: - DirectCallManipulatorViewportInteraction(); + explicit DirectCallManipulatorViewportInteraction(AZStd::shared_ptr debugDisplayRequests); ~DirectCallManipulatorViewportInteraction(); // ManipulatorViewportInteractionInterface ... diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h index a7b1be2c7d..da2804dfd5 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h @@ -21,7 +21,7 @@ namespace AzManipulatorTestFramework class IndirectCallManipulatorViewportInteraction : public ManipulatorViewportInteraction { public: - IndirectCallManipulatorViewportInteraction(); + explicit IndirectCallManipulatorViewportInteraction(AZStd::shared_ptr debugDisplayRequests); ~IndirectCallManipulatorViewportInteraction(); // ManipulatorViewportInteractionInterface ... diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ViewportInteraction.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ViewportInteraction.h index a353140d4c..1568c1a931 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ViewportInteraction.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ViewportInteraction.h @@ -11,10 +11,13 @@ #include #include +namespace AzFramework +{ + class DebugDisplayRequests; +} + namespace AzManipulatorTestFramework { - class NullDebugDisplayRequests; - //! Implementation of the viewport interaction model to handle viewport interaction requests. class ViewportInteraction : public ViewportInteractionInterface @@ -23,7 +26,7 @@ namespace AzManipulatorTestFramework , private AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler { public: - ViewportInteraction(); + explicit ViewportInteraction(AZStd::shared_ptr debugDisplayRequests); ~ViewportInteraction(); // ViewportInteractionInterface overrides ... @@ -63,7 +66,7 @@ namespace AzManipulatorTestFramework static constexpr AzFramework::ViewportId m_viewportId = 1234; //!< Arbitrary viewport id for manipulator tests. AzFramework::EntityVisibilityQuery m_entityVisibilityQuery; - AZStd::unique_ptr m_nullDebugDisplayRequests; + AZStd::shared_ptr m_debugDisplayRequests; AzFramework::CameraState m_cameraState; bool m_gridSnapping = false; bool m_angularSnapping = false; diff --git a/Code/Framework/AzManipulatorTestFramework/Source/DirectManipulatorViewportInteraction.cpp b/Code/Framework/AzManipulatorTestFramework/Source/DirectManipulatorViewportInteraction.cpp index c9234fe488..c96840e4c9 100644 --- a/Code/Framework/AzManipulatorTestFramework/Source/DirectManipulatorViewportInteraction.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Source/DirectManipulatorViewportInteraction.cpp @@ -118,10 +118,11 @@ namespace AzManipulatorTestFramework return m_manipulatorManager->Interacting(); } - DirectCallManipulatorViewportInteraction::DirectCallManipulatorViewportInteraction() + DirectCallManipulatorViewportInteraction::DirectCallManipulatorViewportInteraction( + AZStd::shared_ptr debugDisplayRequests) : m_customManager( AZStd::make_unique(AzToolsFramework::ManipulatorManagerId(AZ::Crc32("TestManipulatorManagerId")))) - , m_viewportInteraction(AZStd::make_unique()) + , m_viewportInteraction(AZStd::make_unique(AZStd::move(debugDisplayRequests))) , m_manipulatorManager(AZStd::make_unique(m_viewportInteraction.get(), m_customManager)) { } diff --git a/Code/Framework/AzManipulatorTestFramework/Source/IndirectManipulatorViewportInteraction.cpp b/Code/Framework/AzManipulatorTestFramework/Source/IndirectManipulatorViewportInteraction.cpp index 9bcb8986d5..9c5f84196f 100644 --- a/Code/Framework/AzManipulatorTestFramework/Source/IndirectManipulatorViewportInteraction.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Source/IndirectManipulatorViewportInteraction.cpp @@ -76,8 +76,9 @@ namespace AzManipulatorTestFramework return manipulatorInteracting; } - IndirectCallManipulatorViewportInteraction::IndirectCallManipulatorViewportInteraction() - : m_viewportInteraction(AZStd::make_unique()) + IndirectCallManipulatorViewportInteraction::IndirectCallManipulatorViewportInteraction( + AZStd::shared_ptr debugDisplayRequests) + : m_viewportInteraction(AZStd::make_unique(AZStd::move(debugDisplayRequests))) , m_manipulatorManager(AZStd::make_unique(*m_viewportInteraction)) { } diff --git a/Code/Framework/AzManipulatorTestFramework/Source/ViewportInteraction.cpp b/Code/Framework/AzManipulatorTestFramework/Source/ViewportInteraction.cpp index e56f7d6d72..1a28c8cad1 100644 --- a/Code/Framework/AzManipulatorTestFramework/Source/ViewportInteraction.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Source/ViewportInteraction.cpp @@ -13,15 +13,8 @@ namespace AzManipulatorTestFramework { - // Null debug display for dummy draw calls - class NullDebugDisplayRequests : public AzFramework::DebugDisplayRequests - { - public: - virtual ~NullDebugDisplayRequests() = default; - }; - - ViewportInteraction::ViewportInteraction() - : m_nullDebugDisplayRequests(AZStd::make_unique()) + ViewportInteraction::ViewportInteraction(AZStd::shared_ptr debugDisplayRequests) + : m_debugDisplayRequests(AZStd::move(debugDisplayRequests)) { AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler::BusConnect(m_viewportId); AzToolsFramework::ViewportInteraction::ViewportSettingsRequestBus::Handler::BusConnect(m_viewportId); @@ -102,7 +95,7 @@ namespace AzManipulatorTestFramework AzFramework::DebugDisplayRequests& ViewportInteraction::GetDebugDisplay() { - return *m_nullDebugDisplayRequests; + return *m_debugDisplayRequests; } void ViewportInteraction::SetGridSnapping(const bool enabled) diff --git a/Code/Framework/AzManipulatorTestFramework/Tests/GridSnappingTest.cpp b/Code/Framework/AzManipulatorTestFramework/Tests/GridSnappingTest.cpp index 4af66edc0a..8707d08bb3 100644 --- a/Code/Framework/AzManipulatorTestFramework/Tests/GridSnappingTest.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Tests/GridSnappingTest.cpp @@ -26,7 +26,8 @@ namespace UnitTest { public: GridSnappingFixture() - : m_viewportManipulatorInteraction(AZStd::make_unique()) + : m_viewportManipulatorInteraction(AZStd::make_unique( + AZStd::make_shared())) , m_actionDispatcher( AZStd::make_unique(*m_viewportManipulatorInteraction)) { diff --git a/Code/Framework/AzManipulatorTestFramework/Tests/ViewportInteractionTest.cpp b/Code/Framework/AzManipulatorTestFramework/Tests/ViewportInteractionTest.cpp index 38c3e33977..481647f960 100644 --- a/Code/Framework/AzManipulatorTestFramework/Tests/ViewportInteractionTest.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Tests/ViewportInteractionTest.cpp @@ -15,7 +15,8 @@ namespace UnitTest { public: AValidViewportInteraction() - : m_viewportInteraction(AZStd::make_unique()) + : m_viewportInteraction( + AZStd::make_unique(AZStd::make_shared())) { } diff --git a/Code/Framework/AzManipulatorTestFramework/Tests/WorldSpaceBuilderTest.cpp b/Code/Framework/AzManipulatorTestFramework/Tests/WorldSpaceBuilderTest.cpp index 376c18072e..95afe0e47d 100644 --- a/Code/Framework/AzManipulatorTestFramework/Tests/WorldSpaceBuilderTest.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Tests/WorldSpaceBuilderTest.cpp @@ -75,9 +75,11 @@ namespace UnitTest void SetUpEditorFixtureImpl() override { m_directState = - AZStd::make_unique(AZStd::make_unique()); + AZStd::make_unique(AZStd::make_unique( + AZStd::make_shared())); m_busState = - AZStd::make_unique(AZStd::make_unique()); + AZStd::make_unique(AZStd::make_unique( + AZStd::make_shared())); m_cameraState = AzFramework::CreateIdentityDefaultCamera(AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/AngularManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/AngularManipulator.cpp index b8fb4e6a53..29445f6562 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/AngularManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/AngularManipulator.cpp @@ -191,8 +191,8 @@ namespace AzToolsFramework { m_manipulatorView->Draw( GetManipulatorManagerId(), managerState, GetManipulatorId(), - { ApplySpace(GetLocalTransform()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay, cameraState, - mouseInteraction); + ManipulatorState{ ApplySpace(GetLocalTransform()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay, + cameraState, mouseInteraction); } void AngularManipulator::SetAxis(const AZ::Vector3& axis) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineSegmentSelectionManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineSegmentSelectionManipulator.cpp index 2131fdf1cf..4ded50e1ab 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineSegmentSelectionManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineSegmentSelectionManipulator.cpp @@ -116,8 +116,8 @@ namespace AzToolsFramework { m_manipulatorView->Draw( GetManipulatorManagerId(), managerState, GetManipulatorId(), - { TransformUniformScale(GetSpace()), GetNonUniformScale(), m_localStart, MouseOver() }, debugDisplay, cameraState, - mouseInteraction); + ManipulatorState{ TransformUniformScale(GetSpace()), GetNonUniformScale(), m_localStart, MouseOver() }, debugDisplay, + cameraState, mouseInteraction); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.cpp index ee63c5de47..8b55480e5a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.cpp @@ -239,8 +239,8 @@ namespace AzToolsFramework view->Draw( GetManipulatorManagerId(), managerState, GetManipulatorId(), - { ApplySpace(localTransform), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay, cameraState, - mouseInteraction); + ManipulatorState{ ApplySpace(localTransform), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay, + cameraState, mouseInteraction); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorManager.cpp index b07ac08d87..859bfcab30 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorManager.cpp @@ -146,7 +146,7 @@ namespace AzToolsFramework for (const auto& pair : m_manipulatorIdToPtrMap) { - pair.second->Draw({ Interacting() }, debugDisplay, cameraState, mouseInteraction); + pair.second->Draw(ManipulatorManagerState{ Interacting() }, debugDisplay, cameraState, mouseInteraction); } RefreshMouseOverState(mouseInteraction.m_mousePick); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSpace.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSpace.cpp index d42182db92..5e05bea72a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSpace.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSpace.cpp @@ -10,6 +10,15 @@ namespace AzToolsFramework { + AZ::Transform ApplySpace(const AZ::Transform& localTransform, const AZ::Transform& space, const AZ::Vector3& nonUniformScale) + { + AZ::Transform result; + result.SetRotation(space.GetRotation() * localTransform.GetRotation()); + result.SetTranslation(space.TransformPoint(nonUniformScale * localTransform.GetTranslation())); + result.SetUniformScale(space.GetUniformScale() * localTransform.GetUniformScale()); + return result; + } + const AZ::Transform& ManipulatorSpace::GetSpace() const { return m_space; @@ -32,11 +41,7 @@ namespace AzToolsFramework AZ::Transform ManipulatorSpace::ApplySpace(const AZ::Transform& localTransform) const { - AZ::Transform result; - result.SetRotation(m_space.GetRotation() * localTransform.GetRotation()); - result.SetTranslation(m_space.TransformPoint(m_nonUniformScale * localTransform.GetTranslation())); - result.SetUniformScale(m_space.GetUniformScale() * localTransform.GetUniformScale()); - return result; + return AzToolsFramework::ApplySpace(localTransform, m_space, m_nonUniformScale); } const AZ::Vector3& ManipulatorSpaceWithLocalPosition::GetLocalPosition() const diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSpace.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSpace.h index c372afcf32..5ceb4a36cc 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSpace.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSpace.h @@ -17,6 +17,8 @@ namespace AZ namespace AzToolsFramework { + AZ::Transform ApplySpace(const AZ::Transform& localTransform, const AZ::Transform& space, const AZ::Vector3& nonUniformScale); + //! Handles location for manipulators which have a global space but no local transformation. class ManipulatorSpace { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorView.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorView.cpp index e36231032f..e4ee75bbf9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorView.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorView.cpp @@ -383,8 +383,8 @@ namespace AzToolsFramework debugDisplay.DrawLine(quadBoundVisual.m_corner1, quadBoundVisual.m_corner2); debugDisplay.SetColor(ViewColor(manipulatorState.m_mouseOver, m_axis2Color, m_mouseOverColor).GetAsVector4()); + debugDisplay.DrawLine(quadBoundVisual.m_corner4, quadBoundVisual.m_corner1); debugDisplay.DrawLine(quadBoundVisual.m_corner2, quadBoundVisual.m_corner3); - debugDisplay.DrawLine(quadBoundVisual.m_corner1, quadBoundVisual.m_corner4); if (manipulatorState.m_mouseOver) { @@ -738,15 +738,16 @@ namespace AzToolsFramework /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AZStd::unique_ptr CreateManipulatorViewQuad( - const PlanarManipulator& planarManipulator, + const AZ::Vector3& axis1, + const AZ::Vector3& axis2, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const AZ::Vector3& offset, const float size) { AZStd::unique_ptr viewQuad = AZStd::make_unique(); - viewQuad->m_axis1 = planarManipulator.GetAxis1(); - viewQuad->m_axis2 = planarManipulator.GetAxis2(); + viewQuad->m_axis1 = axis1; + viewQuad->m_axis2 = axis2; viewQuad->m_size = size; viewQuad->m_offset = offset; viewQuad->m_axis1Color = axis1Color; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorView.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorView.h index 6f94a9d253..8a9514d11a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorView.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorView.h @@ -382,7 +382,8 @@ namespace AzToolsFramework // Helpers to create various manipulator views. AZStd::unique_ptr CreateManipulatorViewQuad( - const PlanarManipulator& planarManipulator, + const AZ::Vector3& axis1, + const AZ::Vector3& axis2, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const AZ::Vector3& offset, diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.cpp index 10c3a57749..f4dca63d77 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.cpp @@ -145,8 +145,8 @@ namespace AzToolsFramework { view->Draw( GetManipulatorManagerId(), managerState, GetManipulatorId(), - { ApplySpace(GetLocalTransform()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay, - cameraState, mouseInteraction); + ManipulatorState{ ApplySpace(GetLocalTransform()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, + debugDisplay, cameraState, mouseInteraction); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.cpp index 825edf6ba4..9dbb49a1e6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.cpp @@ -202,8 +202,8 @@ namespace AzToolsFramework { view->Draw( GetManipulatorManagerId(), managerState, GetManipulatorId(), - { ApplySpace(GetLocalTransform()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay, - cameraState, mouseInteraction); + ManipulatorState{ ApplySpace(GetLocalTransform()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, + debugDisplay, cameraState, mouseInteraction); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SelectionManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SelectionManipulator.cpp index 9cf97dc213..64496c44d7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SelectionManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SelectionManipulator.cpp @@ -90,8 +90,8 @@ namespace AzToolsFramework { view->Draw( GetManipulatorManagerId(), managerState, GetManipulatorId(), - { TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalPosition(), MouseOver() }, debugDisplay, cameraState, - mouseInteraction); + ManipulatorState{ TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalPosition(), MouseOver() }, debugDisplay, + cameraState, mouseInteraction); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineSelectionManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineSelectionManipulator.cpp index 4ee965e43a..1da4240bf7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineSelectionManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineSelectionManipulator.cpp @@ -94,8 +94,8 @@ namespace AzToolsFramework { m_manipulatorView->Draw( GetManipulatorManagerId(), managerState, GetManipulatorId(), - { TransformUniformScale(GetSpace()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay, - cameraState, mouseInteraction); + ManipulatorState{ TransformUniformScale(GetSpace()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, + debugDisplay, cameraState, mouseInteraction); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SurfaceManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SurfaceManipulator.cpp index 01b8635406..58d579b20c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SurfaceManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SurfaceManipulator.cpp @@ -166,8 +166,8 @@ namespace AzToolsFramework { m_manipulatorView->Draw( GetManipulatorManagerId(), managerState, GetManipulatorId(), - { TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalPosition(), MouseOver() }, debugDisplay, cameraState, - mouseInteraction); + ManipulatorState{ TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalPosition(), MouseOver() }, debugDisplay, + cameraState, mouseInteraction); } void SurfaceManipulator::InvalidateImpl() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/TranslationManipulators.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/TranslationManipulators.cpp index f6c0028546..5810662e57 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/TranslationManipulators.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/TranslationManipulators.cpp @@ -19,6 +19,21 @@ namespace AzToolsFramework static const AZ::Color LinearManipulatorZAxisColor = AZ::Color(0.0f, 0.0f, 1.0f, 1.0f); static const AZ::Color SurfaceManipulatorColor = AZ::Color(1.0f, 1.0f, 0.0f, 0.5f); + static TranslationManipulatorsViewCreateInfo DefaultTranslationManipulatorViewCreateInfo() + { + TranslationManipulatorsViewCreateInfo createInfo; + createInfo.axis1Color = LinearManipulatorXAxisColor; + createInfo.axis2Color = LinearManipulatorYAxisColor; + createInfo.axis3Color = LinearManipulatorZAxisColor; + createInfo.surfaceColor = SurfaceManipulatorColor; + createInfo.linearAxisLength = LinearManipulatorAxisLength(); + createInfo.linearConeLength = LinearManipulatorConeLength(); + createInfo.linearConeRadius = LinearManipulatorConeRadius(); + createInfo.planarAxisLength = PlanarManipulatorAxisLength(); + createInfo.surfaceRadius = SurfaceManipulatorRadius(); + return createInfo; + } + TranslationManipulators::TranslationManipulators( const Dimensions dimensions, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale) : m_dimensions(dimensions) @@ -231,17 +246,36 @@ namespace AzToolsFramework } } + void TranslationManipulators::ConfigureView2d(const TranslationManipulatorsViewCreateInfo& translationManipulatorViewCreateInfo) + { + ConfigureLinearView( + translationManipulatorViewCreateInfo.linearAxisLength, translationManipulatorViewCreateInfo.linearConeLength, + translationManipulatorViewCreateInfo.linearConeRadius, translationManipulatorViewCreateInfo.axis1Color, + translationManipulatorViewCreateInfo.axis2Color, translationManipulatorViewCreateInfo.axis3Color); + ConfigurePlanarView( + translationManipulatorViewCreateInfo.planarAxisLength, translationManipulatorViewCreateInfo.linearAxisLength, + translationManipulatorViewCreateInfo.linearConeLength, translationManipulatorViewCreateInfo.axis1Color, + translationManipulatorViewCreateInfo.axis2Color, translationManipulatorViewCreateInfo.axis3Color); + } + + void TranslationManipulators::ConfigureView3d(const TranslationManipulatorsViewCreateInfo& translationManipulatorViewCreateInfo) + { + ConfigureView2d(translationManipulatorViewCreateInfo); + ConfigureSurfaceView(translationManipulatorViewCreateInfo.surfaceRadius, translationManipulatorViewCreateInfo.surfaceColor); + } + void TranslationManipulators::ConfigureLinearView( const float axisLength, + const float coneLength, + const float coneRadius, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const AZ::Color& axis3Color /*= AZ::Color(0.0f, 0.0f, 1.0f, 0.5f)*/) { const AZ::Color axesColor[] = { axis1Color, axis2Color, axis3Color }; - const auto configureLinearView = - [lineBoundWidth = m_lineBoundWidth, coneLength = LinearManipulatorConeLength(), axisLength, - coneRadius = LinearManipulatorConeRadius()](LinearManipulator* linearManipulator, const AZ::Color& color) + const auto configureLinearView = [lineBoundWidth = m_lineBoundWidth, coneLength, axisLength, + coneRadius](LinearManipulator* linearManipulator, const AZ::Color& color) { const auto lineLength = axisLength - coneLength; @@ -259,25 +293,21 @@ namespace AzToolsFramework } void TranslationManipulators::ConfigurePlanarView( - const float planeSize, + const float planarAxisLength, + const float linearAxisLength, + const float linearConeLength, const AZ::Color& plane1Color, const AZ::Color& plane2Color /*= AZ::Color(0.0f, 1.0f, 0.0f, 0.5f)*/, const AZ::Color& plane3Color /*= AZ::Color(0.0f, 0.0f, 1.0f, 0.5f)*/) { const AZ::Color planesColor[] = { plane1Color, plane2Color, plane3Color }; - const float linearAxisLength = LinearManipulatorAxisLength(); - const float linearConeLength = LinearManipulatorConeLength(); for (size_t manipulatorIndex = 0; manipulatorIndex < m_planarManipulators.size(); ++manipulatorIndex) { const auto& planarManipulator = *m_planarManipulators[manipulatorIndex]; - const AZStd::shared_ptr manipulatorView = CreateManipulatorViewQuad( - *m_planarManipulators[manipulatorIndex], planesColor[manipulatorIndex], planesColor[(manipulatorIndex + 1) % 3], - (planarManipulator.GetAxis1() + planarManipulator.GetAxis2()) * - (((linearAxisLength - linearConeLength) * 0.5f) - (planeSize * 0.5f)), - planeSize); - - m_planarManipulators[manipulatorIndex]->SetViews(ManipulatorViews{ manipulatorView }); + m_planarManipulators[manipulatorIndex]->SetViews(ManipulatorViews{ CreateManipulatorViewQuadForPlanarTranslationManipulator( + planarManipulator.GetAxis1(), planarManipulator.GetAxis2(), planesColor[manipulatorIndex], + planesColor[(manipulatorIndex + 1) % 3], linearAxisLength, linearConeLength, planarAxisLength) }); } } @@ -325,19 +355,25 @@ namespace AzToolsFramework void ConfigureTranslationManipulatorAppearance3d(TranslationManipulators* translationManipulators) { translationManipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ()); - translationManipulators->ConfigurePlanarView( - PlanarManipulatorAxisLength(), LinearManipulatorXAxisColor, LinearManipulatorYAxisColor, LinearManipulatorZAxisColor); - translationManipulators->ConfigureLinearView( - LinearManipulatorAxisLength(), LinearManipulatorXAxisColor, LinearManipulatorYAxisColor, LinearManipulatorZAxisColor); - translationManipulators->ConfigureSurfaceView(SurfaceManipulatorRadius(), SurfaceManipulatorColor); + translationManipulators->ConfigureView3d(DefaultTranslationManipulatorViewCreateInfo()); } void ConfigureTranslationManipulatorAppearance2d(TranslationManipulators* translationManipulators) { translationManipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY()); - translationManipulators->ConfigurePlanarView( - PlanarManipulatorAxisLength(), LinearManipulatorXAxisColor, LinearManipulatorYAxisColor); - translationManipulators->ConfigureLinearView( - LinearManipulatorAxisLength(), LinearManipulatorXAxisColor, LinearManipulatorYAxisColor); + translationManipulators->ConfigureView2d(DefaultTranslationManipulatorViewCreateInfo()); + } + + AZStd::shared_ptr CreateManipulatorViewQuadForPlanarTranslationManipulator( + const AZ::Vector3& axis1, + const AZ::Vector3& axis2, + const AZ::Color& axis1Color, + const AZ::Color& axis2Color, + const float linearAxisLength, + const float linearConeLength, + const float planarAxisLength) + { + const AZ::Vector3 offset = (axis1 + axis2) * (((linearAxisLength - linearConeLength) * 0.5f) - (planarAxisLength * 0.5f)); + return CreateManipulatorViewQuad(axis1, axis2, axis1Color, axis2Color, offset, planarAxisLength); } } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/TranslationManipulators.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/TranslationManipulators.h index 341bb2d4ac..ea8dbb7975 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/TranslationManipulators.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/TranslationManipulators.h @@ -15,6 +15,20 @@ namespace AzToolsFramework { + //! Parameters to configure the appearance of the TranslationManipulators view(s). + struct TranslationManipulatorsViewCreateInfo + { + float linearAxisLength; + float linearConeLength; + float linearConeRadius; + float planarAxisLength; + float surfaceRadius; + AZ::Color axis1Color; + AZ::Color axis2Color; + AZ::Color axis3Color; + AZ::Color surfaceColor; + }; + //! TranslationManipulators is an aggregation of 3 linear manipulators, 3 planar manipulators //! and one surface manipulator who share the same transform. class TranslationManipulators : public Manipulators @@ -23,6 +37,9 @@ namespace AzToolsFramework AZ_RTTI(TranslationManipulators, "{D5E49EA2-30E0-42BC-A51D-6A7F87818260}") AZ_CLASS_ALLOCATOR(TranslationManipulators, AZ::SystemAllocator, 0) + TranslationManipulators(TranslationManipulators&&) = delete; + TranslationManipulators& operator=(TranslationManipulators&&) = delete; + //! How many dimensions does this translation manipulator have. enum class Dimensions { @@ -52,26 +69,31 @@ namespace AzToolsFramework void SetAxes(const AZ::Vector3& axis1, const AZ::Vector3& axis2, const AZ::Vector3& axis3 = AZ::Vector3::CreateAxisZ()); + void ConfigureView2d(const TranslationManipulatorsViewCreateInfo& translationManipulatorViewCreateInfo); + void ConfigureView3d(const TranslationManipulatorsViewCreateInfo& translationManipulatorViewCreateInfo); + + //! Sets the bound width to use for the line/axis of a linear manipulator. + void SetLineBoundWidth(float lineBoundWidth); + + private: void ConfigurePlanarView( float planeSize, + float linearAxisLength, + float linearConeLength, const AZ::Color& plane1Color, const AZ::Color& plane2Color = AZ::Color(0.0f, 1.0f, 0.0f, 0.5f), const AZ::Color& plane3Color = AZ::Color(0.0f, 0.0f, 1.0f, 0.5f)); void ConfigureLinearView( float axisLength, + float coneLength, + float coneRadius, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const AZ::Color& axis3Color = AZ::Color(0.0f, 0.0f, 1.0f, 0.5f)); void ConfigureSurfaceView(float radius, const AZ::Color& color); - //! Sets the bound width to use for the line/axis of a linear manipulator. - void SetLineBoundWidth(float lineBoundWidth); - - private: - AZ_DISABLE_COPY_MOVE(TranslationManipulators) - // Manipulators void ProcessManipulators(const AZStd::function&) override; @@ -131,4 +153,12 @@ namespace AzToolsFramework void ConfigureTranslationManipulatorAppearance3d(TranslationManipulators* translationManipulators); void ConfigureTranslationManipulatorAppearance2d(TranslationManipulators* translationManipulators); + AZStd::shared_ptr CreateManipulatorViewQuadForPlanarTranslationManipulator( + const AZ::Vector3& axis1, + const AZ::Vector3& axis2, + const AZ::Color& axis1Color, + const AZ::Color& axis2Color, + float linearAxisLength, + float linearConeLength, + float planarAxisLength); } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h index 1e29f1dbce..77a3639871 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h @@ -15,12 +15,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -235,6 +237,13 @@ namespace UnitTest return toolsApp; } + //! It is possible to override this in classes deriving from ToolsApplicationFixture to provide alternate + //! implementations of the DebugDisplayRequests interface (e.g. TestDebugDisplayRequests). + virtual AZStd::shared_ptr CreateDebugDisplayRequests() + { + return AZStd::make_shared(); + } + protected: TestEditorActions m_editorActions; ToolsApplicationMessageHandler m_messageHandler; // used to suppress trace messages in test output diff --git a/Code/Framework/AzToolsFramework/Tests/ManipulatorViewTests.cpp b/Code/Framework/AzToolsFramework/Tests/ManipulatorViewTests.cpp index 11ec33a995..5f02d9da9c 100644 --- a/Code/Framework/AzToolsFramework/Tests/ManipulatorViewTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/ManipulatorViewTests.cpp @@ -7,12 +7,16 @@ */ #include +#include +#include +#include +#include #include #include -#include +#include #include -#include - +#include +#include #include #include #include @@ -21,8 +25,7 @@ namespace UnitTest { using namespace AzToolsFramework; - class ManipulatorViewTest - : public AllocatorsTestFixture + class ManipulatorViewTest : public AllocatorsTestFixture { AZStd::unique_ptr m_serializeContext; @@ -32,7 +35,7 @@ namespace UnitTest m_serializeContext = AZStd::make_unique(); m_app.Start(AzFramework::Application::Descriptor()); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); } @@ -51,12 +54,9 @@ namespace UnitTest /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Given const AZ::Transform orientation = - AZ::Transform::CreateFromQuaternion( - AZ::Quaternion::CreateFromAxisAngle( - AZ::Vector3::CreateAxisX(), AZ::DegToRad(-90.0f))); + AZ::Transform::CreateFromQuaternion(AZ::Quaternion::CreateRotationX(AZ::DegToRad(-90.0f))); - const AZ::Transform translation = - AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 0.0f, 10.0f)); + const AZ::Transform translation = AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 0.0f, 10.0f)); const AZ::Transform manipulatorSpace = translation * orientation; // create a rotation manipulator in an arbitrary space @@ -67,8 +67,7 @@ namespace UnitTest // When const AZ::Vector3 worldCameraPosition = AZ::Vector3(5.0f, -10.0f, 10.0f); // transform the view direction to the space of the manipulator (space + local transform) - const AZ::Vector3 viewDirection = - CalculateViewDirection(rotationManipulators, worldCameraPosition); + const AZ::Vector3 viewDirection = CalculateViewDirection(rotationManipulators, worldCameraPosition); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -84,8 +83,7 @@ namespace UnitTest cameraState.m_position = AZ::Vector3::CreateAxisY(20.0f); cameraState.m_forward = -AZ::Vector3::CreateAxisY(); - const float scale = - AzToolsFramework::CalculateScreenToWorldMultiplier(AZ::Vector3::CreateZero(), cameraState); + const float scale = AzToolsFramework::CalculateScreenToWorldMultiplier(AZ::Vector3::CreateZero(), cameraState); EXPECT_NEAR(scale, 2.0f, std::numeric_limits::epsilon()); } @@ -96,9 +94,57 @@ namespace UnitTest cameraState.m_position = AZ::Vector3::CreateAxisY(20.0f); cameraState.m_forward = -AZ::Vector3::CreateAxisY(); - const float scale = - AzToolsFramework::CalculateScreenToWorldMultiplier(AZ::Vector3::CreateAxisX(-10.0f), cameraState); + const float scale = AzToolsFramework::CalculateScreenToWorldMultiplier(AZ::Vector3::CreateAxisX(-10.0f), cameraState); EXPECT_NEAR(scale, 2.0f, std::numeric_limits::epsilon()); } + + TEST_F(ManipulatorViewTest, ManipulatorViewQuadDrawsAtCorrectPositionWhenManipulatorSpaceIsScaledUniformlyAndNonUniformly) + { + // Given + // simulate a custom manipulator space (e.g. entity transform) and a local offset within that space (e.g. spline vertex position) + const AZ::Transform space = + AZ::Transform::CreateTranslation(AZ::Vector3(2.0f, -3.0f, -4.0f)) * AZ::Transform::CreateUniformScale(2.0f); + const AZ::Vector3 localPosition = AZ::Vector3(2.0f, -2.0f, 0.0f); + const AZ::Vector3 nonUniformScale = AZ::Vector3(2.0f, 3.0f, 4.0f); + const AZ::Transform combinedTransform = + AzToolsFramework::ApplySpace(AZ::Transform::CreateTranslation(localPosition), space, nonUniformScale); + + // create a manipulator state based on the space and local position + AzToolsFramework::ManipulatorState manipulatorState{}; + manipulatorState.m_worldFromLocal = combinedTransform; + manipulatorState.m_nonUniformScale = nonUniformScale; + // note: This is zero as the localPosition is already encoded in the combinedTransform + manipulatorState.m_localPosition = AZ::Vector3::CreateZero(); + + // camera (go to position format) - 10.00, -15.00, 6.00, -90.00, 0.00 + const AzFramework::CameraState cameraState = AzFramework::CreateDefaultCamera( + AZ::Transform::CreateFromMatrix3x3AndTranslation( + AZ::Matrix3x3::CreateRotationX(AZ::DegToRad(-90.0f)), AZ::Vector3(10.0f, -15.0f, 6.0f)), + AZ::Vector2(1280, 720)); + + // test debug display instance to record vertices that were output + auto testDebugDisplayRequests = AZStd::make_shared(); + auto planarTranslationViewQuad = CreateManipulatorViewQuadForPlanarTranslationManipulator( + AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Color::CreateZero(), AZ::Color::CreateZero(), 2.2f, 0.2f, 1.0f); + + // When + // draw the quad as it would be for a manipulator + planarTranslationViewQuad->Draw( + AzToolsFramework::ManipulatorManagerId(1), AzToolsFramework::ManipulatorManagerState{ false }, + AzToolsFramework::ManipulatorId(1), manipulatorState, *testDebugDisplayRequests, cameraState, + AzToolsFramework::ViewportInteraction::MouseInteraction{}); + + const AZStd::vector expectedDisplayPositions = { + AZ::Vector3(10.5f, -13.5f, -4.0f), AZ::Vector3(11.5f, -13.5f, -4.0f), AZ::Vector3(10.5f, -14.5f, -4.0f), + AZ::Vector3(11.5f, -14.5f, -4.0f), AZ::Vector3(10.5f, -13.5f, -4.0f), AZ::Vector3(10.5f, -14.5f, -4.0f), + AZ::Vector3(11.5f, -14.5f, -4.0f), AZ::Vector3(11.5f, -13.5f, -4.0f) + }; + + // Then + const auto points = testDebugDisplayRequests->GetPoints(); + // quad vertices appear in the expected position (not offset or scaled incorrectly by space scale) + using ::testing::UnorderedPointwise; + EXPECT_THAT(points, UnorderedPointwise(ContainerIsClose(), expectedDisplayPositions)); + } } // namespace UnitTest diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.cpp index e942d6beaa..b229c9d020 100644 --- a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.cpp +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.cpp @@ -347,8 +347,9 @@ namespace PhysX void JointsSubComponentModeAngleCone::ConfigurePlanarView(const AZ::Color& planeColor, const AZ::Color& plane2Color) { AzToolsFramework::ManipulatorViews views; - views.emplace_back(CreateManipulatorViewQuad( - *m_yzPlanarManipulator, planeColor, plane2Color, AZ::Vector3::CreateZero(), AzToolsFramework::PlanarManipulatorAxisLength())); + views.emplace_back(AzToolsFramework::CreateManipulatorViewQuad( + m_yzPlanarManipulator->GetAxis1(), m_yzPlanarManipulator->GetAxis2(), planeColor, plane2Color, AZ::Vector3::CreateZero(), + AzToolsFramework::PlanarManipulatorAxisLength())); m_yzPlanarManipulator->SetViews(AZStd::move(views)); } diff --git a/Gems/WhiteBox/Code/Tests/WhiteBoxComponentTest.cpp b/Gems/WhiteBox/Code/Tests/WhiteBoxComponentTest.cpp index 0e93f38195..ce592ee2ed 100644 --- a/Gems/WhiteBox/Code/Tests/WhiteBoxComponentTest.cpp +++ b/Gems/WhiteBox/Code/Tests/WhiteBoxComponentTest.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -38,10 +39,6 @@ namespace UnitTest static const AzToolsFramework::ManipulatorManagerId TestManipulatorManagerId = AzToolsFramework::ManipulatorManagerId(AZ::Crc32("TestManipulatorManagerId")); - class NullDebugDisplayRequests : public AzFramework::DebugDisplayRequests - { - }; - class WhiteBoxManipulatorFixture : public WhiteBoxTestFixture { public: @@ -67,7 +64,8 @@ namespace UnitTest // create the direct call manipulator viewport interaction and an immediate mode dispatcher AZStd::unique_ptr viewportManipulatorInteraction = - AZStd::make_unique(); + AZStd::make_unique( + AZStd::make_shared()); AZStd::unique_ptr actionDispatcher = AZStd::make_unique( *viewportManipulatorInteraction); From a7989df0516daea2e6a1be8140a7869766af0b6e Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Mon, 6 Dec 2021 10:39:49 -0600 Subject: [PATCH 102/128] Fixed status combo box style in Entity Inspector. Signed-off-by: Chris Galvan --- .../UI/PropertyEditor/EntityPropertyEditor.cpp | 4 ---- .../UI/PropertyEditor/EntityPropertyEditor.ui | 5 ++++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp index 0b9420a629..8104aee4fd 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp @@ -539,10 +539,6 @@ namespace AzToolsFramework model->setItem(row, 0, m_comboItems[row]); } m_gui->m_statusComboBox->setModel(model); - m_gui->m_statusComboBox->setStyleSheet("QComboBox {border: 0px; border-radius:3px; background-color:#555555; color:white}" - "QComboBox:on {background-color:#e9e9e9; color:black; border:0px}" - "QComboBox::down-arrow:on {image: url(:/stylesheet/img/dropdowns/black_down_arrow.png)}" - "QComboBox::drop-down {border-radius: 3p}"); AzQtComponents::ComboBox::addCustomCheckStateStyle(m_gui->m_statusComboBox); EnableEditor(true); m_sceneIsNew = true; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.ui b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.ui index 8a86d429f1..b7cb5a0156 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.ui +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.ui @@ -191,7 +191,7 @@ - background-color:rgb(51, 51, 51) + QWidget#m_darkBox { background-color:rgb(51, 51, 51) } @@ -444,6 +444,9 @@ Qt::Horizontal + + background-color:rgb(51, 51, 51) + From be252d797dc8842344879781eb01c5348cc1d7fb Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Mon, 6 Dec 2021 09:11:56 -0800 Subject: [PATCH 103/128] Remove disabled failed asset load tests trait from linux (#6100) * Remove trait AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS for Linux Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> --- .../Tests/Asset/AssetManagerLoadingTests.cpp | 16 ++++++++-------- .../AzTest/Platform/Linux/AzTest_Traits_Linux.h | 1 - 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp index 043eb1aee6..c3be9b886a 100644 --- a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp +++ b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp @@ -914,11 +914,11 @@ namespace UnitTest m_testAssetManager->SetParallelDependentLoadingEnabled(true); } -#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS || AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS +#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS TEST_F(AssetJobsFloodTest, DISABLED_LoadTest_SameAsset_DifferentFilters) #else TEST_F(AssetJobsFloodTest, LoadTest_SameAsset_DifferentFilters) -#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS || AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS +#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS { m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusConnect(); @@ -1263,11 +1263,11 @@ namespace UnitTest m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusDisconnect(); } -#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS || AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS +#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS TEST_F(AssetJobsFloodTest, DISABLED_AssetWithNoLoadReference_LoadDependencies_NoLoadNotLoaded) #else TEST_F(AssetJobsFloodTest, AssetWithNoLoadReference_LoadDependencies_NoLoadNotLoaded) -#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS || AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS +#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS { m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusConnect(); // Setup has already created/destroyed assets @@ -1304,11 +1304,11 @@ namespace UnitTest m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusDisconnect(); } -#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS || AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS +#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS TEST_F(AssetJobsFloodTest, DISABLED_AssetWithNoLoadReference_LoadContainerDependencies_LoadAllLoadsNoLoad) #else TEST_F(AssetJobsFloodTest, AssetWithNoLoadReference_LoadContainerDependencies_LoadAllLoadsNoLoad) -#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS || AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS +#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS { m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusConnect(); // Setup has already created/destroyed assets @@ -1343,11 +1343,11 @@ namespace UnitTest m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusDisconnect(); } -#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS || AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS +#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS TEST_F(AssetJobsFloodTest, DISABLED_AssetWithNoLoadReference_LoadDependencies_BehaviorObeyed) #else TEST_F(AssetJobsFloodTest, AssetWithNoLoadReference_LoadDependencies_BehaviorObeyed) -#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS || AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS +#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS { m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusConnect(); // Setup has already created/destroyed assets diff --git a/Code/Framework/AzTest/AzTest/Platform/Linux/AzTest_Traits_Linux.h b/Code/Framework/AzTest/AzTest/Platform/Linux/AzTest_Traits_Linux.h index 6d6513043b..94f3dd004a 100644 --- a/Code/Framework/AzTest/AzTest/Platform/Linux/AzTest_Traits_Linux.h +++ b/Code/Framework/AzTest/AzTest/Platform/Linux/AzTest_Traits_Linux.h @@ -14,7 +14,6 @@ #define AZ_TRAIT_UNIT_TEST_DILLER_TRIGGER_EVENT_COUNT 100000 #define AZ_TRAIT_DISABLE_FAILED_AP_CONNECTION_TESTS true -#define AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS true #define AZ_TRAIT_DISABLE_FAILED_ATOM_RPI_TESTS true #define AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS true From e3306f948f0fce67c2fbb47b5f84b132555a22cc Mon Sep 17 00:00:00 2001 From: smurly Date: Mon, 6 Dec 2021 09:18:16 -0800 Subject: [PATCH 104/128] Atom Level component test support in editor_entity_utils.py and tests for level components (#6082) * Level component helper and test cases for Atom Level components which currently crash Signed-off-by: Scott Murray * moved a close paren to end of previous line to match existing style Signed-off-by: Scott Murray * adding a forgotten import Signed-off-by: Scott Murray * minor refactor and prep for adding back the Display Mapper Game component test Signed-off-by: Scott Murray * putting Game compoenent Display Mapper test back with addition of setting property Enabled to true Signed-off-by: Scott Murray * typo in line fixed Test. bocomes Tests. Signed-off-by: Scott Murray --- .../Gem/PythonTests/Atom/TestSuite_Sandbox.py | 15 +++ .../Atom/atom_utils/atom_constants.py | 26 +++- ...ntsLevel_DiffuseGlobalIlluminationAdded.py | 109 +++++++++++++++ ...ditorComponentsLevel_DisplayMapperAdded.py | 124 ++++++++++++++++++ ...AtomEditorComponents_DisplayMapperAdded.py | 75 ++++++----- .../editor_entity_utils.py | 98 +++++++++++++- 6 files changed, 409 insertions(+), 38 deletions(-) create mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded.py create mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DisplayMapperAdded.py diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py index 292bb9c19c..f0bb6e72ca 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py @@ -12,6 +12,7 @@ import pytest import ly_test_tools.environment.file_system as file_system import editor_python_test_tools.hydra_test_utils as hydra +from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite from Atom.atom_utils.atom_constants import LIGHT_TYPES logger = logging.getLogger(__name__) @@ -159,3 +160,17 @@ class TestMaterialEditorBasicTests(object): enable_prefab_system=False, ) + +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +class TestAutomation(EditorTestSuite): + + enable_prefab_system = False + + @pytest.mark.test_case_id("C36529666") + class AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded as test_module + + @pytest.mark.test_case_id("C36525660") + class AtomEditorComponentsLevel_DisplayMapperAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponentsLevel_DisplayMapperAdded as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py index 290e1cd2e4..c73f75fbc0 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py @@ -18,6 +18,13 @@ LIGHT_TYPES = { 'simple_spot': 7, } +# Qualiity Level settings for Diffuse Global Illumination level component +GLOBAL_ILLUMINATION_QUALITY = { + 'Low': 0, + 'Medium': 1, + 'High': 2, +} + class AtomComponentProperties: """ @@ -116,6 +123,21 @@ class AtomComponentProperties: } return properties[property] + @staticmethod + def diffuse_global_illumination(property: str = 'name') -> str: + """ + Diffuse Global Illumination level component properties. + Controls global settings for Diffuse Probe Grid components. + - 'Quality Level' from atom_constants.py GLOBAL_ILLUMINATION_QUALITY + :param property: From the last element of the property tree path. Default 'name' for component name string. + :return: Full property path OR component name if no property specified. + """ + properties = { + 'name': 'Diffuse Global Illumination', + 'Quality Level': 'Controller|Configuration|Quality Level' + } + return properties[property] + @staticmethod def diffuse_probe_grid(property: str = 'name') -> str: """ @@ -148,7 +170,8 @@ class AtomComponentProperties: @staticmethod def display_mapper(property: str = 'name') -> str: """ - Display Mapper component properties. + Display Mapper level component properties. + - 'Enable LDR color grading LUT' toggles the use of LDR color grading LUT - 'LDR color Grading LUT' is the Low Definition Range (LDR) color grading for Look-up Textures (LUT) which is an Asset.id value corresponding to a lighting asset file. :param property: From the last element of the property tree path. Default 'name' for component name string. @@ -156,6 +179,7 @@ class AtomComponentProperties: """ properties = { 'name': 'Display Mapper', + 'Enable LDR color grading LUT': 'Controller|Configuration|Enable LDR color grading LUT', 'LDR color Grading LUT': 'Controller|Configuration|LDR color Grading LUT', } return properties[property] diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded.py new file mode 100644 index 0000000000..ddcd5c3c46 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded.py @@ -0,0 +1,109 @@ +""" +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 +""" + +class Tests: + creation_undo = ( + "UNDO Level component addition success", + "UNDO Level component addition failed") + creation_redo = ( + "REDO Level component addition success", + "REDO Level component addition failed") + diffuse_global_illumination_component = ( + "Level has a Diffuse Global Illumination component", + "Level failed to find Diffuse Global Illumination component") + diffuse_global_illumination_quality = ( + "Quality Level set", + "Quality Level could not be set") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + + +def AtomEditorComponentsLevel_DiffuseGlobalIllumination_AddedToEntity(): + """ + Summary: + Tests the Diffuse Global Illumination level component can be added to the level entity and is stable. + + Test setup: + - Wait for Editor idle loop. + - Open the "Base" level. + + Expected Behavior: + The component can be added, used in game mode, and has accurate required components. + Creation and deletion undo/redo should also work. + + Test Steps: + 1) Add Diffuse Global Illumination level component to the level entity. + 2) UNDO the level component addition. + 3) REDO the level component addition. + 4) Set Quality Level property to Low + 5) Enter/Exit game mode. + 6) Look for errors and asserts. + + :return: None + """ + + import azlmbr.legacy.general as general + + from editor_python_test_tools.editor_entity_utils import EditorLevelEntity + from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties, GLOBAL_ILLUMINATION_QUALITY + + with Tracer() as error_tracer: + # Test setup begins. + # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. + TestHelper.init_idle() + TestHelper.open_level("", "Base") + + # Test steps begin. + # 1. Add Diffuse Global Illumination level component to the level entity. + diffuse_global_illumination_component = EditorLevelEntity.add_component( + AtomComponentProperties.diffuse_global_illumination()) + Report.critical_result( + Tests.diffuse_global_illumination_component, + EditorLevelEntity.has_component(AtomComponentProperties.diffuse_global_illumination())) + + # 2. UNDO the level component addition. + # -> UNDO component addition. + general.undo() + general.idle_wait_frames(1) + Report.result(Tests.creation_undo, + not EditorLevelEntity.has_component(AtomComponentProperties.diffuse_global_illumination())) + + # 3. REDO the level component addition. + # -> REDO component addition. + general.redo() + general.idle_wait_frames(1) + Report.result(Tests.creation_redo, + EditorLevelEntity.has_component(AtomComponentProperties.diffuse_global_illumination())) + + # 4. Set Quality Level property to Low + diffuse_global_illumination_component.set_component_property_value( + AtomComponentProperties.diffuse_global_illumination('Quality Level', GLOBAL_ILLUMINATION_QUALITY['Low'])) + quality = diffuse_global_illumination_component.get_component_property_value( + AtomComponentProperties.diffuse_global_illumination('Quality Level')) + Report.result(diffuse_global_illumination_quality, quality == GLOBAL_ILLUMINATION_QUALITY['Low']) + + # 5. Enter/Exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + general.idle_wait_frames(1) + TestHelper.exit_game_mode(Tests.exit_game_mode) + + # 6. Look for errors and asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") + + +if __name__ == "__main__": + from editor_python_test_tools.utils import Report + Report.start_test(AtomEditorComponentsLevel_DiffuseGlobalIllumination_AddedToEntity) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DisplayMapperAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DisplayMapperAdded.py new file mode 100644 index 0000000000..c050dd76d4 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DisplayMapperAdded.py @@ -0,0 +1,124 @@ +""" +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 +""" + + +class Tests: + creation_undo = ( + "UNDO level component addition success", + "UNDO level component addition failed") + creation_redo = ( + "REDO Level component addition success", + "REDO Level component addition failed") + display_mapper_component = ( + "Level has a Display Mapper component", + "Level failed to find Display Mapper component") + ldr_color_grading_lut = ( + "LDR color Grading LUT asset set", + "LDR color Grading LUT asset could not be set") + enable_ldr_color_grading_lut = ( + "Enable LDR color grading LUT set", + "Enable LDR color grading LUT could not be set") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + + +def AtomEditorComponentsLevel_DisplayMapper_AddedToEntity(): + """ + Summary: + Tests the Display Mapper level component can be added to the level entity and has the expected functionality. + + Test setup: + - Wait for Editor idle loop. + - Open the "Base" level. + + Expected Behavior: + The component can be added, used in game mode, and has accurate required components. + Creation and deletion undo/redo should also work. + + Test Steps: + 1) Add Display Mapper level component to the level entity. + 2) UNDO the level component addition. + 3) REDO the level component addition. + 4) Set LDR color Grading LUT asset. + 5) Set Enable LDR color grading LUT property True + 6) Enter/Exit game mode. + 7) Look for errors and asserts. + + :return: None + """ + import os + + import azlmbr.legacy.general as general + + from editor_python_test_tools.asset_utils import Asset + from editor_python_test_tools.editor_entity_utils import EditorLevelEntity + from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties + + with Tracer() as error_tracer: + # Test setup begins. + # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. + TestHelper.init_idle() + TestHelper.open_level("", "Base") + + # Test steps begin. + # 1. Add Display Mapper level component to the level entity. + display_mapper_component = EditorLevelEntity.add_component(AtomComponentProperties.display_mapper()) + Report.critical_result( + Tests.display_mapper_component, + EditorLevelEntity.has_component(AtomComponentProperties.display_mapper())) + + # 2. UNDO the level component addition. + # -> UNDO component addition. + general.undo() + general.idle_wait_frames(1) + Report.result(Tests.creation_undo, not EditorLevelEntity.has_component(AtomComponentProperties.display_mapper())) + + # 3. REDO the level component addition. + # -> REDO component addition. + general.redo() + general.idle_wait_frames(1) + Report.result(Tests.creation_redo, EditorLevelEntity.has_component(AtomComponentProperties.display_mapper())) + + # 4. Set LDR color Grading LUT asset. + display_mapper_asset_path = os.path.join("TestData", "test.lightingpreset.azasset") + display_mapper_asset = Asset.find_asset_by_path(display_mapper_asset_path, False) + display_mapper_component.set_component_property_value( + AtomComponentProperties.display_mapper('LDR color Grading LUT'), display_mapper_asset.id) + Report.result( + Tests.ldr_color_grading_lut, + display_mapper_component.get_component_property_value( + AtomComponentProperties.display_mapper('LDR color Grading LUT')) == display_mapper_asset.id) + + # 5. Set Enable LDR color grading LUT property True + display_mapper_component.set_component_property_value( + AtomComponentProperties.display_mapper('Enable LDR color grading LUT'), True) + Report.result( + Test.enable_ldr_color_grading_lut, + display_mapper_component.get_component_property_value( + AtomComponentProperties.display_mapper('Enable LDR color grading LUT')) is True) + + # 6. Enter/Exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + general.idle_wait_frames(1) + TestHelper.exit_game_mode(Tests.exit_game_mode) + + # 7. Look for errors and asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") + + +if __name__ == "__main__": + from editor_python_test_tools.utils import Report + Report.start_test(AtomEditorComponentsLevel_DisplayMapper_AddedToEntity) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py index e2e432364d..558d69046e 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py @@ -7,15 +7,6 @@ SPDX-License-Identifier: Apache-2.0 OR MIT class Tests: - camera_creation = ( - "Camera Entity successfully created", - "Camera Entity failed to be created") - camera_component_added = ( - "Camera component was added to entity", - "Camera component failed to be added to entity") - camera_component_check = ( - "Entity has a Camera component", - "Entity failed to find Camera component") creation_undo = ( "UNDO Entity creation success", "UNDO Entity creation failed") @@ -43,6 +34,9 @@ class Tests: ldr_color_grading_lut = ( "LDR color Grading LUT asset set", "LDR color Grading LUT asset could not be set") + enable_ldr_color_grading_lut = ( + "Enable LDR color grading LUT set", + "Enable LDR color grading LUT could not be set") entity_deleted = ( "Entity deleted", "Entity was not deleted") @@ -72,14 +66,15 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity(): 2) Add Display Mapper component to Display Mapper entity. 3) UNDO the entity creation and component addition. 4) REDO the entity creation and component addition. - 5) Enter/Exit game mode. - 6) Test IsHidden. - 7) Test IsVisible. - 8) Set LDR color Grading LUT asset. - 9) Delete Display Mapper entity. - 10) UNDO deletion. - 11) REDO deletion. - 12) Look for errors and asserts. + 5) Set LDR color Grading LUT asset. + 6) Set Enable LDR color grading LUT property True + 7) Enter/Exit game mode. + 8) Test IsHidden. + 9) Test IsVisible. + 10) Delete Display Mapper entity. + 11) UNDO deletion. + 12) REDO deletion. + 13) Look for errors and asserts. :return: None """ @@ -133,21 +128,7 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity(): general.idle_wait_frames(1) Report.result(Tests.creation_redo, display_mapper_entity.exists()) - # 5. Enter/Exit game mode. - TestHelper.enter_game_mode(Tests.enter_game_mode) - general.idle_wait_frames(1) - TestHelper.exit_game_mode(Tests.exit_game_mode) - - # 6. Test IsHidden. - display_mapper_entity.set_visibility_state(False) - Report.result(Tests.is_hidden, display_mapper_entity.is_hidden() is True) - - # 7. Test IsVisible. - display_mapper_entity.set_visibility_state(True) - general.idle_wait_frames(1) - Report.result(Tests.is_visible, display_mapper_entity.is_visible() is True) - - # 8. Set LDR color Grading LUT asset. + # 5. Set LDR color Grading LUT asset. display_mapper_asset_path = os.path.join("TestData", "test.lightingpreset.azasset") display_mapper_asset = Asset.find_asset_by_path(display_mapper_asset_path, False) display_mapper_component.set_component_property_value( @@ -157,19 +138,41 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity(): display_mapper_component.get_component_property_value( AtomComponentProperties.display_mapper("LDR color Grading LUT")) == display_mapper_asset.id) - # 9. Delete Display Mapper entity. + # 6. Set Enable LDR color grading LUT property True + display_mapper_component.set_component_property_value( + AtomComponentProperties.display_mapper('Enable LDR color grading LUT'), True) + Report.result( + Tests.enable_ldr_color_grading_lut, + display_mapper_component.get_component_property_value( + AtomComponentProperties.display_mapper('Enable LDR color grading LUT')) is True) + + # 7. Enter/Exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + general.idle_wait_frames(1) + TestHelper.exit_game_mode(Tests.exit_game_mode) + + # 8. Test IsHidden. + display_mapper_entity.set_visibility_state(False) + Report.result(Tests.is_hidden, display_mapper_entity.is_hidden() is True) + + # 9. Test IsVisible. + display_mapper_entity.set_visibility_state(True) + general.idle_wait_frames(1) + Report.result(Tests.is_visible, display_mapper_entity.is_visible() is True) + + # 10. Delete Display Mapper entity. display_mapper_entity.delete() Report.result(Tests.entity_deleted, not display_mapper_entity.exists()) - # 10. UNDO deletion. + # 11. UNDO deletion. general.undo() Report.result(Tests.deletion_undo, display_mapper_entity.exists()) - # 11. REDO deletion. + # 12. REDO deletion. general.redo() Report.result(Tests.deletion_redo, not display_mapper_entity.exists()) - # 12. Look for errors and asserts. + # 13. Look for errors and asserts. TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) for error_info in error_tracer.errors: Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py index 309601b0ba..2d1c34b9c4 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py @@ -107,7 +107,6 @@ class EditorComponent: return type_ids - def convert_to_azvector3(xyz) -> azlmbr.math.Vector3: """ Converts a vector3-like element into a azlmbr.math.Vector3 @@ -120,6 +119,7 @@ def convert_to_azvector3(xyz) -> azlmbr.math.Vector3: else: raise ValueError("vector must be a 3 element list/tuple or azlmbr.math.Vector3") + class EditorEntity: """ Entity class is used to create and interact with Editor Entities. @@ -470,3 +470,99 @@ class EditorEntity: assert self.id.isValid(), "A valid entity id is required to focus on its owning prefab." focus_prefab_result = azlmbr.prefab.PrefabFocusPublicRequestBus(bus.Broadcast, "FocusOnOwningPrefab", self.id) assert focus_prefab_result.IsSuccess(), f"Prefab operation 'FocusOnOwningPrefab' failed. Error: {focus_prefab_result.GetError()}" + + +class EditorLevelEntity: + """ + EditorLevel class used to add and fetch level components. + Level entity is a special entity that you do not create/destroy independently of larger systems of level creation. + This collects a number of staticmethods that do not rely on entityId since Level entity is found internally by + EditorLevelComponentAPIBus requests. + """ + + @staticmethod + def get_type_ids(component_names: list) -> list: + """ + Used to get type ids of given components list for EntityType Level + :param: component_names: List of components to get type ids + :return: List of type ids of given components. + """ + type_ids = editor.EditorComponentAPIBus( + bus.Broadcast, "FindComponentTypeIdsByEntityType", component_names, azlmbr.entity.EntityType().Level + ) + return type_ids + + @staticmethod + def add_component(component_name: str) -> EditorComponent: + """ + Used to add new component to Level. + :param component_name: String of component name to add. + :return: Component object of newly added component. + """ + component = EditorLevelEntity.add_components([component_name])[0] + return component + + @staticmethod + def add_components(component_names: list) -> List[EditorComponent]: + """ + Used to add multiple components + :param: component_names: List of components to add to level + :return: List of newly added components to the level + """ + components = [] + type_ids = EditorLevelEntity.get_type_ids(component_names) + for type_id in type_ids: + new_comp = EditorComponent() + new_comp.type_id = type_id + add_component_outcome = editor.EditorLevelComponentAPIBus( + bus.Broadcast, "AddComponentsOfType", [type_id] + ) + assert ( + add_component_outcome.IsSuccess() + ), f"Failure: Could not add component: '{new_comp.get_component_name()}' to level" + new_comp.id = add_component_outcome.GetValue()[0] + components.append(new_comp) + return components + + @staticmethod + def get_components_of_type(component_names: list) -> List[EditorComponent]: + """ + Used to get components of type component_name that already exists on the level + :param component_names: List of names of components to check + :return: List of Level Component objects of given component name + """ + component_list = [] + type_ids = EditorLevelEntity.get_type_ids(component_names) + for type_id in type_ids: + component = EditorComponent() + component.type_id = type_id + get_component_of_type_outcome = editor.EditorLevelComponentAPIBus( + bus.Broadcast, "GetComponentOfType", type_id + ) + assert ( + get_component_of_type_outcome.IsSuccess() + ), f"Failure: Level does not have component:'{component.get_component_name()}'" + component.id = get_component_of_type_outcome.GetValue() + component_list.append(component) + + return component_list + + @staticmethod + def has_component(component_name: str) -> bool: + """ + Used to verify if the level has the specified component + :param component_name: Name of component to check for + :return: True, if level has specified component. Else, False + """ + type_ids = EditorLevelEntity.get_type_ids([component_name]) + return editor.EditorLevelComponentAPIBus(bus.Broadcast, "HasComponentOfType", type_ids[0]) + + @staticmethod + def count_components_of_type(component_name: str) -> int: + """ + Used to get a count of the specified level component attached to the level + :param component_name: Name of component to check for + :return: integer count of occurences of level component attached to level or zero if none are present + """ + type_ids = EditorLevelEntity.get_type_ids([component_name]) + return editor.EditorLevelComponentAPIBus(bus.Broadcast, "CountComponentsOfType", type_ids[0]) From 83cb085a2863c9d2f260b9346eb8a81f640518bb Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Mon, 6 Dec 2021 11:24:04 -0600 Subject: [PATCH 105/128] Fixed the register.py command with a --project-path to check against a (#6158) supplied --engine-path parameter to determine if it should update the project.json if one has been provided. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- scripts/o3de/o3de/register.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/o3de/o3de/register.py b/scripts/o3de/o3de/register.py index 2500df1568..62a342f948 100644 --- a/scripts/o3de/o3de/register.py +++ b/scripts/o3de/o3de/register.py @@ -411,7 +411,7 @@ def register_project_path(json_data: dict, if not remove: # registering a project has the additional step of setting the project.json 'engine' field - this_engine_json = manifest.get_engine_json_data(engine_path=manifest.get_this_engine_path()) + this_engine_json = manifest.get_engine_json_data(engine_path=engine_path if engine_path else manifest.get_this_engine_path()) if not this_engine_json: return 1 project_json_data = manifest.get_project_json_data(project_path=project_path) From 1f279ca7131192207c60bfbc6629cf2079222eb2 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Mon, 6 Dec 2021 12:19:02 -0600 Subject: [PATCH 106/128] Updated viewport to hide the transform maniuplators for entities marked as read only. Signed-off-by: Chris Galvan --- .../EditorTransformComponentSelection.cpp | 27 +++++++++++++++++++ .../EditorTransformComponentSelection.h | 5 ++++ 2 files changed, 32 insertions(+) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index f43e8225a6..14344f33f9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -1019,6 +1020,7 @@ namespace AzToolsFramework EditorManipulatorCommandUndoRedoRequestBus::Handler::BusConnect(entityContextId); EditorContextMenuBus::Handler::BusConnect(); ViewportInteraction::ViewportSettingsNotificationBus::Handler::BusConnect(ViewportUi::DefaultViewportId); + ReadOnlyEntityPublicNotificationBus::Handler::BusConnect(entityContextId); CreateTransformModeSelectionCluster(); CreateSpaceSelectionCluster(); @@ -1054,6 +1056,7 @@ namespace AzToolsFramework m_pivotOverrideFrame.Reset(); + ReadOnlyEntityPublicNotificationBus::Handler::BusDisconnect(); ViewportInteraction::ViewportSettingsNotificationBus::Handler::BusDisconnect(); EditorContextMenuBus::Handler::BusConnect(); EditorManipulatorCommandUndoRedoRequestBus::Handler::BusDisconnect(); @@ -3623,6 +3626,22 @@ namespace AzToolsFramework m_selectedEntityIds.erase(focusRoot); } } + + // Do not create maniuplators for any entities marked as read only + if (auto readOnlyEntityPublicInterface = AZ::Interface::Get()) + { + for (auto it = m_selectedEntityIds.begin(); it != m_selectedEntityIds.end();) + { + if (readOnlyEntityPublicInterface->IsReadOnly(*it)) + { + it = m_selectedEntityIds.erase(it); + } + else + { + ++it; + } + } + } } void EditorTransformComponentSelection::OnTransformChanged( @@ -3830,6 +3849,14 @@ namespace AzToolsFramework m_snappingCluster.TrySetVisible(m_viewportUiVisible && !m_selectedEntityIds.empty()); } + void EditorTransformComponentSelection::OnReadOnlyEntityStatusChanged(const AZ::EntityId& entityId, [[maybe_unused]] bool readOnly) + { + if (IsEntitySelected(entityId)) + { + RefreshSelectedEntityIdsAndRegenerateManipulators(); + } + } + namespace ETCS { // little raii wrapper to switch a value from true to false and back diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h index afc290380b..7b3ba08894 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -160,6 +161,7 @@ namespace AzToolsFramework , private EditorManipulatorCommandUndoRedoRequestBus::Handler , private AZ::TransformNotificationBus::MultiHandler , private ViewportInteraction::ViewportSettingsNotificationBus::Handler + , private ReadOnlyEntityPublicNotificationBus::Handler { public: AZ_CLASS_ALLOCATOR_DECL @@ -297,6 +299,9 @@ namespace AzToolsFramework // ViewportSettingsNotificationBus overrides ... void OnGridSnappingChanged(bool enabled) override; + // ReadOnlyEntityPublicNotificationBus overrides ... + void OnReadOnlyEntityStatusChanged(const AZ::EntityId& entityId, bool readOnly) override; + // Helpers to safely interact with the TransformBus (requests). void SetEntityWorldTranslation(AZ::EntityId entityId, const AZ::Vector3& worldTranslation); void SetEntityLocalTranslation(AZ::EntityId entityId, const AZ::Vector3& localTranslation); From 1c42cd98cc11277a3c0a0f634e7e0a58e975409c Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Mon, 6 Dec 2021 10:31:35 -0800 Subject: [PATCH 107/128] Address a bit more review feedback Signed-off-by: Nicholas Van Sickle --- .../AzCore/DOM/Backends/JSON/JsonBackend.h | 2 +- .../Backends/JSON/JsonSerializationUtils.cpp | 44 +++++++++---------- .../Backends/JSON/JsonSerializationUtils.h | 6 +-- 3 files changed, 25 insertions(+), 27 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h index 1c8f4eb607..af8e4e114c 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h @@ -35,7 +35,7 @@ namespace AZ::Dom Visitor::Result WriteToStream(AZ::IO::GenericStream& stream, WriteCallback callback) override { AZStd::unique_ptr visitor = Json::CreateJsonStreamWriter(stream, WriteFormat); - return callback(*visitor.get()); + return callback(*visitor); } }; } // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp index e1db5be29e..17f9bfea54 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.cpp @@ -95,18 +95,19 @@ namespace AZ::Dom::Json return VisitorFailure(VisitorErrorCode::InternalError, "EndObject called without a matching BeginObject call"); } - if (!m_entryStack.front().m_isObject) + const ValueInfo& frontEntry = m_entryStack.front(); + if (!frontEntry.m_isObject) { return VisitorFailure(VisitorErrorCode::InternalError, "Expected EndArray and received EndObject instead"); } - if (m_entryStack.front().m_entryCount != attributeCount) + if (frontEntry.m_entryCount != attributeCount) { return VisitorFailure( VisitorErrorCode::InternalError, AZStd::string::format( "EndObject: Expected %llu attributes but received %llu attributes instead", attributeCount, - m_entryStack.front().m_entryCount)); + frontEntry.m_entryCount)); } m_entryStack.pop_front(); @@ -149,17 +150,18 @@ namespace AZ::Dom::Json return VisitorFailure(VisitorErrorCode::InternalError, "EndArray called without a matching BeginArray call"); } - if (m_entryStack.front().m_isObject) + const ValueInfo& frontEntry = m_entryStack.front(); + if (frontEntry.m_isObject) { return VisitorFailure(VisitorErrorCode::InternalError, "Expected EndObject and received EndArray instead"); } - if (m_entryStack.front().m_entryCount != elementCount) + if (frontEntry.m_entryCount != elementCount) { return VisitorFailure( VisitorErrorCode::InternalError, AZStd::string::format( - "EndArray: Expected %llu elements but received %llu elements instead", elementCount, m_entryStack.front().m_entryCount)); + "EndArray: Expected %llu elements but received %llu elements instead", elementCount, frontEntry.m_entryCount)); } m_entryStack.pop_front(); @@ -176,16 +178,17 @@ namespace AZ::Dom::Json // Retrieve the top value of the stack and replace it with a null value rapidjson::Value value; m_entryStack.front().m_value.Swap(value); - ++m_entryStack.front().m_entryCount; + ValueInfo& newEntry = m_entryStack.front(); + ++newEntry.m_entryCount; - if (m_entryStack.front().m_key.IsString()) + if (newEntry.m_key.IsString()) { - m_entryStack.front().m_container.AddMember(m_entryStack.front().m_key.Move(), AZStd::move(value), m_allocator); - m_entryStack.front().m_key.SetNull(); + newEntry.m_container.AddMember(m_entryStack.front().m_key.Move(), AZStd::move(value), m_allocator); + newEntry.m_key.SetNull(); } else { - m_entryStack.front().m_container.PushBack(AZStd::move(value), m_allocator); + newEntry.m_container.PushBack(AZStd::move(value), m_allocator); } return VisitorSuccess(); @@ -358,11 +361,7 @@ namespace AZ::Dom::Json bool RapidJsonReadHandler::String(const char* str, rapidjson::SizeType length, bool copy) { - Lifetime lifetime = m_stringLifetime; - if (!copy) - { - lifetime = Lifetime::Temporary; - } + const Lifetime lifetime = copy ? m_stringLifetime : Lifetime::Temporary; return CheckResult(m_visitor->String(AZStd::string_view(str, length), lifetime)); } @@ -378,11 +377,7 @@ namespace AZ::Dom::Json { m_visitor->Key(AZ::Name(key)); } - Lifetime lifetime = m_stringLifetime; - if (!copy) - { - lifetime = Lifetime::Temporary; - } + const Lifetime lifetime = copy ? m_stringLifetime : Lifetime::Temporary; return CheckResult(m_visitor->RawKey(key, lifetime)); } @@ -408,12 +403,15 @@ namespace AZ::Dom::Json bool RapidJsonReadHandler::CheckResult(Visitor::Result result) { - if (!result.IsSuccess()) + if (result.IsSuccess()) + { + return true; + } + else { m_outcome = AZStd::move(result); return false; } - return true; } // diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h index db43395475..af0955dcfe 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonSerializationUtils.h @@ -233,12 +233,12 @@ namespace AZ::Dom::Json if (buffer.data()[buffer.size()] == '\0') { NullDelimitedStringStream stream(buffer); - reader.Parse(parseFlags)>(stream, handler); + reader.Parse(parseFlags)>(stream, handler); } else { rapidjson::MemoryStream stream(buffer.data(), buffer.size()); - reader.Parse(parseFlags)>(stream, handler); + reader.Parse(parseFlags)>(stream, handler); } return handler.TakeOutcome(); } @@ -250,7 +250,7 @@ namespace AZ::Dom::Json NullDelimitedStringStream stream(buffer); RapidJsonReadHandler handler(&visitor, Lifetime::Persistent); - reader.Parse(parseFlags) | rapidjson::kParseInsituFlag>(stream, handler); + reader.Parse(parseFlags) | rapidjson::kParseInsituFlag>(stream, handler); return handler.TakeOutcome(); } } // namespace AZ::Dom::Json From e24323660b0c707813a03336977bdf7e38834583 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Mon, 6 Dec 2021 12:44:52 -0600 Subject: [PATCH 108/128] Fixed typo. Signed-off-by: Chris Galvan --- .../ViewportSelection/EditorTransformComponentSelection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index 14344f33f9..df4f041a51 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -3627,7 +3627,7 @@ namespace AzToolsFramework } } - // Do not create maniuplators for any entities marked as read only + // Do not create manipulators for any entities marked as read only if (auto readOnlyEntityPublicInterface = AZ::Interface::Get()) { for (auto it = m_selectedEntityIds.begin(); it != m_selectedEntityIds.end();) From ea9d7c9d82b400acc292947680a4ad744e7e0ab6 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Mon, 6 Dec 2021 10:45:45 -0800 Subject: [PATCH 109/128] Add optional size parameter to ReadFromBufferInPlace Signed-off-by: Nicholas Van Sickle --- Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h | 2 +- Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp | 4 ++-- Code/Framework/AzCore/AzCore/DOM/DomBackend.h | 3 ++- Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h index af8e4e114c..45825ff92d 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h @@ -27,7 +27,7 @@ namespace AZ::Dom return Json::VisitSerializedJson({ buffer, size }, lifetime, visitor); } - Visitor::Result ReadFromBufferInPlace(char* buffer, Visitor& visitor) override + Visitor::Result ReadFromBufferInPlace(char* buffer, [[maybe_unused]] AZStd::optional size, Visitor& visitor) override { return Json::VisitSerializedJsonInPlace(buffer, visitor); } diff --git a/Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp b/Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp index 8ff0e8a0bb..b29c0be231 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/DomBackend.cpp @@ -10,8 +10,8 @@ namespace AZ::Dom { - Visitor::Result Backend::ReadFromBufferInPlace(char* buffer, Visitor& visitor) + Visitor::Result Backend::ReadFromBufferInPlace(char* buffer, AZStd::optional size, Visitor& visitor) { - return ReadFromBuffer(buffer, strlen(buffer), AZ::Dom::Lifetime::Persistent, visitor); + return ReadFromBuffer(buffer, size.value_or(strlen(buffer)), AZ::Dom::Lifetime::Persistent, visitor); } } // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/DomBackend.h b/Code/Framework/AzCore/AzCore/DOM/DomBackend.h index c70af72652..6c9c40ef0e 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomBackend.h +++ b/Code/Framework/AzCore/AzCore/DOM/DomBackend.h @@ -12,6 +12,7 @@ #include #include #include +#include #include namespace AZ::Dom @@ -32,7 +33,7 @@ namespace AZ::Dom //! - The string won't be deallocated until the visitor no longer needs the values and //! - The string is safe to modify in place. //! The base implementation simply calls ReadFromBuffer. - virtual Visitor::Result ReadFromBufferInPlace(char* buffer, Visitor& visitor); + virtual Visitor::Result ReadFromBufferInPlace(char* buffer, AZStd::optional size, Visitor& visitor); //! A callback that accepts a Visitor, making DOM calls to inform the serializer, and returns an //! aggregate error code to indicate whether or not the operation succeeded. diff --git a/Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp b/Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp index 3c5d4eb668..ca27b177bd 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp @@ -19,7 +19,7 @@ namespace AZ::Dom::Utils Visitor::Result ReadFromStringInPlace(Backend& backend, AZStd::string& string, Visitor& visitor) { - return backend.ReadFromBufferInPlace(string.data(), visitor); + return backend.ReadFromBufferInPlace(string.data(), string.size(), visitor); } Visitor::Result WriteToString(Backend& backend, AZStd::string& buffer, Backend::WriteCallback writeCallback) From a76e9bba694521de537fdc8eca1bcece4085ef51 Mon Sep 17 00:00:00 2001 From: carlitosan <82187351+carlitosan@users.noreply.github.com> Date: Mon, 6 Dec 2021 12:12:46 -0800 Subject: [PATCH 110/128] Restore undo/redo Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com> --- .../Assets/ScriptCanvasFileHandling.cpp | 9 +++- .../Editor/Assets/ScriptCanvasMemoryAsset.cpp | 2 - .../Editor/Assets/ScriptCanvasUndoHelper.cpp | 48 +++++++++++++------ .../Editor/Assets/ScriptCanvasUndoHelper.h | 16 +++++-- .../Code/Editor/Components/EditorGraph.cpp | 1 + .../ScriptCanvas/Components/EditorGraph.h | 2 + .../Editor/Undo/ScriptCanvasGraphCommand.cpp | 14 +++--- .../Editor/Undo/ScriptCanvasGraphCommand.h | 8 ++-- .../Editor/Undo/ScriptCanvasUndoManager.cpp | 4 +- .../Editor/Undo/ScriptCanvasUndoManager.h | 1 + 10 files changed, 68 insertions(+), 37 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp index be909e5043..c4579c9042 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasFileHandling.cpp @@ -252,11 +252,16 @@ namespace ScriptCanvasEditor AZ::u64 entityId = aznumeric_caster(ScriptCanvas::MathNodeUtilities::GetRandomIntegral(1, std::numeric_limits::max())); entity->SetId(AZ::EntityId(entityId)); - entity->Init(); - entity->Activate(); auto graph = entity->FindComponent(); graph->MarkOwnership(*scriptCanvasData); + + entity->Init(); + entity->Activate(); + } + else + { + return AZ::Failure(AZStd::string("Loaded script canvas file was missing a necessary Entity.")); } return AZ::Success(ScriptCanvasEditor::SourceHandle(scriptCanvasData, path)); diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp index 992b33889b..a20a6e54a1 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp @@ -278,8 +278,6 @@ namespace ScriptCanvasEditor EditorGraphNotificationBus::Handler::BusDisconnect(); EditorGraphNotificationBus::Handler::BusConnect(m_scriptCanvasId); - - m_undoHelper = AZStd::make_unique(*this); } ScriptCanvasEditor::Widget::CanvasWidget* ScriptCanvasMemoryAsset::CreateView(QWidget* /*parent*/) diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.cpp index 388da67987..31bdf0077c 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.cpp @@ -9,13 +9,19 @@ #include "ScriptCanvasUndoHelper.h" #include "ScriptCanvasMemoryAsset.h" #include +#include namespace ScriptCanvasEditor { - UndoHelper::UndoHelper(ScriptCanvasMemoryAsset& memoryAsset) - : m_memoryAsset(memoryAsset) + UndoHelper::UndoHelper() + : m_undoState(this) { - UndoRequestBus::Handler::BusConnect(memoryAsset.GetScriptCanvasId()); + } + + UndoHelper::UndoHelper(SourceHandle memoryAsset) + : m_undoState(this) + { + SetSource(memoryAsset); } UndoHelper::~UndoHelper() @@ -23,15 +29,21 @@ namespace ScriptCanvasEditor UndoRequestBus::Handler::BusDisconnect(); } + void UndoHelper::SetSource(SourceHandle source) + { + m_memoryAsset = source; + UndoRequestBus::Handler::BusConnect(source.Get()->GetScriptCanvasId()); + } + ScriptCanvasEditor::UndoCache* UndoHelper::GetSceneUndoCache() { - return m_memoryAsset.GetUndoState()->m_undoCache.get(); + return m_undoState.m_undoCache.get(); } ScriptCanvasEditor::UndoData UndoHelper::CreateUndoData() { - AZ::EntityId graphCanvasGraphId = m_memoryAsset.GetGraphId(); - ScriptCanvas::ScriptCanvasId scriptCanvasId = m_memoryAsset.GetScriptCanvasId(); + AZ::EntityId graphCanvasGraphId = m_memoryAsset.Get()->GetGraphCanvasGraphId(); + ScriptCanvas::ScriptCanvasId scriptCanvasId = m_memoryAsset.Get()->GetScriptCanvasId(); GraphCanvas::GraphModelRequestBus::Event(graphCanvasGraphId, &GraphCanvas::GraphModelRequests::OnSaveDataDirtied, graphCanvasGraphId); @@ -56,17 +68,17 @@ namespace ScriptCanvasEditor void UndoHelper::BeginUndoBatch(AZStd::string_view label) { - m_memoryAsset.GetUndoState()->BeginUndoBatch(label); + m_undoState.BeginUndoBatch(label); } void UndoHelper::EndUndoBatch() { - m_memoryAsset.GetUndoState()->EndUndoBatch(); + m_undoState.EndUndoBatch(); } void UndoHelper::AddUndo(AzToolsFramework::UndoSystem::URSequencePoint* sequencePoint) { - if (SceneUndoState* sceneUndoState = m_memoryAsset.GetUndoState()) + if (SceneUndoState* sceneUndoState = &m_undoState) { if (!sceneUndoState->m_currentUndoBatch) { @@ -105,7 +117,7 @@ namespace ScriptCanvasEditor { AZ_PROFILE_FUNCTION(ScriptCanvas); - SceneUndoState* sceneUndoState = m_memoryAsset.GetUndoState(); + SceneUndoState* sceneUndoState = &m_undoState; if (sceneUndoState) { AZ_Warning("Script Canvas", !sceneUndoState->m_currentUndoBatch, "Script Canvas Editor has an open undo batch when performing a redo operation"); @@ -125,7 +137,7 @@ namespace ScriptCanvasEditor { AZ_PROFILE_FUNCTION(ScriptCanvas); - SceneUndoState* sceneUndoState = m_memoryAsset.GetUndoState(); + SceneUndoState* sceneUndoState = &m_undoState; if (sceneUndoState) { AZ_Warning("Script Canvas", !sceneUndoState->m_currentUndoBatch, "Script Canvas Editor has an open undo batch when performing a redo operation"); @@ -143,7 +155,7 @@ namespace ScriptCanvasEditor void UndoHelper::Reset() { - if (SceneUndoState* sceneUndoState = m_memoryAsset.GetUndoState()) + if (SceneUndoState* sceneUndoState = &m_undoState) { AZ_Warning("Script Canvas", !sceneUndoState->m_currentUndoBatch, "Script Canvas Editor has an open undo batch when resetting the undo stack"); sceneUndoState->m_undoStack->Reset(); @@ -162,17 +174,23 @@ namespace ScriptCanvasEditor bool UndoHelper::CanUndo() const { - return m_memoryAsset.GetUndoState()->m_undoStack->CanUndo(); + return m_undoState.m_undoStack->CanUndo(); } bool UndoHelper::CanRedo() const { - return m_memoryAsset.GetUndoState()->m_undoStack->CanRedo(); + return m_undoState.m_undoStack->CanRedo(); + } + + void UndoHelper::OnUndoStackChanged() + { + UndoNotificationBus::Broadcast(&UndoNotifications::OnCanUndoChanged, m_undoState.m_undoStack->CanUndo()); + UndoNotificationBus::Broadcast(&UndoNotifications::OnCanRedoChanged, m_undoState.m_undoStack->CanRedo()); } void UndoHelper::UpdateCache() { - ScriptCanvas::ScriptCanvasId scriptCanvasId = m_memoryAsset.GetScriptCanvasId(); + ScriptCanvas::ScriptCanvasId scriptCanvasId = m_memoryAsset.Get()->GetScriptCanvasId(); UndoCache* undoCache = nullptr; UndoRequestBus::EventResult(undoCache, scriptCanvasId, &UndoRequests::GetSceneUndoCache); diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.h b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.h index 7bf5c8b630..3652b07686 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.h +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.h @@ -8,22 +8,27 @@ #pragma once #include +#include namespace ScriptCanvasEditor { - class ScriptCanvasMemoryAsset; // Helper class that provides the implementation for UndoRequestBus - class UndoHelper : UndoRequestBus::Handler + class UndoHelper + : public UndoRequestBus::Handler + , public AzToolsFramework::UndoSystem::IUndoNotify { public: - UndoHelper(ScriptCanvasMemoryAsset& memoryAsset); + UndoHelper(); + UndoHelper(SourceHandle source); ~UndoHelper(); UndoCache* GetSceneUndoCache() override; UndoData CreateUndoData() override; + void SetSource(SourceHandle source); + void BeginUndoBatch(AZStd::string_view label) override; void EndUndoBatch() override; void AddUndo(AzToolsFramework::UndoSystem::URSequencePoint* seqPoint) override; @@ -41,6 +46,7 @@ namespace ScriptCanvasEditor bool CanRedo() const override; private: + void OnUndoStackChanged() override; void UpdateCache(); @@ -51,7 +57,7 @@ namespace ScriptCanvasEditor }; Status m_status = Status::Idle; - - ScriptCanvasMemoryAsset& m_memoryAsset; + SceneUndoState m_undoState; + SourceHandle m_memoryAsset; }; } diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp index 79621bbddb..a46b2a4a5c 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp @@ -1067,6 +1067,7 @@ namespace ScriptCanvasEditor void Graph::MarkOwnership(ScriptCanvas::ScriptCanvasData& owner) { m_owner = &owner; + m_undoHelper.SetSource(SourceHandle(GetOwnership(), {}, "")); } ScriptCanvas::DataPtr Graph::GetOwnership() const diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h index a969187743..9157aaeac9 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h @@ -34,6 +34,7 @@ #include #include +#include namespace ScriptCanvas { @@ -380,6 +381,7 @@ namespace ScriptCanvasEditor GraphCanvas::NodeFocusCyclingHelper m_focusHelper; GraphStatisticsHelper m_statisticsHelper; + UndoHelper m_undoHelper; bool m_ignoreSaveRequests; diff --git a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.cpp b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.cpp index 4e3e0c85ad..406e139ef1 100644 --- a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -19,7 +20,6 @@ #include #include -#include namespace ScriptCanvasEditor { @@ -36,7 +36,7 @@ namespace ScriptCanvasEditor { } - void GraphItemCommand::Capture(ScriptCanvasMemoryAsset&, bool) + void GraphItemCommand::Capture(SourceHandle&, bool) { } @@ -105,10 +105,10 @@ namespace ScriptCanvasEditor RestoreItem(m_redoState); } - void GraphItemChangeCommand::Capture(ScriptCanvasMemoryAsset& memoryAsset, bool captureUndo) + void GraphItemChangeCommand::Capture(SourceHandle& memoryAsset, bool captureUndo) { - m_scriptCanvasId = memoryAsset.GetScriptCanvasId(); - m_graphCanvasGraphId = memoryAsset.GetGraphId(); + m_scriptCanvasId = memoryAsset.Get()->GetScriptCanvasId(); + m_graphCanvasGraphId = memoryAsset.Get()->GetGraphCanvasGraphId(); UndoCache* undoCache = nullptr; UndoRequestBus::EventResult(undoCache, m_scriptCanvasId, &UndoRequests::GetSceneUndoCache); @@ -204,7 +204,7 @@ namespace ScriptCanvasEditor RestoreItem(m_redoState); } - void GraphItemAddCommand::Capture(ScriptCanvasMemoryAsset& memoryAsset, bool) + void GraphItemAddCommand::Capture(SourceHandle& memoryAsset, bool) { GraphItemChangeCommand::Capture(memoryAsset, false); } @@ -225,7 +225,7 @@ namespace ScriptCanvasEditor RestoreItem(m_redoState); } - void GraphItemRemovalCommand::Capture(ScriptCanvasMemoryAsset& memoryAsset, bool) + void GraphItemRemovalCommand::Capture(SourceHandle& memoryAsset, bool) { GraphItemChangeCommand::Capture(memoryAsset, true); } diff --git a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.h b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.h index e0f5adde7e..61102f690c 100644 --- a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.h +++ b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.h @@ -46,7 +46,7 @@ namespace ScriptCanvasEditor void Undo() override; void Redo() override; - virtual void Capture(ScriptCanvasMemoryAsset& memoryAsset, bool captureUndo); + virtual void Capture(SourceHandle& memoryAsset, bool captureUndo); bool Changed() const override; @@ -76,7 +76,7 @@ namespace ScriptCanvasEditor void Undo() override; void Redo() override; - void Capture(ScriptCanvasMemoryAsset& memoryAsset, bool captureUndo) override; + void Capture(SourceHandle& memoryAsset, bool captureUndo) override; void RestoreItem(const AZStd::vector& restoreBuffer) override; @@ -103,7 +103,7 @@ namespace ScriptCanvasEditor void Undo() override; void Redo() override; - void Capture(ScriptCanvasMemoryAsset& memoryAsset, bool captureUndo) override; + void Capture(SourceHandle& memoryAsset, bool captureUndo) override; protected: GraphItemAddCommand(const GraphItemAddCommand&) = delete; @@ -124,7 +124,7 @@ namespace ScriptCanvasEditor void Undo() override; void Redo() override; - void Capture(ScriptCanvasMemoryAsset& memoryAsset, bool captureUndo) override; + void Capture(SourceHandle& memoryAsset, bool captureUndo) override; protected: GraphItemRemovalCommand(const GraphItemRemovalCommand&) = delete; diff --git a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasUndoManager.cpp b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasUndoManager.cpp index 4d24720227..5a01507352 100644 --- a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasUndoManager.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasUndoManager.cpp @@ -28,9 +28,9 @@ namespace ScriptCanvasEditor // SceneUndoState SceneUndoState::SceneUndoState(AzToolsFramework::UndoSystem::IUndoNotify* undoNotify) - : m_undoStack(AZStd::make_unique(c_undoLimit, undoNotify)) - , m_undoCache(AZStd::make_unique()) { + m_undoStack = AZStd::make_unique(c_undoLimit, undoNotify); + m_undoCache = AZStd::make_unique(); } void SceneUndoState::BeginUndoBatch(AZStd::string_view label) diff --git a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasUndoManager.h b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasUndoManager.h index 52d7b1de3e..1d207e9408 100644 --- a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasUndoManager.h +++ b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasUndoManager.h @@ -61,6 +61,7 @@ namespace ScriptCanvasEditor public: AZ_CLASS_ALLOCATOR(SceneUndoState, AZ::SystemAllocator, 0); + SceneUndoState() = default; SceneUndoState(AzToolsFramework::UndoSystem::IUndoNotify* undoNotify); ~SceneUndoState(); From 476e66d902bd31247f792d6615576ffdd69b5d1b Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Mon, 6 Dec 2021 12:16:16 -0800 Subject: [PATCH 111/128] LYN-8631 + LYN-8632 | Display appropriate read-only icons and procedural prefabs ui in the Outliner (#6160) * First step of procedural prefab styling and read-only registration. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * WIP - Introduce read-only handler for procedural prefabs (not hooked up) Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Introduce read-only entity interface, handler and unit tests. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Introduce temp read-only icon, use new icon hierarchy in Outliner. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Switch from a push paradigm to a pull paradigm - handlers get to implement logic to determine if an entity should be read-only. This allows multiple systems to weigh into whether an entity is read-only. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Fixed to missing call in test Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Post-rebase fixes to class name changes Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Display a lock icon on top of the entity icon in the Entity Outliner. This icon is added programmatically, which prevents having to alter all Outliner icons and future-proofs this functionality. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Minor style changes to procedural prefabs in the Outliner (use white icon) Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Ensure cache is refreshed when the handler is created, and also whenever the focus changes. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Remove Procedural Prefab setreg that was added in the wrong place Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Remove redundant function Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Fix spacing issue caused by rebase Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Change tooltip so that it accurately says "inspect" instead of "edit" for procedural prefabs. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Address minor styling issues mentioned in PR. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../Entity/prefab_edit_open_readonly.svg | 3 + .../AzQtComponents/Images/Entity/readonly.svg | 3 + .../AzQtComponents/Images/resources.qrc | 2 + .../ReadOnly/ReadOnlyEntitySystemComponent.h | 4 +- .../Prefab/PrefabFocusHandler.cpp | 16 +++++ .../Prefab/PrefabFocusHandler.h | 2 + .../Prefab/PrefabPublicHandler.cpp | 12 ++++ .../Prefab/PrefabPublicHandler.h | 1 + .../Prefab/PrefabPublicInterface.h | 7 ++ .../UI/Outliner/EntityOutlinerListModel.cpp | 37 ++++++++-- .../UI/Outliner/EntityOutlinerListModel.hxx | 15 +++- .../UI/Prefab/PrefabIntegrationManager.cpp | 10 ++- .../UI/Prefab/PrefabIntegrationManager.h | 13 +++- .../UI/Prefab/PrefabUiHandler.cpp | 11 --- .../UI/Prefab/PrefabUiHandler.h | 26 +++---- .../ProceduralPrefabReadOnlyHandler.cpp | 68 +++++++++++++++++++ .../ProceduralPrefabReadOnlyHandler.h | 43 ++++++++++++ .../Procedural/ProceduralPrefabUiHandler.cpp | 32 +++++++++ .../Procedural/ProceduralPrefabUiHandler.h | 36 ++++++++++ .../aztoolsframework_files.cmake | 4 ++ .../Entity/ReadOnly/ReadOnlyEntityTests.cpp | 18 +++++ 21 files changed, 325 insertions(+), 38 deletions(-) create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Images/Entity/prefab_edit_open_readonly.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Images/Entity/readonly.svg create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/Procedural/ProceduralPrefabReadOnlyHandler.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/Procedural/ProceduralPrefabReadOnlyHandler.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/Procedural/ProceduralPrefabUiHandler.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/Procedural/ProceduralPrefabUiHandler.h diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/Entity/prefab_edit_open_readonly.svg b/Code/Framework/AzQtComponents/AzQtComponents/Images/Entity/prefab_edit_open_readonly.svg new file mode 100644 index 0000000000..9f16c88211 --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/Entity/prefab_edit_open_readonly.svg @@ -0,0 +1,3 @@ + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/Entity/readonly.svg b/Code/Framework/AzQtComponents/AzQtComponents/Images/Entity/readonly.svg new file mode 100644 index 0000000000..2e942e87f8 --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/Entity/readonly.svg @@ -0,0 +1,3 @@ + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc b/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc index 15049aeb69..7e7fafc9ee 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc @@ -7,7 +7,9 @@ Entity/prefab.svg Entity/prefab_edit.svg Entity/prefab_edit_open.svg + Entity/prefab_edit_open_readonly.svg Entity/prefab_edit_close.svg + Entity/readonly.svg Level/level.svg diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/ReadOnly/ReadOnlyEntitySystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/ReadOnly/ReadOnlyEntitySystemComponent.h index efc91e9d89..4b8942bcd1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/ReadOnly/ReadOnlyEntitySystemComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/ReadOnly/ReadOnlyEntitySystemComponent.h @@ -37,9 +37,9 @@ namespace AzToolsFramework static void Reflect(AZ::ReflectContext* context); static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); - // ReadOnlyEntityPublicNotifications overrides ... + // ReadOnlyEntityPublicInterface overrides ... bool IsReadOnly(const AZ::EntityId& entityId) override; - + // ReadOnlyEntityQueryInterface overrides ... void RefreshReadOnlyState(const EntityIdList& entityIds) override; void RefreshReadOnlyStateForAllEntities() override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index 2ab68bfc10..3426c56c99 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -74,6 +75,13 @@ namespace AzToolsFramework::Prefab "Prefab - PrefabFocusHandler - " "Focus Mode Interface could not be found. " "Check that it is being correctly initialized."); + + m_readOnlyEntityQueryInterface = AZ::Interface::Get(); + AZ_Assert( + m_readOnlyEntityQueryInterface, + "Prefab - PrefabFocusHandler - " + "ReadOnly Entity Query Interface could not be found. " + "Check that it is being correctly initialized."); } PrefabFocusOperationResult PrefabFocusHandler::FocusOnOwningPrefab(AZ::EntityId entityId) @@ -186,6 +194,8 @@ namespace AzToolsFramework::Prefab // Close all container entities in the old path. CloseInstanceContainers(m_instanceFocusHierarchy); + AZ::EntityId previousContainerEntityId = m_focusedInstanceContainerEntityId; + // Do not store the container for the root instance, use an invalid EntityId instead. m_focusedInstanceContainerEntityId = focusedInstance->get().GetParentInstance().has_value() ? focusedInstance->get().GetContainerEntityId() : AZ::EntityId(); m_focusedTemplateId = focusedInstance->get().GetTemplateId(); @@ -201,6 +211,12 @@ namespace AzToolsFramework::Prefab m_focusModeInterface->SetFocusRoot(containerEntityId); } + // Refresh the read-only cache, if the interface is initialized. + if (m_readOnlyEntityQueryInterface) + { + m_readOnlyEntityQueryInterface->RefreshReadOnlyState({ previousContainerEntityId, m_focusedInstanceContainerEntityId }); + } + // Refresh path variables. RefreshInstanceFocusList(); RefreshInstanceFocusPath(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h index b02106d69d..4f3dbdd708 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h @@ -22,6 +22,7 @@ namespace AzToolsFramework { class ContainerEntityInterface; class FocusModeInterface; + class ReadOnlyEntityQueryInterface; } namespace AzToolsFramework::Prefab @@ -93,6 +94,7 @@ namespace AzToolsFramework::Prefab ContainerEntityInterface* m_containerEntityInterface = nullptr; FocusModeInterface* m_focusModeInterface = nullptr; InstanceEntityMapperInterface* m_instanceEntityMapperInterface = nullptr; + ReadOnlyEntityQueryInterface* m_readOnlyEntityQueryInterface = nullptr; }; } // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index e5530b49f4..dfabd42cd1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -918,6 +918,18 @@ namespace AzToolsFramework } } + bool PrefabPublicHandler::IsOwnedByProceduralPrefabInstance(AZ::EntityId entityId) const + { + if (InstanceOptionalReference instanceReference = m_instanceEntityMapperInterface->FindOwningInstance(entityId); + instanceReference.has_value()) + { + TemplateReference templateReference = m_prefabSystemComponentInterface->FindTemplate(instanceReference->get().GetTemplateId()); + return (templateReference.has_value()) && (templateReference->get().IsProcedural()); + } + + return false; + } + bool PrefabPublicHandler::IsInstanceContainerEntity(AZ::EntityId entityId) const { InstanceOptionalReference owningInstance = m_instanceEntityMapperInterface->FindOwningInstance(entityId); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h index dd071ac09f..41c9b4a292 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h @@ -54,6 +54,7 @@ namespace AzToolsFramework PrefabOperationResult GenerateUndoNodesForEntityChangeAndUpdateCache(AZ::EntityId entityId, UndoSystem::URSequencePoint* parentUndoBatch) override; + bool IsOwnedByProceduralPrefabInstance(AZ::EntityId entityId) const override; bool IsInstanceContainerEntity(AZ::EntityId entityId) const override; bool IsLevelInstanceContainerEntity(AZ::EntityId entityId) const override; AZ::EntityId GetInstanceContainerEntityId(AZ::EntityId entityId) const override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicInterface.h index ede857dd2b..2eb0bfa8e6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicInterface.h @@ -101,6 +101,13 @@ namespace AzToolsFramework */ virtual PrefabOperationResult GenerateUndoNodesForEntityChangeAndUpdateCache( AZ::EntityId entityId, UndoSystem::URSequencePoint* parentUndoBatch) = 0; + + /** + * Detects if an entity is owned by a procedural prefab. + * @param entityId The entity to query. + * @return True if the entity is owned by a procedural prefab instance, false otherwise. + */ + virtual bool IsOwnedByProceduralPrefabInstance(AZ::EntityId entityId) const = 0; /** * Detects if an entity is the container entity for its owning prefab instance. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp index a68a72f00a..284caaa7a2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -313,7 +314,7 @@ namespace AzToolsFramework if (isEditorOnly) { - return QIcon(QString(":/Icons/Entity_Editor_Only.svg")); + return QIcon(QString(":/Entity/entity_editoronly.svg")); } AZ::Entity* entity = nullptr; @@ -322,10 +323,10 @@ namespace AzToolsFramework if (!isInitiallyActive) { - return QIcon(QString(":/Icons/Entity_Not_Active.svg")); + return QIcon(QString(":/Entity/entity_notactive.svg")); } - return QIcon(QString(":/Icons/Entity.svg")); + return QIcon(QString(":/Entity/entity.svg")); } QVariant EntityOutlinerListModel::GetEntityTooltip(const AZ::EntityId& id) const @@ -1994,9 +1995,13 @@ namespace AzToolsFramework , m_lockCheckBoxes(parent, "Lock", EntityOutlinerListModel::PartiallyLockedRole, EntityOutlinerListModel::LockedAncestorRole) { m_editorEntityFrameworkInterface = AZ::Interface::Get(); - AZ_Assert((m_editorEntityFrameworkInterface != nullptr), "EntityOutlinerItemDelegate requires a EditorEntityFrameworkInterface instance on Construction."); + + m_readOnlyEntityPublicInterface = AZ::Interface::Get(); + AZ_Assert( + (m_readOnlyEntityPublicInterface != nullptr), + "EntityOutlinerItemDelegate requires a ReadOnlyEntityPublicInterface instance on Construction."); } EntityOutlinerItemDelegate::CheckboxGroup::CheckboxGroup(QWidget* parent, AZStd::string prefix, @@ -2108,6 +2113,12 @@ namespace AzToolsFramework } PaintEntityNameAsRichText(painter, customOption, index); + + // Paint Read-Only icon if necessary + if (m_readOnlyEntityPublicInterface->IsReadOnly(entityId)) + { + PaintReadOnlyIcon(painter, option, index); + } } break; default: @@ -2166,10 +2177,10 @@ namespace AzToolsFramework backgroundPath.addRect(backgroundRect); - QColor backgroundColor = m_hoverColor; + QColor backgroundColor = s_hoverColor; if (isSelected) { - backgroundColor = m_selectedColor; + backgroundColor = s_selectedColor; } painter->fillPath(backgroundPath, backgroundColor); @@ -2336,6 +2347,20 @@ namespace AzToolsFramework EntityOutlinerListModel::s_paintingName = false; } + void EntityOutlinerItemDelegate::PaintReadOnlyIcon(QPainter* painter, const QStyleOptionViewItem& option, [[maybe_unused]] const QModelIndex& index) const + { + // Build the rect that will be used to paint the icon + QRect readOnlyRect = QRect(option.rect.topLeft() + s_readOnlyOffset, QSize(s_readOnlyRadius * 2, s_readOnlyRadius * 2)); + + painter->save(); + painter->setRenderHint(QPainter::Antialiasing, true); + painter->setPen(Qt::NoPen); + painter->setBrush(s_readOnlyBackgroundColor); + painter->drawEllipse(readOnlyRect.center(), s_readOnlyRadius, s_readOnlyRadius); + s_readOnlyIcon.paint(painter, readOnlyRect); + painter->restore(); + } + QSize EntityOutlinerItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& /*index*/) const { // Get the height of a tall character... diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx index 0a46ee4850..b785dcb31e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx @@ -38,6 +38,7 @@ namespace AzToolsFramework { class EditorEntityUiInterface; class FocusModeInterface; + class ReadOnlyEntityPublicInterface; namespace EntityOutliner { @@ -344,6 +345,9 @@ namespace AzToolsFramework // Paint the entity name using rich text void PaintEntityNameAsRichText(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + // Paint the read-only icon on the entity + void PaintReadOnlyIcon(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + struct CheckboxGroup { EntityOutlinerCheckBox m_default; @@ -372,10 +376,17 @@ namespace AzToolsFramework // this is a cache, and is hence mutable mutable QRect m_cachedBoundingRectOfTallCharacter; - const QColor m_selectedColor = QColor(255, 255, 255, 45); - const QColor m_hoverColor = QColor(255, 255, 255, 30); + inline static const QColor s_selectedColor = QColor(255, 255, 255, 45); + inline static const QColor s_hoverColor = QColor(255, 255, 255, 30); + + inline static const QColor s_readOnlyBackgroundColor = QColor("#444444"); + inline static const QPoint s_readOnlyOffset = QPoint(10, 10); + inline static const int s_readOnlyRadius = 6; + + QIcon s_readOnlyIcon = QIcon(QString(":/Entity/readonly.svg")); EditorEntityUiInterface* m_editorEntityFrameworkInterface = nullptr; + ReadOnlyEntityPublicInterface* m_readOnlyEntityPublicInterface = nullptr; }; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index bc6700aca5..1c60b78322 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1264,7 +1265,14 @@ namespace AzToolsFramework } else { - s_editorEntityUiInterface->RegisterEntity(entityId, m_prefabUiHandler.GetHandlerId()); + if (s_prefabPublicInterface->IsOwnedByProceduralPrefabInstance(entityId)) + { + s_editorEntityUiInterface->RegisterEntity(entityId, m_proceduralPrefabUiHandler.GetHandlerId()); + } + else + { + s_editorEntityUiInterface->RegisterEntity(entityId, m_prefabUiHandler.GetHandlerId()); + } // Register entity as a container s_containerEntityInterface->RegisterEntityAsContainer(entityId); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h index 808a0c2408..8589bee942 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h @@ -18,10 +18,11 @@ #include #include #include - #include #include #include +#include +#include #include @@ -92,12 +93,18 @@ namespace AzToolsFramework void ExecuteSavePrefabDialog(TemplateId templateId, bool useSaveAllPrefabsPreference) override; private: - // Used to handle the UI for the level root + // Used to handle the UI for the level root. LevelRootUiHandler m_levelRootUiHandler; - // Used to handle the UI for prefab entities + // Used to handle the UI for prefab entities. PrefabUiHandler m_prefabUiHandler; + // Used to handle the UI for procedural prefab entities. + ProceduralPrefabUiHandler m_proceduralPrefabUiHandler; + + // Ensures entities owned by procedural prefab instances are marked as read-only correctly. + ProceduralPrefabReadOnlyHandler m_proceduralPrefabReadOnlyHandler; + // Context menu item handlers static void ContextMenu_CreatePrefab(AzToolsFramework::EntityIdList selectedEntities); static void ContextMenu_InstantiatePrefab(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp index 8b56b26508..cc0018753e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp @@ -23,17 +23,6 @@ namespace AzToolsFramework { AzFramework::EntityContextId PrefabUiHandler::s_editorEntityContextId = AzFramework::EntityContextId::CreateNull(); - const QColor PrefabUiHandler::m_backgroundColor = QColor("#444444"); - const QColor PrefabUiHandler::m_backgroundHoverColor = QColor("#5A5A5A"); - const QColor PrefabUiHandler::m_backgroundSelectedColor = QColor("#656565"); - const QColor PrefabUiHandler::m_prefabCapsuleColor = QColor("#1E252F"); - const QColor PrefabUiHandler::m_prefabCapsuleDisabledColor = QColor("#35383C"); - const QColor PrefabUiHandler::m_prefabCapsuleEditColor = QColor("#4A90E2"); - const QString PrefabUiHandler::m_prefabIconPath = QString(":/Entity/prefab.svg"); - const QString PrefabUiHandler::m_prefabEditIconPath = QString(":/Entity/prefab_edit.svg"); - const QString PrefabUiHandler::m_prefabEditOpenIconPath = QString(":/Entity/prefab_edit_open.svg"); - const QString PrefabUiHandler::m_prefabEditCloseIconPath = QString(":/Entity/prefab_edit_close.svg"); - PrefabUiHandler::PrefabUiHandler() { m_prefabPublicInterface = AZ::Interface::Get(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.h index bb1c646dbe..a1c624f85a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.h @@ -46,7 +46,7 @@ namespace AzToolsFramework void OnOutlinerItemCollapse(const QModelIndex& index) const override; bool OnEntityDoubleClick(AZ::EntityId entityId) const override; - private: + protected: Prefab::PrefabFocusPublicInterface* m_prefabFocusPublicInterface = nullptr; Prefab::PrefabPublicInterface* m_prefabPublicInterface = nullptr; @@ -56,17 +56,17 @@ namespace AzToolsFramework static AzFramework::EntityContextId s_editorEntityContextId; - static constexpr int m_prefabCapsuleRadius = 6; - static constexpr int m_prefabBorderThickness = 2; - static const QColor m_backgroundColor; - static const QColor m_backgroundHoverColor; - static const QColor m_backgroundSelectedColor; - static const QColor m_prefabCapsuleColor; - static const QColor m_prefabCapsuleDisabledColor; - static const QColor m_prefabCapsuleEditColor; - static const QString m_prefabIconPath; - static const QString m_prefabEditIconPath; - static const QString m_prefabEditOpenIconPath; - static const QString m_prefabEditCloseIconPath; + int m_prefabCapsuleRadius = 6; + int m_prefabBorderThickness = 2; + QColor m_backgroundColor = QColor("#444444"); + QColor m_backgroundHoverColor = QColor("#5A5A5A"); + QColor m_backgroundSelectedColor = QColor("#656565"); + QColor m_prefabCapsuleColor = QColor("#1E252F"); + QColor m_prefabCapsuleDisabledColor = QColor("#35383C"); + QColor m_prefabCapsuleEditColor = QColor("#4A90E2"); + QString m_prefabIconPath = QString(":/Entity/prefab.svg"); + QString m_prefabEditIconPath = QString(":/Entity/prefab_edit.svg"); + QString m_prefabEditOpenIconPath = QString(":/Entity/prefab_edit_open.svg"); + QString m_prefabEditCloseIconPath = QString(":/Entity/prefab_edit_close.svg"); }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/Procedural/ProceduralPrefabReadOnlyHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/Procedural/ProceduralPrefabReadOnlyHandler.cpp new file mode 100644 index 0000000000..ed962ef4ad --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/Procedural/ProceduralPrefabReadOnlyHandler.cpp @@ -0,0 +1,68 @@ +/* + * 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 + +namespace AzToolsFramework +{ + namespace Prefab + { + ProceduralPrefabReadOnlyHandler::ProceduralPrefabReadOnlyHandler() + { + m_prefabPublicInterface = AZ::Interface::Get(); + AZ_Assert( + m_prefabPublicInterface != nullptr, + "ProceduralPrefabReadOnlyHandler requires a PrefabPublicInterface instance on Initialize."); + + m_prefabFocusPublicInterface = AZ::Interface::Get(); + AZ_Assert( + m_prefabFocusPublicInterface != nullptr, + "ProceduralPrefabReadOnlyHandler requires a PrefabFocusPublicInterface instance on Initialize."); + + AzFramework::EntityContextId editorEntityContextId = AzFramework::EntityContextId::CreateNull(); + EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId); + + ReadOnlyEntityQueryRequestBus::Handler::BusConnect(editorEntityContextId); + + // Refresh the whole read-only cache + if (auto readOnlyEntityQueryInterface = AZ::Interface::Get()) + { + readOnlyEntityQueryInterface->RefreshReadOnlyStateForAllEntities(); + } + } + + ProceduralPrefabReadOnlyHandler ::~ProceduralPrefabReadOnlyHandler() + { + ReadOnlyEntityQueryRequestBus::Handler::BusDisconnect(); + } + + void ProceduralPrefabReadOnlyHandler::IsReadOnly(const AZ::EntityId& entityId, bool& isReadOnly) + { + if(m_prefabPublicInterface->IsOwnedByProceduralPrefabInstance(entityId)) + { + // All entities nested inside a procedural prefabs should always be marked as read-only. + if (!m_prefabPublicInterface->IsInstanceContainerEntity(entityId)) + { + isReadOnly = true; + } + + // The container entity of a procedural prefab should only be marked as read-only when the prefab is being edited. + if (m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId)) + { + isReadOnly = true; + } + } + } + + } // namespace Prefab +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/Procedural/ProceduralPrefabReadOnlyHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/Procedural/ProceduralPrefabReadOnlyHandler.h new file mode 100644 index 0000000000..a4d13752bd --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/Procedural/ProceduralPrefabReadOnlyHandler.h @@ -0,0 +1,43 @@ +/* + * 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 AzToolsFramework +{ + namespace Prefab + { + class PrefabFocusPublicInterface; + class PrefabPublicInterface; + + //! Ensures entities in a procedural prefab are correctly reported as read-only. + class ProceduralPrefabReadOnlyHandler + : public ReadOnlyEntityQueryRequestBus::Handler + { + public: + AZ_CLASS_ALLOCATOR(ProceduralPrefabReadOnlyHandler, AZ::SystemAllocator, 0); + AZ_RTTI(AzToolsFramework::ProceduralPrefabReadOnlyHandler, "{A2D72461-8CA3-45EE-81D2-4976BC0B6AE9}"); + + ProceduralPrefabReadOnlyHandler(); + ~ProceduralPrefabReadOnlyHandler() override; + + // ReadOnlyEntityQueryRequestBus overrides ... + void IsReadOnly(const AZ::EntityId& entityId, bool& isReadOnly) override; + + private: + PrefabPublicInterface* m_prefabPublicInterface = nullptr; + PrefabFocusPublicInterface* m_prefabFocusPublicInterface = nullptr; + }; + + } // namespace Prefab +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/Procedural/ProceduralPrefabUiHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/Procedural/ProceduralPrefabUiHandler.cpp new file mode 100644 index 0000000000..57b41d3a4b --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/Procedural/ProceduralPrefabUiHandler.cpp @@ -0,0 +1,32 @@ +/* + * 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 + +namespace AzToolsFramework +{ + ProceduralPrefabUiHandler::ProceduralPrefabUiHandler() + { + m_prefabCapsuleColor = QColor("#361561"); + m_prefabCapsuleDisabledColor = QColor("#4B3455"); + m_prefabCapsuleEditColor = QColor("#361561"); + m_prefabIconPath = QString(":/Entity/prefab_edit.svg"); + m_prefabEditOpenIconPath = QString(":/Entity/prefab_edit_open_readonly.svg"); + } + + QString ProceduralPrefabUiHandler::GenerateItemTooltip(AZ::EntityId entityId) const + { + if (AZ::IO::Path path = m_prefabPublicInterface->GetOwningInstancePrefabPath(entityId); !path.empty()) + { + return QObject::tr("Double click to inspect.\n%1").arg(path.Native().data()); + } + return QString(); + } +} diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/Procedural/ProceduralPrefabUiHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/Procedural/ProceduralPrefabUiHandler.h new file mode 100644 index 0000000000..2b8c90e0eb --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/Procedural/ProceduralPrefabUiHandler.h @@ -0,0 +1,36 @@ +/* + * 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 + +namespace AzToolsFramework +{ + namespace Prefab + { + class PrefabFocusPublicInterface; + class PrefabPublicInterface; + }; + + //! Implements the Editor UI for Procedural Prefabs. + class ProceduralPrefabUiHandler + : public PrefabUiHandler + { + public: + AZ_CLASS_ALLOCATOR(ProceduralPrefabUiHandler, AZ::SystemAllocator, 0); + AZ_RTTI(AzToolsFramework::ProceduralPrefabUiHandler, "{3A3DF9FF-9C2E-4439-B7B4-72173B5A3502}", PrefabUiHandler); + + ProceduralPrefabUiHandler(); + ~ProceduralPrefabUiHandler() override = default; + + QString GenerateItemTooltip(AZ::EntityId entityId) const override; + }; +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 49eaa9b34a..6922ad26a2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -768,6 +768,10 @@ set(FILES UI/Prefab/PrefabUiHandler.cpp UI/Prefab/PrefabViewportFocusPathHandler.h UI/Prefab/PrefabViewportFocusPathHandler.cpp + UI/Prefab/Procedural/ProceduralPrefabReadOnlyHandler.h + UI/Prefab/Procedural/ProceduralPrefabReadOnlyHandler.cpp + UI/Prefab/Procedural/ProceduralPrefabUiHandler.h + UI/Prefab/Procedural/ProceduralPrefabUiHandler.cpp UI/Notifications/ToastNotificationsView.cpp UI/Notifications/ToastNotificationsView.h UI/Notifications/ToastBus.h diff --git a/Code/Framework/AzToolsFramework/Tests/Entity/ReadOnly/ReadOnlyEntityTests.cpp b/Code/Framework/AzToolsFramework/Tests/Entity/ReadOnly/ReadOnlyEntityTests.cpp index 532325e208..69a130b33f 100644 --- a/Code/Framework/AzToolsFramework/Tests/Entity/ReadOnly/ReadOnlyEntityTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Entity/ReadOnly/ReadOnlyEntityTests.cpp @@ -96,4 +96,22 @@ namespace AzToolsFramework // Verify the child entity is no longer marked as read-only EXPECT_FALSE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[ChildEntityName])); } + + TEST_F(ReadOnlyEntityFixture, EnsureCacheIsClearedCorrectlyEvenIfUnchanged) + { + // Create a handler that sets all entities to read-only. + ReadOnlyHandlerAlwaysTrue alwaysTrueHandler; + + { + // Create a handler that sets the child entity to read-only. + ReadOnlyHandlerEntityId entityIdHandler(m_entityMap[ChildEntityName]); + + // Verify the child entity is marked as read-only + EXPECT_TRUE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[ChildEntityName])); + } + // When the handler goes out of scope, it calls RefreshReadOnlyStateForAllEntities and refreshes the cache. + + // Verify the child entity is still marked as read-only + EXPECT_TRUE(m_readOnlyEntityPublicInterface->IsReadOnly(m_entityMap[ChildEntityName])); + } } From 10e95cd863ab951c2a30c2ed2e452c7a4833d180 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Mon, 6 Dec 2021 14:21:00 -0600 Subject: [PATCH 112/128] Updated logic to use AZStd::erase_if Signed-off-by: Chris Galvan --- .../EditorTransformComponentSelection.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index df4f041a51..f54da3b089 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -3630,17 +3630,13 @@ namespace AzToolsFramework // Do not create manipulators for any entities marked as read only if (auto readOnlyEntityPublicInterface = AZ::Interface::Get()) { - for (auto it = m_selectedEntityIds.begin(); it != m_selectedEntityIds.end();) - { - if (readOnlyEntityPublicInterface->IsReadOnly(*it)) + AZStd::erase_if( + m_selectedEntityIds, + [readOnlyEntityPublicInterface](auto entityId) { - it = m_selectedEntityIds.erase(it); + return readOnlyEntityPublicInterface->IsReadOnly(entityId); } - else - { - ++it; - } - } + ); } } From 35b7705119bb036299165837b838d2adf452ed89 Mon Sep 17 00:00:00 2001 From: mrieggeramzn <61609885+mrieggeramzn@users.noreply.github.com> Date: Mon, 6 Dec 2021 13:33:13 -0800 Subject: [PATCH 113/128] Atom/mriegger/overflow (#6119) * first pass Signed-off-by: mrieggeramzn * more nice fixes Signed-off-by: mrieggeramzn * feedback addressing Signed-off-by: mrieggeramzn --- .../LightCullingTileIterator.azsli | 7 ++- .../Atom/Features/LightCulling/NVLC.azsli | 5 +- .../LightCulling/LightCullingHeatmap.azsl | 48 +++++++++++-------- .../LightCulling/LightCullingRemap.azsl | 13 +++-- 4 files changed, 48 insertions(+), 25 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/LightCulling/LightCullingTileIterator.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/LightCulling/LightCullingTileIterator.azsli index 9b191eb06a..69958edebe 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/LightCulling/LightCullingTileIterator.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/LightCulling/LightCullingTileIterator.azsli @@ -27,6 +27,7 @@ class LightCullingTileIterator tileLightDataTex.GetDimensions(tileWidth, tileHeight); TileLightData tileLightData = Tile_UnpackData(tileLightDataTex[tileId]); + m_overflow = tileLightData.overflow; uint bin = NVLC_GetBin(viewz, tileLightData); m_readIndex = ((tileId.y * tileWidth + tileId.x) * NVLC_MAX_BINS + bin) * NVLC_MAX_POSSIBLE_LIGHTS_PER_BIN; m_value = 0; @@ -53,6 +54,10 @@ class LightCullingTileIterator } uint m_readIndex; - uint m_value; + uint m_value; + + // true if the maximum number of lights per tile is exceeded + // lights will probably flicker if this happens + bool m_overflow; StructuredBuffer m_lightListRemapped; }; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/LightCulling/NVLC.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/LightCulling/NVLC.azsli index 60d5bf38f2..f6dfc0aab4 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/LightCulling/NVLC.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/LightCulling/NVLC.azsli @@ -67,6 +67,8 @@ struct TileLightData // If there is a pixel of opaque geometry there, we mark a bit in this bin. uint mask; uint logMaxBins; + // true if there are too many lights or decals assigned to this tile + bool overflow; }; @@ -115,7 +117,8 @@ TileLightData Tile_UnpackData(uint4 pack) data.zFar = asfloat( pack.y | NVLC_BINS_MASK ); data.mask = pack.z; data.logMaxBins = pack.y & NVLC_BINS_MASK; - + // unpack the "lights overflowed" bit + data.overflow = pack.w >> 31; return data; } diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingHeatmap.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingHeatmap.azsl index bd51fb96bb..9e30a84330 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingHeatmap.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingHeatmap.azsl @@ -6,16 +6,17 @@ * */ -// The heatmap will change color as the light count increases up to TileCountMax, at which point and beyond it will be white. +// The heatmap will change color as the light count increases up to TileCountMax static const int TileCountMax = 75; +static const int OverflowDisplayNumber = 999; - -static const float3 BARELY_USED_COLOR = float3(0.05, 0.05, 0.20); -static const float3 LIGHTLY_USED_COLOR = float3(0.05, 0.05, 0.60); -static const float3 MODERATELY_USED_COLOR = float3(0.05, 0.60, 0.05); -static const float3 HEAVILY_USED_COLOR = float3(1.00, 1.00, 0.05); -static const float3 OVER_USED_COLOR = float3(1.00, 0.05, 0.05); +static const float3 BarelyUsedColor = float3(0.05, 0.05, 0.20); // Deep dark blue +static const float3 LightlyUsedColor = float3(0.05, 0.05, 0.60); // Deep blue +static const float3 ModeratelyUsedColor = float3(0.05, 0.60, 0.05); // Green +static const float3 HeavilyUsedColor = float3(1.00, 1.00, 0.05); // Yellow +static const float3 OverUsedColor = float3(1.00, 0.05, 0.05); // Red +static const float3 OverflowColor = float3(1.0, 1.0, 1.0); // White #include @@ -174,30 +175,33 @@ uint PrintNumbersInsideTile(uint x, uint2 origin, uint2 uv, uint scale) } -float3 ComputeTileColor(uint2 uv, uint print_me, uint maximum) +float3 ComputeTileColor(const uint2 uv, const uint print_me, const bool overflow) { int2 local_uv = int2( uv % uint2(TILE_DIM_X, TILE_DIM_Y) ); - float x = float(print_me) / float(maximum); + float x = float(print_me) / float(TileCountMax); x = sqrt(x); x = saturate(x); float3 color; - if( x <= 0.0 ) + if (overflow) + { + color = OverflowColor; + } + else if( x <= 0.0 ) { color = float3(0.0, 0.0, 0.0); } else if( x >= 1.0 ) { - color = float3(1.0, 1.0, 1.0); + color = OverUsedColor; } else { - color = lerp(BARELY_USED_COLOR, LIGHTLY_USED_COLOR, saturate((x - 0.00) * 4.0)); - color = lerp(color, MODERATELY_USED_COLOR, saturate((x - 0.25) * 4.0)); - color = lerp(color, HEAVILY_USED_COLOR, saturate((x - 0.50) * 4.0)); - color = lerp(color, OVER_USED_COLOR, saturate((x - 0.75) * 4.0)); + color = lerp(BarelyUsedColor, LightlyUsedColor, saturate((x - 0.00) * 4.0)); + color = lerp(color, ModeratelyUsedColor, saturate((x - 0.33) * 4.0)); + color = lerp(color, HeavilyUsedColor, saturate((x - 0.66) * 4.0)); } float border = (local_uv.x == TILE_DIM_X - 1 || local_uv.y == TILE_DIM_Y - 1) ? 1.0 : 0.0; @@ -226,12 +230,18 @@ ShaderResourceGroup PassSrg : SRG_PerPass PSOutput MainPS(VSOutput IN) { - uint2 tileId = ComputeTileId(IN.m_position.xy); + const uint2 tileId = ComputeTileId(IN.m_position.xy); - // We subtract NUM_LIGHT_TYPES because it includes termination markers - uint lightCount = PassSrg::m_tileLightData[tileId].w - NUM_LIGHT_TYPES; + const uint tileLightDataW = PassSrg::m_tileLightData[tileId].w; - float3 tileColor = ComputeTileColor(IN.m_position.xy, lightCount, TileCountMax); + // check to see if we are overflowing the number of lights per tile + // expect the lighting to flicker if this happens + const bool overflow = (tileLightDataW >> 31); + + // We subtract NUM_LIGHT_TYPES because it includes termination markers + const uint lightCount = overflow ? OverflowDisplayNumber : tileLightDataW - NUM_LIGHT_TYPES; + + const float3 tileColor = ComputeTileColor(IN.m_position.xy, lightCount, overflow); PSOutput OUT; OUT.m_color.rgb = tileColor; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingRemap.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingRemap.azsl index a0daa66507..37f22b034c 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingRemap.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingRemap.azsl @@ -138,17 +138,19 @@ uint CalculateNumLightsInWorstBin(uint groupIndex, uint3 groupID, uint baseBin, return lightsInWorstBin; } -void WriteTileLightData(uint groupIndex, uint3 groupID, uint lightsInWorstBin) +void WriteTileLightData(const uint groupIndex, const uint3 groupID, const uint lightsInWorstBin, const bool overflow) { if (groupIndex == 0) { uint4 tileLightData = PassSrg::m_tileLightData[groupID.xy]; - // Used for the heatmap tileLightData.w = lightsInWorstBin; + + // pack a "lights have overflowed bit" into this uint + tileLightData.w |= overflow ? (1 << 31) : 0; PassSrg::m_tileLightData[groupID.xy] = tileLightData; - } + } } void WriteEndOfList(uint groupIndex, uint writeIndices[NVLC_MAX_BINS]) @@ -193,6 +195,9 @@ void MainCS( GroupMemoryBarrierWithGroupSync(); uint totalLights = PassSrg::m_lightCount.Load(uint3(groupID.xy, 0)).x; + + // expect flickering if the max number of lights per tile is exceeded + const bool overflow = totalLights > (NVLC_MAX_POSSIBLE_LIGHTS_PER_BIN - 1); totalLights = min(totalLights, NVLC_MAX_POSSIBLE_LIGHTS_PER_BIN - 1); AssignLightsToSharedMemoryBins(groupIndex, groupID, totalLights); @@ -207,5 +212,5 @@ void MainCS( uint lightsInWorstBin = CalculateNumLightsInWorstBin(groupIndex, groupID, baseBin, writeIndices); WriteEndOfList(groupIndex, writeIndices); - WriteTileLightData(groupIndex, groupID, lightsInWorstBin); + WriteTileLightData(groupIndex, groupID, lightsInWorstBin, overflow); } From d4206270a6ada8742d869f611b36f95bf3e6af1e Mon Sep 17 00:00:00 2001 From: carlitosan <82187351+carlitosan@users.noreply.github.com> Date: Mon, 6 Dec 2021 13:37:29 -0800 Subject: [PATCH 114/128] Use weak reference for undo state, as it is an entirely internal class Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com> --- .../Editor/Assets/ScriptCanvasUndoHelper.cpp | 24 +++++++++---------- .../Editor/Assets/ScriptCanvasUndoHelper.h | 6 ++--- .../Code/Editor/Components/EditorGraph.cpp | 2 +- .../Editor/Undo/ScriptCanvasGraphCommand.cpp | 16 ++++++------- .../Editor/Undo/ScriptCanvasGraphCommand.h | 8 +++---- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.cpp index 31bdf0077c..f125a4cbc9 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.cpp @@ -18,10 +18,10 @@ namespace ScriptCanvasEditor { } - UndoHelper::UndoHelper(SourceHandle memoryAsset) + UndoHelper::UndoHelper(Graph* graph) : m_undoState(this) { - SetSource(memoryAsset); + SetSource(graph); } UndoHelper::~UndoHelper() @@ -29,10 +29,10 @@ namespace ScriptCanvasEditor UndoRequestBus::Handler::BusDisconnect(); } - void UndoHelper::SetSource(SourceHandle source) + void UndoHelper::SetSource(Graph* graph) { - m_memoryAsset = source; - UndoRequestBus::Handler::BusConnect(source.Get()->GetScriptCanvasId()); + m_graph = graph; + UndoRequestBus::Handler::BusConnect(graph->GetScriptCanvasId()); } ScriptCanvasEditor::UndoCache* UndoHelper::GetSceneUndoCache() @@ -42,8 +42,8 @@ namespace ScriptCanvasEditor ScriptCanvasEditor::UndoData UndoHelper::CreateUndoData() { - AZ::EntityId graphCanvasGraphId = m_memoryAsset.Get()->GetGraphCanvasGraphId(); - ScriptCanvas::ScriptCanvasId scriptCanvasId = m_memoryAsset.Get()->GetScriptCanvasId(); + AZ::EntityId graphCanvasGraphId = m_graph->GetGraphCanvasGraphId(); + ScriptCanvas::ScriptCanvasId scriptCanvasId = m_graph->GetScriptCanvasId(); GraphCanvas::GraphModelRequestBus::Event(graphCanvasGraphId, &GraphCanvas::GraphModelRequests::OnSaveDataDirtied, graphCanvasGraphId); @@ -94,22 +94,22 @@ namespace ScriptCanvasEditor void UndoHelper::AddGraphItemChangeUndo(AZStd::string_view undoLabel) { GraphItemChangeCommand* command = aznew GraphItemChangeCommand(undoLabel); - command->Capture(m_memoryAsset, true); - command->Capture(m_memoryAsset, false); + command->Capture(m_graph, true); + command->Capture(m_graph, false); AddUndo(command); } void UndoHelper::AddGraphItemAdditionUndo(AZStd::string_view undoLabel) { GraphItemAddCommand* command = aznew GraphItemAddCommand(undoLabel); - command->Capture(m_memoryAsset, false); + command->Capture(m_graph, false); AddUndo(command); } void UndoHelper::AddGraphItemRemovalUndo(AZStd::string_view undoLabel) { GraphItemRemovalCommand* command = aznew GraphItemRemovalCommand(undoLabel); - command->Capture(m_memoryAsset, true); + command->Capture(m_graph, true); AddUndo(command); } @@ -190,7 +190,7 @@ namespace ScriptCanvasEditor void UndoHelper::UpdateCache() { - ScriptCanvas::ScriptCanvasId scriptCanvasId = m_memoryAsset.Get()->GetScriptCanvasId(); + ScriptCanvas::ScriptCanvasId scriptCanvasId = m_graph->GetScriptCanvasId(); UndoCache* undoCache = nullptr; UndoRequestBus::EventResult(undoCache, scriptCanvasId, &UndoRequests::GetSceneUndoCache); diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.h b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.h index 3652b07686..e2d4f008fa 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.h +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasUndoHelper.h @@ -21,13 +21,13 @@ namespace ScriptCanvasEditor public: UndoHelper(); - UndoHelper(SourceHandle source); + UndoHelper(Graph* source); ~UndoHelper(); UndoCache* GetSceneUndoCache() override; UndoData CreateUndoData() override; - void SetSource(SourceHandle source); + void SetSource(Graph* source); void BeginUndoBatch(AZStd::string_view label) override; void EndUndoBatch() override; @@ -58,6 +58,6 @@ namespace ScriptCanvasEditor Status m_status = Status::Idle; SceneUndoState m_undoState; - SourceHandle m_memoryAsset; + Graph* m_graph = nullptr; }; } diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp index a46b2a4a5c..b50457adbf 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp @@ -481,6 +481,7 @@ namespace ScriptCanvasEditor ScriptCanvas::Graph::Activate(); PostActivate(); + m_undoHelper.SetSource(this); } void Graph::Deactivate() @@ -1067,7 +1068,6 @@ namespace ScriptCanvasEditor void Graph::MarkOwnership(ScriptCanvas::ScriptCanvasData& owner) { m_owner = &owner; - m_undoHelper.SetSource(SourceHandle(GetOwnership(), {}, "")); } ScriptCanvas::DataPtr Graph::GetOwnership() const diff --git a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.cpp b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.cpp index 406e139ef1..944a5e667d 100644 --- a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.cpp @@ -36,7 +36,7 @@ namespace ScriptCanvasEditor { } - void GraphItemCommand::Capture(SourceHandle&, bool) + void GraphItemCommand::Capture(Graph*, bool) { } @@ -105,10 +105,10 @@ namespace ScriptCanvasEditor RestoreItem(m_redoState); } - void GraphItemChangeCommand::Capture(SourceHandle& memoryAsset, bool captureUndo) + void GraphItemChangeCommand::Capture(Graph* graph, bool captureUndo) { - m_scriptCanvasId = memoryAsset.Get()->GetScriptCanvasId(); - m_graphCanvasGraphId = memoryAsset.Get()->GetGraphCanvasGraphId(); + m_scriptCanvasId = graph->GetScriptCanvasId(); + m_graphCanvasGraphId = graph->GetGraphCanvasGraphId(); UndoCache* undoCache = nullptr; UndoRequestBus::EventResult(undoCache, m_scriptCanvasId, &UndoRequests::GetSceneUndoCache); @@ -204,9 +204,9 @@ namespace ScriptCanvasEditor RestoreItem(m_redoState); } - void GraphItemAddCommand::Capture(SourceHandle& memoryAsset, bool) + void GraphItemAddCommand::Capture(Graph* graph, bool) { - GraphItemChangeCommand::Capture(memoryAsset, false); + GraphItemChangeCommand::Capture(graph, false); } //// Graph Item Removal Command @@ -225,8 +225,8 @@ namespace ScriptCanvasEditor RestoreItem(m_redoState); } - void GraphItemRemovalCommand::Capture(SourceHandle& memoryAsset, bool) + void GraphItemRemovalCommand::Capture(Graph* graph, bool) { - GraphItemChangeCommand::Capture(memoryAsset, true); + GraphItemChangeCommand::Capture(graph, true); } } diff --git a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.h b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.h index 61102f690c..b9435d0702 100644 --- a/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.h +++ b/Gems/ScriptCanvas/Code/Editor/Undo/ScriptCanvasGraphCommand.h @@ -46,7 +46,7 @@ namespace ScriptCanvasEditor void Undo() override; void Redo() override; - virtual void Capture(SourceHandle& memoryAsset, bool captureUndo); + virtual void Capture(Graph* graph, bool captureUndo); bool Changed() const override; @@ -76,7 +76,7 @@ namespace ScriptCanvasEditor void Undo() override; void Redo() override; - void Capture(SourceHandle& memoryAsset, bool captureUndo) override; + void Capture(Graph* graph, bool captureUndo) override; void RestoreItem(const AZStd::vector& restoreBuffer) override; @@ -103,7 +103,7 @@ namespace ScriptCanvasEditor void Undo() override; void Redo() override; - void Capture(SourceHandle& memoryAsset, bool captureUndo) override; + void Capture(Graph* graph, bool captureUndo) override; protected: GraphItemAddCommand(const GraphItemAddCommand&) = delete; @@ -124,7 +124,7 @@ namespace ScriptCanvasEditor void Undo() override; void Redo() override; - void Capture(SourceHandle& memoryAsset, bool captureUndo) override; + void Capture(Graph* graph, bool captureUndo) override; protected: GraphItemRemovalCommand(const GraphItemRemovalCommand&) = delete; From dae25beef5a813265619b6c03785fea272489524 Mon Sep 17 00:00:00 2001 From: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Mon, 6 Dec 2021 17:11:30 -0600 Subject: [PATCH 115/128] {lyn2264} Adding Python API for Actor Group (#6064) * {lyn2264} Adding Python API for Actor Group * updating the IBoneData with behavior attributes * adding actor_group.py for making actor group JSON data * adding physics_data.py for making physics JSON data Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com> * fixing dictionary issues Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com> * updated comment style to numpydoc Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com> * updated to numpydoc style Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com> * example of actor group rules Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com> * Updated based on feedback Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com> --- .../Assets/TestAnim/rin_skeleton.fbx | 3 + .../TestAnim/rin_skeleton.fbx.assetinfo | 8 + .../Assets/TestAnim/scene_export_actor.py | 221 +++++++ .../SceneAPI/SceneData/GraphData/BoneData.cpp | 3 + .../Editor/Scripts/scene_api/actor_group.py | 519 ++++++++++++++++ .../Editor/Scripts/scene_api/physics_data.py | 580 ++++++++++++++++++ 6 files changed, 1334 insertions(+) create mode 100644 AutomatedTesting/Assets/TestAnim/rin_skeleton.fbx create mode 100644 AutomatedTesting/Assets/TestAnim/rin_skeleton.fbx.assetinfo create mode 100644 AutomatedTesting/Assets/TestAnim/scene_export_actor.py create mode 100644 Gems/PythonAssetBuilder/Editor/Scripts/scene_api/actor_group.py create mode 100644 Gems/PythonAssetBuilder/Editor/Scripts/scene_api/physics_data.py diff --git a/AutomatedTesting/Assets/TestAnim/rin_skeleton.fbx b/AutomatedTesting/Assets/TestAnim/rin_skeleton.fbx new file mode 100644 index 0000000000..f727c26ad2 --- /dev/null +++ b/AutomatedTesting/Assets/TestAnim/rin_skeleton.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:27f87510ae07771dbad3e430e31502b1d1d13dee868f143b7f1de2a7febc8eb9 +size 7046400 diff --git a/AutomatedTesting/Assets/TestAnim/rin_skeleton.fbx.assetinfo b/AutomatedTesting/Assets/TestAnim/rin_skeleton.fbx.assetinfo new file mode 100644 index 0000000000..2d5502f42f --- /dev/null +++ b/AutomatedTesting/Assets/TestAnim/rin_skeleton.fbx.assetinfo @@ -0,0 +1,8 @@ +{ + "values": [ + { + "$type": "ScriptProcessorRule", + "scriptFilename": "Assets/TestAnim/scene_export_actor.py" + } + ] +} \ No newline at end of file diff --git a/AutomatedTesting/Assets/TestAnim/scene_export_actor.py b/AutomatedTesting/Assets/TestAnim/scene_export_actor.py new file mode 100644 index 0000000000..9dddc056a2 --- /dev/null +++ b/AutomatedTesting/Assets/TestAnim/scene_export_actor.py @@ -0,0 +1,221 @@ +# +# 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 +# +# +import traceback, sys, uuid, os, json + +# +# Example for exporting ActorGroup scene rules +# + +def log_exception_traceback(): + exc_type, exc_value, exc_tb = sys.exc_info() + data = traceback.format_exception(exc_type, exc_value, exc_tb) + print(str(data)) + +def get_node_names(sceneGraph, nodeTypeName, testEndPoint = False, validList = None): + import azlmbr.scene.graph + import scene_api.scene_data + + node = sceneGraph.get_root() + nodeList = [] + children = [] + paths = [] + + while node.IsValid(): + # store children to process after siblings + if sceneGraph.has_node_child(node): + children.append(sceneGraph.get_node_child(node)) + + nodeName = scene_api.scene_data.SceneGraphName(sceneGraph.get_node_name(node)) + paths.append(nodeName.get_path()) + + include = True + + if (validList is not None): + include = False # if a valid list filter provided, assume to not include node name + name_parts = nodeName.get_path().split('.') + for valid in validList: + if (valid in name_parts[-1]): + include = True + break + + # store any node that has provides specifc data content + nodeContent = sceneGraph.get_node_content(node) + if include and nodeContent.CastWithTypeName(nodeTypeName): + if testEndPoint is not None: + include = sceneGraph.is_node_end_point(node) is testEndPoint + if include: + if (len(nodeName.get_path())): + nodeList.append(scene_api.scene_data.SceneGraphName(sceneGraph.get_node_name(node))) + + # advance to next node + if sceneGraph.has_node_sibling(node): + node = sceneGraph.get_node_sibling(node) + elif children: + node = children.pop() + else: + node = azlmbr.scene.graph.NodeIndex() + + return nodeList, paths + +def generate_mesh_group(scene, sceneManifest, meshDataList, paths): + # Compute the name of the scene file + clean_filename = scene.sourceFilename.replace('.', '_') + mesh_group_name = os.path.basename(clean_filename) + + # make the mesh group + mesh_group = sceneManifest.add_mesh_group(mesh_group_name) + mesh_group['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, clean_filename)) + '}' + + # add all nodes to this mesh group + for activeMeshIndex in range(len(meshDataList)): + mesh_name = meshDataList[activeMeshIndex] + mesh_path = mesh_name.get_path() + sceneManifest.mesh_group_select_node(mesh_group, mesh_path) + +def create_shape_configuration(nodeName): + import scene_api.physics_data + + if(nodeName in ['_foot_','_wrist_']): + shapeConfiguration = scene_api.physics_data.BoxShapeConfiguration() + shapeConfiguration.scale = [1.1, 1.1, 1.1] + shapeConfiguration.dimensions = [2.1, 3.1, 4.1] + return shapeConfiguration + else: + shapeConfiguration = scene_api.physics_data.CapsuleShapeConfiguration() + shapeConfiguration.scale = [1.0, 1.0, 1.0] + shapeConfiguration.height = 1.0 + shapeConfiguration.radius = 1.0 + return shapeConfiguration + +def create_collider_configuration(nodeName): + import scene_api.physics_data + + colliderConfiguration = scene_api.physics_data.ColliderConfiguration() + colliderConfiguration.Position = [0.1, 0.1, 0.2] + colliderConfiguration.Rotation = [45.0, 35.0, 25.0] + return colliderConfiguration + +def generate_physics_nodes(actorPhysicsSetupRule, nodeNameList): + import scene_api.physics_data + + hitDetectionConfig = scene_api.physics_data.CharacterColliderConfiguration() + simulatedObjectColliderConfig = scene_api.physics_data.CharacterColliderConfiguration() + clothConfig = scene_api.physics_data.CharacterColliderConfiguration() + ragdollConfig = scene_api.physics_data.RagdollConfiguration() + + for nodeName in nodeNameList: + shapeConfiguration = create_shape_configuration(nodeName) + colliderConfiguration = create_collider_configuration(nodeName) + hitDetectionConfig.add_character_collider_node_configuration_node(nodeName, colliderConfiguration, shapeConfiguration) + simulatedObjectColliderConfig.add_character_collider_node_configuration_node(nodeName, colliderConfiguration, shapeConfiguration) + clothConfig.add_character_collider_node_configuration_node(nodeName, colliderConfiguration, shapeConfiguration) + # + ragdollNode = scene_api.physics_data.RagdollNodeConfiguration() + ragdollNode.JointConfig.Name = nodeName + ragdollConfig.add_ragdoll_node_configuration(ragdollNode) + ragdollConfig.colliders.add_character_collider_node_configuration_node(nodeName, colliderConfiguration, shapeConfiguration) + + actorPhysicsSetupRule.set_simulated_object_collider_config(simulatedObjectColliderConfig) + actorPhysicsSetupRule.set_hit_detection_config(hitDetectionConfig) + actorPhysicsSetupRule.set_cloth_config(clothConfig) + actorPhysicsSetupRule.set_ragdoll_config(ragdollConfig) + +def generate_actor_group(scene, sceneManifest, meshDataList, paths): + import scene_api.scene_data + import scene_api.physics_data + import scene_api.actor_group + + # fetch bone data + validNames = ['_neck_','_pelvis_','_leg_','_knee_','_spine_','_arm_','_clavicle_','_head_','_elbow_','_wrist_'] + graph = scene_api.scene_data.SceneGraph(scene.graph) + nodeList, allNodePaths = get_node_names(graph, 'BoneData', validList = validNames) + + nodeNameList = [] + for activeMeshIndex, nodeName in enumerate(nodeList): + nodeNameList.append(nodeName.get_name()) + + # add comment + commentRule = scene_api.actor_group.CommentRule() + commentRule.text = str(nodeNameList) + + # ActorPhysicsSetupRule + actorPhysicsSetupRule = scene_api.actor_group.ActorPhysicsSetupRule() + generate_physics_nodes(actorPhysicsSetupRule, nodeNameList) + + # add scale of the Actor rule + actorScaleRule = scene_api.actor_group.ActorScaleRule() + actorScaleRule.scaleFactor = 2.0 + + # add coordinate system rule + coordinateSystemRule = scene_api.actor_group.CoordinateSystemRule() + coordinateSystemRule.useAdvancedData = False + + # add morph target rule + morphTargetRule = scene_api.actor_group.MorphTargetRule() + morphTargetRule.targets.select_targets([nodeNameList[0]], nodeNameList) + + # add skeleton optimization rule + skeletonOptimizationRule = scene_api.actor_group.SkeletonOptimizationRule() + skeletonOptimizationRule.autoSkeletonLOD = True + skeletonOptimizationRule.criticalBonesList.select_targets([nodeNameList[0:2]], nodeNameList) + + # add LOD rule + lodRule = scene_api.actor_group.LodRule() + lodRule0 = lodRule.add_lod_level(0) + lodRule0.select_targets([nodeNameList[1:4]], nodeNameList) + + actorGroup = scene_api.actor_group.ActorGroup() + actorGroup.name = os.path.basename(scene.sourceFilename) + actorGroup.add_rule(actorScaleRule) + actorGroup.add_rule(coordinateSystemRule) + actorGroup.add_rule(skeletonOptimizationRule) + actorGroup.add_rule(morphTargetRule) + actorGroup.add_rule(lodRule) + actorGroup.add_rule(actorPhysicsSetupRule) + actorGroup.add_rule(commentRule) + sceneManifest.manifest['values'].append(actorGroup.to_dict()) + +def update_manifest(scene): + import json, uuid, os + import azlmbr.scene.graph + import scene_api.scene_data + + graph = scene_api.scene_data.SceneGraph(scene.graph) + mesh_name_list, all_node_paths = get_node_names(graph, 'MeshData') + scene_manifest = scene_api.scene_data.SceneManifest() + generate_actor_group(scene, scene_manifest, mesh_name_list, all_node_paths) + generate_mesh_group(scene, scene_manifest, mesh_name_list, all_node_paths) + + # Convert the manifest to a JSON string and return it + return scene_manifest.export() + +sceneJobHandler = None + +def on_update_manifest(args): + try: + scene = args[0] + return update_manifest(scene) + except RuntimeError as err: + print (f'ERROR - {err}') + log_exception_traceback() + except: + log_exception_traceback() + + global sceneJobHandler + sceneJobHandler.disconnect() + sceneJobHandler = None + +# try to create SceneAPI handler for processing +try: + import azlmbr.scene + + sceneJobHandler = azlmbr.scene.ScriptBuildingNotificationBusHandler() + sceneJobHandler.connect() + sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest) +except: + sceneJobHandler = None diff --git a/Code/Tools/SceneAPI/SceneData/GraphData/BoneData.cpp b/Code/Tools/SceneAPI/SceneData/GraphData/BoneData.cpp index 8a3807c31a..e1a6c2608f 100644 --- a/Code/Tools/SceneAPI/SceneData/GraphData/BoneData.cpp +++ b/Code/Tools/SceneAPI/SceneData/GraphData/BoneData.cpp @@ -46,6 +46,9 @@ namespace AZ BehaviorContext* behaviorContext = azrtti_cast(context); if (behaviorContext) { + behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Module, "scene"); behaviorContext->Class() ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) diff --git a/Gems/PythonAssetBuilder/Editor/Scripts/scene_api/actor_group.py b/Gems/PythonAssetBuilder/Editor/Scripts/scene_api/actor_group.py new file mode 100644 index 0000000000..dd9f1f8729 --- /dev/null +++ b/Gems/PythonAssetBuilder/Editor/Scripts/scene_api/actor_group.py @@ -0,0 +1,519 @@ +""" +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 +""" + +import json +import uuid +import os, sys + +sys.path.append(os.path.dirname(__file__)) +import physics_data + +class ActorGroup(): + """ + Configure actor data exporting. + + Attributes + ---------- + name: + Name for the group. This name will also be used as the name for the generated file. + + selectedRootBone: + The root bone of the animation that will be exported. + + rules: `list` of actor rules (derived from BaseRule) + modifiers to fine-tune the export process. + + Methods + ------- + + to_dict() + Converts contents to a Python dictionary + + add_rule(rule) + Adds a rule into the internal rules container + Returns True if the rule was added to the internal rules container + + create_rule(rule) + Helper method to add and return the rule + + remove_rule(type) + Removes the rule from the internal rules container + + to_dict() + Converts the contents to as a Python dictionary + + to_json() + Converts the contents to a JSON string + + """ + def __init__(self): + self.typename = 'ActorGroup' + self.name = '' + self.selectedRootBone = '' + self.id = uuid.uuid4() + self.rules = set() + + def add_rule(self, rule) -> bool: + if (rule not in self.rules): + self.rules.add(rule) + return True + return False + + def create_rule(self, rule) -> any: + if (self.add_rule(rule)): + return rule + return None + + def remove_rule(self, type) -> None: + self.rules.discard(rule) + + def to_dict(self) -> dict: + out = {} + out['$type'] = self.typename + out['name'] = self.name + out['selectedRootBone'] = self.selectedRootBone + out['id'] = f"{{{str(self.id)}}}" + # convert the rules + ruleList = [] + for rule in self.rules: + jsonStr = json.dumps(rule, cls=RuleEncoder) + jsonDict = json.loads(jsonStr) + ruleList.append(jsonDict) + out['rules'] = ruleList + return out + + def to_json(self) -> any: + jsonDOM = self.to_dict() + return json.dumps(jsonDOM, cls=RuleEncoder, indent=1) + +class RuleEncoder(json.JSONEncoder): + """ + A helper class to encode the Python classes with to a Python dictionary + + Methods + ------- + + encode(obj) + Converts contents to a Python dictionary for the JSONEncoder + + """ + def encode(self, obj): + chunk = obj + if isinstance(obj, BaseRule): + chunk = obj.to_dict() + elif isinstance(obj, dict): + chunk = obj + elif hasattr(obj, 'to_dict'): + chunk = obj.to_dict() + else: + chunk = obj.__dict__ + + return super().encode(chunk) + +class BaseRule(): + """ + Base class of the actor rules to help encode the type name of abstract rules + + Parameters + ---------- + typename : str + A typename the $type will be in the JSON chunk object + + Attributes + ---------- + typename: str + The type name of the abstract classes to be serialized + + id: UUID + a unique ID for the rule + + Methods + ------- + to_dict() + Converts contents to a Python dictionary + Adds the '$type' member + Adds a random 'id' member + """ + def __init__(self, typename): + self.typename = typename + self.id = uuid.uuid4() + + def __eq__(self, other): + return self.id.__eq__(other.id) + + def __ne__(self, other): + return self.__eq__(other) is False + + def __hash__(self): + return self.id.__hash__() + + def to_dict(self): + data = self.__dict__ + data['id'] = f"{{{str(self.id)}}}" + # rename 'typename' to '$type' + data['$type'] = self.typename + data.pop('typename') + return data + +class SceneNodeSelectionList(BaseRule): + """ + Contains a list of node names to include (selectedNodes) and to exclude (unselectedNodes) + + Attributes + ---------- + selectedNodes: `list` of str + The node names to include for this group rule + + unselectedNodes: `list` of str + The node names to exclude for this group rule + + Methods + ------- + convert_selection(self, container, key): + this adds its contents to an existing dictionary container at a key position + + select_targets(self, selectedList, allNodesList:list) + helper function to include a small list of node names from list of all the node names + + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self): + super().__init__('SceneNodeSelectionList') + self.selectedNodes = [] + self.unselectedNodes = [] + + def convert_selection(self, container, key): + container[key] = self.to_dict() + + def select_targets(self, selectedList, allNodesList:list): + self.selectedNodes = selectedList + self.unselectedNodes = allNodesList.copy() + for node in selectedList: + if node in self.unselectedNodes: + self.unselectedNodes.remove(node) + +class LodNodeSelectionList(SceneNodeSelectionList): + """ + Level of Detail node selection list + + The selected nodes should be joints with BoneData + derived from SceneNodeSelectionList + see also LodRule + + Attributes + ---------- + lodLevel: int + the level of detail to target where 0 is nearest level of detail + up to 5 being the farthest level of detail range for 6 levels maximum + + Methods + ------- + + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self): + super().__init__() + self.typename = 'LodNodeSelectionList' + self.lodLevel = 0 + + def to_dict(self): + data = super().to_dict() + data['lodLevel'] = self.lodLevel + return data + +class PhysicsAnimationConfiguration(): + """ + Configuration for animated physics structures which are more detailed than the character controller. + For example, ragdoll or hit detection configurations. + See also 'class Physics::AnimationConfiguration' + + Attributes + ---------- + hitDetectionConfig: CharacterColliderConfiguration + for hit detection + + ragdollConfig: RagdollConfiguration + to set up physics properties + + clothConfig: CharacterColliderConfiguration + for cloth physics + + simulatedObjectColliderConfig: CharacterColliderConfiguration + for simulation physics + + Methods + ------- + + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self): + self.hitDetectionConfig = physics_data.CharacterColliderConfiguration() + self.ragdollConfig = physics_data.RagdollConfiguration() + self.clothConfig = physics_data.CharacterColliderConfiguration() + self.simulatedObjectColliderConfig = physics_data.CharacterColliderConfiguration() + + def to_dict(self): + data = {} + data["hitDetectionConfig"] = self.hitDetectionConfig.to_dict() + data["ragdollConfig"] = self.ragdollConfig.to_dict() + data["clothConfig"] = self.clothConfig.to_dict() + data["simulatedObjectColliderConfig"] = self.simulatedObjectColliderConfig.to_dict() + return data + +class EMotionFXPhysicsSetup(): + """ + Physics setup properties + See also 'class EMotionFX::PhysicsSetup' + + Attributes + ---------- + config: PhysicsAnimationConfiguration + Configuration to setup physics properties + + Methods + ------- + + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self): + self.typename = 'PhysicsSetup' + self.config = PhysicsAnimationConfiguration() + + def to_dict(self): + return { + "config" : self.config.to_dict() + } + +class ActorPhysicsSetupRule(BaseRule): + """ + Physics setup properties + + Attributes + ---------- + data: EMotionFXPhysicsSetup + Data to setup physics properties + + Methods + ------- + + set_hit_detection_config(self, hitDetectionConfig) + Simple helper function to assign the hit detection configuration + + set_ragdoll_config(self, ragdollConfig) + Simple helper function to assign the ragdoll configuration + + set_cloth_config(self, clothConfig) + Simple helper function to assign the cloth configuration + + set_simulated_object_collider_config(self, simulatedObjectColliderConfig) + Simple helper function to assign the assign simulated object collider configuration + + to_dict() + Converts contents to a Python dictionary + + """ + def __init__(self): + super().__init__('ActorPhysicsSetupRule') + self.data = EMotionFXPhysicsSetup() + + def set_hit_detection_config(self, hitDetectionConfig) -> None: + self.data.config.hitDetectionConfig = hitDetectionConfig + + def set_ragdoll_config(self, ragdollConfig) -> None: + self.data.config.ragdollConfig = ragdollConfig + + def set_cloth_config(self, clothConfig) -> None: + self.data.config.clothConfig = clothConfig + + def set_simulated_object_collider_config(self, simulatedObjectColliderConfig) -> None: + self.data.config.simulatedObjectColliderConfig = simulatedObjectColliderConfig + + def to_dict(self): + data = super().to_dict() + data["data"] = self.data.to_dict() + return data + +class ActorScaleRule(BaseRule): + """ + Scale the actor + + Attributes + ---------- + scaleFactor: float + Set the multiplier to scale geometry. + + Methods + ------- + to_dict() + Converts contents to a Python dictionary + + """ + def __init__(self): + super().__init__('ActorScaleRule') + self.scaleFactor = 1.0 + +class CoordinateSystemRule(BaseRule): + """ + Modify the target coordinate system, applying a transformation to all data (transforms and vertex data if it exists). + + Attributes + ---------- + targetCoordinateSystem: int + Change the direction the actor/motion will face by applying a post transformation to the data. + + useAdvancedData: bool + If True, use advanced settings + + originNodeName: str + Select a Node from the scene as the origin for this export. + + rotation: [float, float, float, float] + Sets the orientation offset of the processed mesh in degrees. Rotates (yaw, pitch, roll) the group after translation. + + translation: [float, float, float] + Moves the group along the given vector3. + + scale: float + Sets the scale offset of the processed mesh. + + Methods + ------- + + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self): + super().__init__('CoordinateSystemRule') + self.targetCoordinateSystem = 0 + self.useAdvancedData = False + self.originNodeName = '' + self.rotation = [0.0, 0.0, 0.0, 1.0] + self.translation = [0.0, 0.0, 0.0] + self.scale = 1.0 + +class SkeletonOptimizationRule(BaseRule): + """ + Advanced skeleton optimization rule. + + Attributes + ---------- + autoSkeletonLOD: bool + Client side skeleton LOD based on skinning information and critical bones list. + + serverSkeletonOptimization: bool + Server side skeleton optimization based on hit detections and critical bones list. + + criticalBonesList: `list` of SceneNodeSelectionList + Bones in this list will not be optimized out. + + Methods + ------- + + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self): + super().__init__('SkeletonOptimizationRule') + self.autoSkeletonLOD = True + self.serverSkeletonOptimization = False + self.criticalBonesList = SceneNodeSelectionList() + + def to_dict(self): + data = super().to_dict() + self.criticalBonesList.convert_selection(data, 'criticalBonesList') + return data + +class LodRule(BaseRule): + """ + Set up the level of detail for the meshes in this group. + + The engine supports 6 total lods. + 1 for the base model then 5 more lods. + The rule only captures lods past level 0 so this is set to 5. + + Attributes + ---------- + nodeSelectionList: `list` of LodNodeSelectionList + Select the meshes to assign to each level of detail. + + Methods + ------- + + add_lod_level(lodLevel, selectedNodes=None, unselectedNodes=None) + A helper function to add selected nodes (list of node names) and unselected nodes (list of node names) + This creates a LodNodeSelectionList and adds it to the node selection list + returns the LodNodeSelectionList that was created + + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self): + super().__init__('{3CB103B3-CEAF-49D7-A9DC-5A31E2DF15E4} LodRule') + self.nodeSelectionList = [] # list of LodNodeSelectionList + + def add_lod_level(self, lodLevel, selectedNodes=None, unselectedNodes=None) -> LodNodeSelectionList: + lodNodeSelection = LodNodeSelectionList() + lodNodeSelection.selectedNodes = selectedNodes + lodNodeSelection.unselectedNodes = unselectedNodes + lodNodeSelection.lodLevel = lodLevel + self.nodeSelectionList.append(lodNodeSelection) + return lodNodeSelection + + def to_dict(self): + data = super().to_dict() + selectionListList = data.pop('nodeSelectionList') + data['nodeSelectionList'] = [] + for nodeList in selectionListList: + data['nodeSelectionList'].append(nodeList.to_dict()) + return data + +class MorphTargetRule(BaseRule): + """ + Select morph targets for actor. + + Attributes + ---------- + targets: `list` of SceneNodeSelectionList + Select 1 or more meshes to include in the actor as morph targets. + + Methods + ------- + + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self): + super().__init__('MorphTargetRule') + self.targets = SceneNodeSelectionList() + + def to_dict(self): + data = super().to_dict() + self.targets.convert_selection(data, 'targets') + return data + +class CommentRule(BaseRule): + """ + Add an optional comment to the asset's properties. + + Attributes + ---------- + text: str + Text for the comment. + + Methods + ------- + + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self): + super().__init__('CommentRule') + self.text = '' diff --git a/Gems/PythonAssetBuilder/Editor/Scripts/scene_api/physics_data.py b/Gems/PythonAssetBuilder/Editor/Scripts/scene_api/physics_data.py new file mode 100644 index 0000000000..8dea8d8b3a --- /dev/null +++ b/Gems/PythonAssetBuilder/Editor/Scripts/scene_api/physics_data.py @@ -0,0 +1,580 @@ +""" +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 +""" + +# for underlying data structures, see Code\Framework\AzFramework\AzFramework\Physics\Shape.h + +class ColliderConfiguration(): + """ + Configuration for a collider + + Attributes + ---------- + Trigger: bool + Should this shape act as a trigger shape. + + Simulated: bool + Should this shape partake in collision in the physical simulation. + + InSceneQueries: bool + Should this shape partake in scene queries (ray casts, overlap tests, sweeps). + + Exclusive: bool + Can this collider be shared between multiple bodies? + + Position: [float, float, float] Vector3 + Shape offset relative to the connected rigid body. + + Rotation: [float, float, float, float] Quaternion + Shape rotation relative to the connected rigid body. + + ColliderTag: str + Identification tag for the collider. + + RestOffset: float + Bodies will come to rest separated by the sum of their rest offsets. + + ContactOffset: float + Bodies will start to generate contacts when closer than the sum of their contact offsets. + Methods + ------- + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self): + self.Trigger = True + self.Simulated = True + self.InSceneQueries = True + self.Exclusive = True + self.Position = [0.0, 0.0, 0.0] + self.Rotation = [0.0, 0.0, 0.0, 1.0] + self.ColliderTag = '' + self.RestOffset = 0.0 + self.ContactOffset = 0.02 + + def to_dict(self): + return self.__dict__ + +# for underlying data structures, see Code\Framework\AzFramework\AzFramework\Physics\Character.h + +class CharacterColliderNodeConfiguration(): + """ + Shapes to define the animation's to model of physics + + Attributes + ---------- + name : str + debug name of the node + + shapes : `list` of `tuple` of (ColliderConfiguration, ShapeConfiguration) + a list of pairs of collider and shape configuration + + Methods + ------- + add_collider_shape_pair(colliderConfiguration, shapeConfiguration) + Helper function to add a collider and shape configuration at the same time + + to_dict() + Converts contents to a Python dictionary + + """ + def __init__(self): + self.name = '' + self.shapes = [] # List of Tuple of (ColliderConfiguration, ShapeConfiguration) + + def add_collider_shape_pair(self, colliderConfiguration, shapeConfiguration) -> None: + pair = (colliderConfiguration, shapeConfiguration) + self.shapes.append(pair) + + def to_dict(self): + data = {} + shapeList = [] + for index, shape in enumerate(self.shapes): + tupleValue = (shape[0].to_dict(), # ColliderConfiguration + shape[1].to_dict()) # ShapeConfiguration + shapeList.append(tupleValue) + data['name'] = self.name + data['shapes'] = shapeList + return data + +class CharacterColliderConfiguration(): + """ + Information required to create the basic physics representation of a character. + + Attributes + ---------- + nodes : `list` of CharacterColliderNodeConfiguration + a list of CharacterColliderNodeConfiguration nodes + + Methods + ------- + add_character_collider_node_configuration(colliderConfiguration, shapeConfiguration) + Helper function to add a character collider node configuration into the nodes + + add_character_collider_node_configuration_node(name, colliderConfiguration, shapeConfiguration) + Helper function to add a character collider node configuration into the nodes + + **Returns**: CharacterColliderNodeConfiguration + + to_dict() + Converts contents to a Python dictionary + + """ + def __init__(self): + self.nodes = [] # list of CharacterColliderNodeConfiguration + + def add_character_collider_node_configuration(self, characterColliderNodeConfiguration) -> None: + self.nodes.append(characterColliderNodeConfiguration) + + def add_character_collider_node_configuration_node(self, name, colliderConfiguration, shapeConfiguration) -> CharacterColliderNodeConfiguration: + characterColliderNodeConfiguration = CharacterColliderNodeConfiguration() + self.add_character_collider_node_configuration(characterColliderNodeConfiguration) + characterColliderNodeConfiguration.name = name + characterColliderNodeConfiguration.add_collider_shape_pair(colliderConfiguration, shapeConfiguration) + return characterColliderNodeConfiguration + + def to_dict(self): + data = {} + nodeList = [] + for node in self.nodes: + nodeList.append(node.to_dict()) + data['nodes'] = nodeList + return data + +# see Code\Framework\AzFramework\AzFramework\Physics\ShapeConfiguration.h for underlying data structures + +class ShapeConfiguration(): + """ + Base class for all the shape collider configurations + + Attributes + ---------- + scale : [float, float, float] + a 3-element list to describe the scale along the X, Y, and Z axises such as [1.0, 1.0, 1.0] + + Methods + ------- + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self, shapeType): + self._shapeType = shapeType + self.scale = [1.0, 1.0, 1.0] + + def to_dict(self): + return { + "$type": self._shapeType, + "Scale": self.scale + } + +class SphereShapeConfiguration(ShapeConfiguration): + """ + The configuration for a Sphere collider + + Attributes + ---------- + radius: float + a scalar value to define the radius of the sphere + + Methods + ------- + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self): + super().__init__('SphereShapeConfiguration') + self.radius = 0.5 + + def to_dict(self): + data = super().to_dict() + data['Radius'] = self.radius + return data + +class BoxShapeConfiguration(ShapeConfiguration): + """ + The configuration for a Box collider + + Attributes + ---------- + dimensions: [float, float, float] + The width, height, and depth dimensions of the Box collider + + Methods + ------- + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self): + super().__init__('BoxShapeConfiguration') + self.dimensions = [1.0, 1.0, 1.0] + + def to_dict(self): + data = super().to_dict() + data['Configuration'] = self.dimensions + return data + +class CapsuleShapeConfiguration(ShapeConfiguration): + """ + The configuration for a Capsule collider + + Attributes + ---------- + height: float + The height of the Capsule + + radius: float + The radius of the Capsule + + Methods + ------- + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self): + super().__init__('CapsuleShapeConfiguration') + self.height = 1.00 + self.radius = 0.25 + + def to_dict(self): + data = super().to_dict() + data['Height'] = self.height + data['Radius'] = self.radius + return data + +class PhysicsAssetShapeConfiguration(ShapeConfiguration): + """ + The configuration for a Asset collider using a mesh asset for collision + + Attributes + ---------- + asset: { "assetHint": assetReference } + the name of the asset to load for collision information + + assetScale: [float, float, float] + The scale of the asset shape such as [1.0, 1.0, 1.0] + + useMaterialsFromAsset: bool + Auto-set physics materials using asset's physics material names + + subdivisionLevel: int + The level of subdivision if a primitive shape is replaced with a convex mesh due to scaling. + + Methods + ------- + set_asset_reference(self, assetReference: str) + Helper function to set the asset reference to the collision mesh such as 'my/folder/my_mesh.azmodel' + + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self): + super().__init__('PhysicsAssetShapeConfiguration') + self.asset = {} + self.assetScale = [1.0, 1.0, 1.0] + self.useMaterialsFromAsset = True + self.subdivisionLevel = 4 + + def set_asset_reference(self, assetReference: str) -> None: + self.asset = { "assetHint": assetReference } + + def to_dict(self): + data = super().to_dict() + data['PhysicsAsset'] = self.asset + data['AssetScale'] = self.assetScale + data['UseMaterialsFromAsset'] = self.useMaterialsFromAsset + data['SubdivisionLevel'] = self.subdivisionLevel + return data + +# for underlying data structures, see Code\Framework\AzFramework\AzFramework\Physics\Configuration\JointConfiguration.h + +class JointConfiguration(): + """ + The joint configuration + + see also: class AzPhysics::JointConfiguration + + Attributes + ---------- + Name: str + For debugging/tracking purposes only. + + ParentLocalRotation: [float, float, float, float] + Parent joint frame relative to parent body. + + ParentLocalPosition: [float, float, float] + Joint position relative to parent body. + + ChildLocalRotation: [float, float, float, float] + Child joint frame relative to child body. + + ChildLocalPosition: [float, float, float] + Joint position relative to child body. + + StartSimulationEnabled: bool + When active, the joint will be enabled when the simulation begins. + + Methods + ------- + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self): + self.Name = '' + self.ParentLocalRotation = [0.0, 0.0, 0.0, 1.0] + self.ParentLocalPosition = [0.0, 0.0, 0.0] + self.ChildLocalRotation = [0.0, 0.0, 0.0, 1.0] + self.ChildLocalPosition = [0.0, 0.0, 0.0] + self.StartSimulationEnabled = True + + def to_dict(self): + return self.__dict__ + +# for underlying data structures, see Code\Framework\AzFramework\AzFramework\Physics\Configuration\SimulatedBodyConfiguration.h + +class SimulatedBodyConfiguration(): + """ + Base Class of all Physics Bodies that will be simulated. + + see also: class AzPhysics::SimulatedBodyConfiguration + + Attributes + ---------- + name: str + For debugging/tracking purposes only. + + position: [float, float, float] + starting position offset + + orientation: [float, float, float, float] + starting rotation (Quaternion) + + startSimulationEnabled: bool + to start when simulation engine starts + + Methods + ------- + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self): + self.name = '' + self.position = [0.0, 0.0, 0.0] + self.orientation = [0.0, 0.0, 0.0, 1.0] + self.startSimulationEnabled = True + + def to_dict(self): + return { + "name" : self.name, + "position" : self.position, + "orientation" : self.orientation, + "startSimulationEnabled" : self.startSimulationEnabled + } + + +# for underlying data structures, see Code\Framework\AzFramework\AzFramework\Physics\Configuration\RigidBodyConfiguration.h + +class RigidBodyConfiguration(SimulatedBodyConfiguration): + """ + PhysX Rigid Body Configuration + + see also: class AzPhysics::RigidBodyConfiguration + + Attributes + ---------- + initialLinearVelocity: [float, float, float] + Linear velocity applied when the rigid body is activated. + + initialAngularVelocity: [float, float, float] + Angular velocity applied when the rigid body is activated (limited by maximum angular velocity) + + centerOfMassOffset: [float, float, float] + Local space offset for the center of mass (COM). + + mass: float + The mass of the rigid body in kilograms. + A value of 0 is treated as infinite. + The trajectory of infinite mass bodies cannot be affected by any collisions or forces other than gravity. + + linearDamping: float + The rate of decay over time for linear velocity even if no forces are acting on the rigid body. + + angularDamping: float + The rate of decay over time for angular velocity even if no forces are acting on the rigid body. + + sleepMinEnergy: float + The rigid body can go to sleep (settle) when kinetic energy per unit mass is persistently below this value. + + maxAngularVelocity: float + Clamp angular velocities to this maximum value. + + startAsleep: bool + When active, the rigid body will be asleep when spawned, and wake when the body is disturbed. + + interpolateMotion: bool + When active, simulation results are interpolated resulting in smoother motion. + + gravityEnabled: bool + When active, global gravity affects this rigid body. + + kinematic: bool + When active, the rigid body is not affected by gravity or other forces and is moved by script. + + ccdEnabled: bool + When active, the rigid body has continuous collision detection (CCD). + Use this to ensure accurate collision detection, particularly for fast moving rigid bodies. + CCD must be activated in the global PhysX preferences. + + ccdMinAdvanceCoefficient: float + Coefficient affecting how granularly time is subdivided in CCD. + + ccdFrictionEnabled: bool + Whether friction is applied when resolving CCD collisions. + + computeCenterOfMass: bool + Compute the center of mass (COM) for this rigid body. + + computeInertiaTensor: bool + When active, inertia is computed based on the mass and shape of the rigid body. + + computeMass: bool + When active, the mass of the rigid body is computed based on the volume and density values of its colliders. + + Methods + ------- + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self): + super().__init__() + + # Basic initial settings. + self.initialLinearVelocity = [0.0, 0.0, 0.0] + self.initialAngularVelocity = [0.0, 0.0, 0.0] + self.centerOfMassOffset = [0.0, 0.0, 0.0] + + # Simulation parameters. + self.mass = 1.0 + self.linearDamping = 0.05 + self.angularDamping = 0.15 + self.sleepMinEnergy = 0.005 + self.maxAngularVelocity = 100.0 + self.startAsleep = False + self.interpolateMotion = False + self.gravityEnabled = True + self.kinematic = False + self.ccdEnabled = False + self.ccdMinAdvanceCoefficient = 0.15 + self.ccdFrictionEnabled = False + self.computeCenterOfMass = True + self.computeInertiaTensor = True + self.computeMass = True + + # Flags to restrict motion along specific world-space axes. + self.lockLinearX = False + self.lockLinearY = False + self.lockLinearZ = False + + # Flags to restrict rotation around specific world-space axes. + self.lockAngularX = False + self.lockAngularY = False + self.lockAngularZ = False + + # If set, non-simulated shapes will also be included in the mass properties calculation. + self.includeAllShapesInMassCalculation = False + + def to_dict(self): + data = super().to_dict() + data["Initial linear velocity"] = self.initialLinearVelocity + data["Initial angular velocity"] = self.initialAngularVelocity + data["Linear damping"] = self.linearDamping + data["Angular damping"] = self.angularDamping + data["Sleep threshold"] = self.sleepMinEnergy + data["Start Asleep"] = self.startAsleep + data["Interpolate Motion"] = self.interpolateMotion + data["Gravity Enabled"] = self.gravityEnabled + data["Kinematic"] = self.kinematic + data["CCD Enabled"] = self.ccdEnabled + data["Compute Mass"] = self.computeMass + data["Lock Linear X"] = self.lockLinearX + data["Lock Linear Y"] = self.lockLinearY + data["Lock Linear Z"] = self.lockLinearZ + data["Lock Angular X"] = self.lockAngularX + data["Lock Angular Y"] = self.lockAngularY + data["Lock Angular Z"] = self.lockAngularZ + data["Mass"] = self.mass + data["Compute COM"] = self.computeCenterOfMass + data["Centre of mass offset"] = self.centerOfMassOffset + data["Compute inertia"] = self.computeInertiaTensor + data["Maximum Angular Velocity"] = self.maxAngularVelocity + data["Include All Shapes In Mass"] = self.includeAllShapesInMassCalculation + data["CCD Min Advance"] = self.ccdMinAdvanceCoefficient + data["CCD Friction"] = self.ccdFrictionEnabled + return data + +# for underlying data structures, see Code\Framework\AzFramework\AzFramework\Physics\Ragdoll.h + +class RagdollNodeConfiguration(RigidBodyConfiguration): + """ + Ragdoll node Configuration + + see also: class Physics::RagdollConfiguration + + Attributes + ---------- + JointConfig: JointConfiguration + Ragdoll joint node configuration + + Methods + ------- + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self): + super().__init__() + self.JointConfig = JointConfiguration() + + def to_dict(self): + data = super().to_dict() + data['JointConfig'] = self.JointConfig.to_dict() + return data + +class RagdollConfiguration(): + """ + A configuration of join nodes and a character collider configuration for a ragdoll + + see also: class Physics::RagdollConfiguration + + Attributes + ---------- + nodes: `list` of RagdollNodeConfiguration + A list of RagdollNodeConfiguration entries + + colliders: CharacterColliderConfiguration + A CharacterColliderConfiguration + + Methods + ------- + add_ragdoll_node_configuration(ragdollNodeConfiguration) + Helper function to add a single ragdoll node configuration (normally for each joint/bone node) + + to_dict() + Converts contents to a Python dictionary + """ + def __init__(self): + self.nodes = [] # list of RagdollNodeConfiguration + self.colliders = CharacterColliderConfiguration() + + def add_ragdoll_node_configuration(self, ragdollNodeConfiguration) -> None: + self.nodes.append(ragdollNodeConfiguration) + + def to_dict(self): + data = {} + nodeList = [] + for index, node in enumerate(self.nodes): + nodeList.append(node.to_dict()) + data['nodes'] = nodeList + data['colliders'] = self.colliders.to_dict() + return data From 6cf805256bebb03d726d7fe018cb890c03d04da7 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Mon, 6 Dec 2021 15:55:35 -0800 Subject: [PATCH 116/128] Make backend write API string-based Signed-off-by: Nicholas Van Sickle --- .../Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h | 4 +++- Code/Framework/AzCore/AzCore/DOM/DomBackend.h | 4 ++-- Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp | 6 ------ Code/Framework/AzCore/AzCore/DOM/DomUtils.h | 2 -- Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp | 6 +++--- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h index 45825ff92d..1023796f61 100644 --- a/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h +++ b/Code/Framework/AzCore/AzCore/DOM/Backends/JSON/JsonBackend.h @@ -10,6 +10,7 @@ #include #include +#include namespace AZ::Dom { @@ -32,8 +33,9 @@ namespace AZ::Dom return Json::VisitSerializedJsonInPlace(buffer, visitor); } - Visitor::Result WriteToStream(AZ::IO::GenericStream& stream, WriteCallback callback) override + Visitor::Result WriteToBuffer(AZStd::string& buffer, WriteCallback callback) { + AZ::IO::ByteContainerStream stream{ &buffer }; AZStd::unique_ptr visitor = Json::CreateJsonStreamWriter(stream, WriteFormat); return callback(*visitor); } diff --git a/Code/Framework/AzCore/AzCore/DOM/DomBackend.h b/Code/Framework/AzCore/AzCore/DOM/DomBackend.h index 6c9c40ef0e..2e4ccf8f3e 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomBackend.h +++ b/Code/Framework/AzCore/AzCore/DOM/DomBackend.h @@ -38,7 +38,7 @@ namespace AZ::Dom //! A callback that accepts a Visitor, making DOM calls to inform the serializer, and returns an //! aggregate error code to indicate whether or not the operation succeeded. using WriteCallback = AZStd::function; - //! Attempt to write a value to a stream using a write callback. - virtual Visitor::Result WriteToStream(AZ::IO::GenericStream& stream, WriteCallback callback) = 0; + //! Attempt to write a value to the specified string using a write callback. + virtual Visitor::Result WriteToBuffer(AZStd::string& buffer, WriteCallback callback) = 0; }; } // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp b/Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp index ca27b177bd..9751b9cecc 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/DomUtils.cpp @@ -21,10 +21,4 @@ namespace AZ::Dom::Utils { return backend.ReadFromBufferInPlace(string.data(), string.size(), visitor); } - - Visitor::Result WriteToString(Backend& backend, AZStd::string& buffer, Backend::WriteCallback writeCallback) - { - AZ::IO::ByteContainerStream stream{ &buffer }; - return backend.WriteToStream(stream, writeCallback); - } } diff --git a/Code/Framework/AzCore/AzCore/DOM/DomUtils.h b/Code/Framework/AzCore/AzCore/DOM/DomUtils.h index cd64d2e107..84a6eb5687 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomUtils.h +++ b/Code/Framework/AzCore/AzCore/DOM/DomUtils.h @@ -14,6 +14,4 @@ namespace AZ::Dom::Utils { Visitor::Result ReadFromString(Backend& backend, AZStd::string_view string, AZ::Dom::Lifetime lifetime, Visitor& visitor); Visitor::Result ReadFromStringInPlace(Backend& backend, AZStd::string& string, Visitor& visitor); - - Visitor::Result WriteToString(Backend& backend, AZStd::string& buffer, Backend::WriteCallback writeCallback); } // namespace AZ::Dom::Utils diff --git a/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp b/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp index b408cd2466..c7af6438cf 100644 --- a/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp +++ b/Code/Framework/AzCore/Tests/DOM/DomJsonTests.cpp @@ -71,7 +71,7 @@ namespace AZ::Dom::Tests { AZStd::string serializedDocument; JsonBackend backend; - auto result = Dom::Utils::WriteToString(backend, serializedDocument, visitDocumentFn); + auto result = backend.WriteToBuffer(serializedDocument, visitDocumentFn); EXPECT_TRUE(result.IsSuccess()); EXPECT_EQ(canonicalSerializedDocument, serializedDocument); } @@ -92,8 +92,8 @@ namespace AZ::Dom::Tests { AZStd::string serializedDocument; JsonBackend backend; - auto result = Dom::Utils::WriteToString( - backend, serializedDocument, + auto result = backend.WriteToBuffer( + serializedDocument, [&backend, &canonicalSerializedDocument](AZ::Dom::Visitor& visitor) { return Dom::Utils::ReadFromString(backend, canonicalSerializedDocument, Lifetime::Temporary, visitor); From ad3148ece52405e481e6d1f5cc572915625d59c2 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Mon, 6 Dec 2021 16:05:55 -0800 Subject: [PATCH 117/128] add new enter_exit_game_mode_take_screenshot() shared function Signed-off-by: jromnoa <80134229+jromnoa@users.noreply.github.com> --- .../Atom/atom_utils/atom_component_helper.py | 22 ++++++++++ .../hydra_AtomGPU_AreaLightScreenshotTest.py | 34 ++++------------ .../hydra_AtomGPU_SpotLightScreenshotTest.py | 40 ++++--------------- .../editor_python_test_tools/utils.py | 6 +-- 4 files changed, 39 insertions(+), 63 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py index 6212ba4314..5fdd4c810d 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py @@ -126,6 +126,28 @@ def initial_viewport_setup(screen_width=1280, screen_height=720): general.update_viewport() +def enter_exit_game_mode_take_screenshot(screenshot_name, enter_game_tuple, exit_game_tuple, timeout_in_seconds=4): + """ + Enters game mode, takes a screenshot named screenshot_name (must include file extension), and exits game mode. + :param screenshot_name: string representing the name of the screenshot file, including file extension. + :param enter_game_tuple: tuple where the 1st string is success & 2nd string is failure for entering the game. + :param exit_game_tuple: tuple where the 1st string is success & 2nd string is failure for exiting the game. + :param timeout_in_seconds: int or float seconds to wait for entering/exiting game mode. + :return: None + """ + import azlmbr.legacy.general as general + + from editor_python_test_tools.utils import TestHelper + + from Atom.atom_utils.screenshot_utils import ScreenshotHelper + + TestHelper.enter_game_mode(enter_game_tuple) + TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=timeout_in_seconds) + ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking(screenshot_name) + TestHelper.exit_game_mode(exit_game_tuple) + TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=timeout_in_seconds) + + def create_basic_atom_rendering_scene(): """ Sets up a new scene inside the Editor for testing Atom rendering GPU output. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_AreaLightScreenshotTest.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_AreaLightScreenshotTest.py index d9a24c13ec..03f842f9b4 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_AreaLightScreenshotTest.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_AreaLightScreenshotTest.py @@ -79,8 +79,8 @@ def AtomGPU_LightComponent_AreaLightScreenshotsMatchGoldenImages(): from editor_python_test_tools.utils import Report, Tracer, TestHelper from Atom.atom_utils.atom_constants import AtomComponentProperties, LIGHT_TYPES - from Atom.atom_utils.atom_component_helper import initial_viewport_setup, create_basic_atom_rendering_scene - from Atom.atom_utils.screenshot_utils import ScreenshotHelper + from Atom.atom_utils.atom_component_helper import ( + initial_viewport_setup, create_basic_atom_rendering_scene, enter_exit_game_mode_take_screenshot) DEGREE_RADIAN_FACTOR = 0.0174533 @@ -129,11 +129,7 @@ def AtomGPU_LightComponent_AreaLightScreenshotsMatchGoldenImages(): AtomComponentProperties.light('Color')) == light_component_color_value) # 5. Enter game mode and take a screenshot then exit game mode. - TestHelper.enter_game_mode(Tests.enter_game_mode) - TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) - ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("AreaLight_1.ppm") - TestHelper.exit_game_mode(Tests.exit_game_mode) - TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + enter_exit_game_mode_take_screenshot("AreaLight_1.ppm", Tests.enter_game_mode, Tests.exit_game_mode) # 6. Set the Intensity property of the Light component to 0.0. light_component.set_component_property_value(AtomComponentProperties.light('Intensity'), 0.0) @@ -148,11 +144,7 @@ def AtomGPU_LightComponent_AreaLightScreenshotsMatchGoldenImages(): light_component.get_component_property_value(AtomComponentProperties.light('Attenuation Radius Mode')) == 1) # 8. Enter game mode and take a screenshot then exit game mode. - TestHelper.enter_game_mode(Tests.enter_game_mode) - TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) - ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("AreaLight_2.ppm") - TestHelper.exit_game_mode(Tests.exit_game_mode) - TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + enter_exit_game_mode_take_screenshot("AreaLight_2.ppm", Tests.enter_game_mode, Tests.exit_game_mode) # 9. Set the Intensity property of the Light component to 1000.0 light_component.set_component_property_value(AtomComponentProperties.light('Intensity'), 1000.0) @@ -161,11 +153,7 @@ def AtomGPU_LightComponent_AreaLightScreenshotsMatchGoldenImages(): light_component.get_component_property_value(AtomComponentProperties.light('Intensity')) == 1000.0) # 10. Enter game mode and take a screenshot then exit game mode. - TestHelper.enter_game_mode(Tests.enter_game_mode) - TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) - ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("AreaLight_3.ppm") - TestHelper.exit_game_mode(Tests.exit_game_mode) - TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + enter_exit_game_mode_take_screenshot("AreaLight_3.ppm", Tests.enter_game_mode, Tests.exit_game_mode) # 11. Set the Light type property to Spot (disk) for the Light component & # rotate DEGREE_RADIAN_FACTOR * 90 degrees. @@ -179,11 +167,7 @@ def AtomGPU_LightComponent_AreaLightScreenshotsMatchGoldenImages(): AtomComponentProperties.light('Light type')) == LIGHT_TYPES['spot_disk']) # 12. Enter game mode and take a screenshot then exit game mode. - TestHelper.enter_game_mode(Tests.enter_game_mode) - TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) - ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("AreaLight_4.ppm") - TestHelper.exit_game_mode(Tests.exit_game_mode) - TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + enter_exit_game_mode_take_screenshot("AreaLight_4.ppm", Tests.enter_game_mode, Tests.exit_game_mode) # 13. Set the Light type property to Point (sphere) instead of Spot (disk) for the Light component. light_component.set_component_property_value( @@ -194,11 +178,7 @@ def AtomGPU_LightComponent_AreaLightScreenshotsMatchGoldenImages(): AtomComponentProperties.light('Light type')) == LIGHT_TYPES['sphere']) # 14. Enter game mode and take a screenshot then exit game mode. - TestHelper.enter_game_mode(Tests.enter_game_mode) - TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) - ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("AreaLight_4.ppm") - TestHelper.exit_game_mode(Tests.exit_game_mode) - TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + enter_exit_game_mode_take_screenshot("AreaLight_5.ppm", Tests.enter_game_mode, Tests.exit_game_mode) # 15. Delete the Area Light entity. area_light_entity.delete() diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py index dd2470e8b2..0c099dc04d 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py @@ -101,8 +101,8 @@ def AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages(): from editor_python_test_tools.utils import Report, Tracer, TestHelper from Atom.atom_utils.atom_constants import AtomComponentProperties, LIGHT_TYPES - from Atom.atom_utils.atom_component_helper import initial_viewport_setup, create_basic_atom_rendering_scene - from Atom.atom_utils.screenshot_utils import ScreenshotHelper + from Atom.atom_utils.atom_component_helper import ( + initial_viewport_setup, create_basic_atom_rendering_scene, enter_exit_game_mode_take_screenshot) DEGREE_RADIAN_FACTOR = 0.0174533 @@ -164,11 +164,7 @@ def AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages(): AtomComponentProperties.light('Light type')) == LIGHT_TYPES['spot_disk']) # 7. Enter game mode and take a screenshot then exit game mode. - TestHelper.enter_game_mode(Tests.enter_game_mode) - TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) - ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("SpotLight_1.ppm") - TestHelper.exit_game_mode(Tests.exit_game_mode) - TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + enter_exit_game_mode_take_screenshot("SpotLight_1.ppm", Tests.enter_game_mode, Tests.exit_game_mode) # 8. Change the default material asset for the Ground Plane entity. ground_plane_name = "Ground Plane" @@ -187,11 +183,7 @@ def AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages(): AtomComponentProperties.material('Material Asset')) == ground_plane_material_asset.id) # 9. Enter game mode and take a screenshot then exit game mode. - TestHelper.enter_game_mode(Tests.enter_game_mode) - TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) - ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("SpotLight_2.ppm") - TestHelper.exit_game_mode(Tests.exit_game_mode) - TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + enter_exit_game_mode_take_screenshot("SpotLight_2.ppm", Tests.enter_game_mode, Tests.exit_game_mode) # 10. Increase the Intensity value of the Light component. light_component.set_component_property_value(AtomComponentProperties.light('Intensity'), 800.0) @@ -201,11 +193,7 @@ def AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages(): AtomComponentProperties.light('Intensity')) == 800.0) # 11. Enter game mode and take a screenshot then exit game mode. - TestHelper.enter_game_mode(Tests.enter_game_mode) - TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) - ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("SpotLight_3.ppm") - TestHelper.exit_game_mode(Tests.exit_game_mode) - TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + enter_exit_game_mode_take_screenshot("SpotLight_3.ppm", Tests.enter_game_mode, Tests.exit_game_mode) # 12. Change the Light component Color property value. color_value = azlmbr.math.Color(47.0 / 255.0, 75.0 / 255.0, 37.0 / 255.0, 255.0 / 255.0) @@ -215,11 +203,7 @@ def AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages(): light_component.get_component_property_value(AtomComponentProperties.light('Color')) == color_value) # 13. Enter game mode and take a screenshot then exit game mode. - TestHelper.enter_game_mode(Tests.enter_game_mode) - TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) - ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("SpotLight_4.ppm") - TestHelper.exit_game_mode(Tests.exit_game_mode) - TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + enter_exit_game_mode_take_screenshot("SpotLight_4.ppm", Tests.enter_game_mode, Tests.exit_game_mode) # 14. Change the Light component Enable shutters, Inner angle, and Outer angle property values. enable_shutters = True @@ -240,11 +224,7 @@ def AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages(): light_component.get_component_property_value(AtomComponentProperties.light('Outer angle')) == outer_angle) # 15. Enter game mode and take a screenshot then exit game mode. - TestHelper.enter_game_mode(Tests.enter_game_mode) - TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) - ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("SpotLight_5.ppm") - TestHelper.exit_game_mode(Tests.exit_game_mode) - TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + enter_exit_game_mode_take_screenshot("SpotLight_5.ppm", Tests.enter_game_mode, Tests.exit_game_mode) # 16. Change the Light component Enable shadow and slightly move Spot Light entity. light_component.set_component_property_value(AtomComponentProperties.light('Enable shadow'), True) @@ -254,11 +234,7 @@ def AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages(): spot_light_entity.set_world_rotation(azlmbr.math.Vector3(0.7, -2.0, 1.9)) # 17. Enter game mode and take a screenshot then exit game mode. - TestHelper.enter_game_mode(Tests.enter_game_mode) - TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) - ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking("SpotLight_6.ppm") - TestHelper.exit_game_mode(Tests.exit_game_mode) - TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + enter_exit_game_mode_take_screenshot("SpotLight_6.ppm", Tests.enter_game_mode, Tests.exit_game_mode) # 18. Look for errors. TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py index 481d73274f..7231af4a12 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py @@ -56,8 +56,7 @@ class TestHelper: general.idle_wait_frames(200) @staticmethod - def enter_game_mode(msgtuple_success_fail : Tuple[str, str]): - # type: (tuple) -> None + def enter_game_mode(msgtuple_success_fail: Tuple[str, str]) -> None: """ :param msgtuple_success_fail: The tuple with the expected/unexpected messages for entering game mode. @@ -70,8 +69,7 @@ class TestHelper: Report.critical_result(msgtuple_success_fail, general.is_in_game_mode()) @staticmethod - def multiplayer_enter_game_mode(msgtuple_success_fail : Tuple[str, str], sv_default_player_spawn_asset : str): - # type: (tuple) -> None + def multiplayer_enter_game_mode(msgtuple_success_fail: Tuple[str, str], sv_default_player_spawn_asset: str) -> None: """ :param msgtuple_success_fail: The tuple with the expected/unexpected messages for entering game mode. :param sv_default_player_spawn_asset: The path to the network player prefab that will be automatically spawned upon entering gamemode. The engine default is "prefabs/player.network.spawnable" From 9698047340e6552ee6bcbe2d406ade46406a8b5a Mon Sep 17 00:00:00 2001 From: benblack75 Date: Mon, 6 Dec 2021 16:18:32 -0800 Subject: [PATCH 118/128] Modified Color Swatch Fix (#6137) * Modified Color Swatch Fix Signed-off-by: Benjamin Black * Updating Macbeth Colors to work with new material formatting Signed-off-by: Benjamin Black * Tweaks to red color values Signed-off-by: Benjamin Black * Tweaked red swatch color values provided by Ken Signed-off-by: Benjamin Black --- .../Materials/Presets/MacBeth/00_illuminant_tex.material | 1 + .../Assets/Materials/Presets/MacBeth/01_dark_skin.material | 1 - .../Materials/Presets/MacBeth/01_dark_skin_tex.material | 2 ++ .../Materials/Presets/MacBeth/02_light_skin.material | 1 - .../Materials/Presets/MacBeth/02_light_skin_tex.material | 2 ++ .../Assets/Materials/Presets/MacBeth/03_blue_sky.material | 1 - .../Materials/Presets/MacBeth/03_blue_sky_tex.material | 2 ++ .../Materials/Presets/MacBeth/04_foliage_tex.material | 1 + .../Materials/Presets/MacBeth/05_blue_flower_tex.material | 1 + .../Materials/Presets/MacBeth/06_bluish_green.material | 1 - .../Materials/Presets/MacBeth/06_bluish_green_tex.material | 2 ++ .../Materials/Presets/MacBeth/07_orange_tex.material | 1 + .../Materials/Presets/MacBeth/08_purplish_blue.material | 1 - .../Presets/MacBeth/08_purplish_blue_tex.material | 2 ++ .../Materials/Presets/MacBeth/09_moderate_red.material | 1 - .../Materials/Presets/MacBeth/09_moderate_red_tex.material | 2 ++ .../Assets/Materials/Presets/MacBeth/10_purple.material | 1 - .../Materials/Presets/MacBeth/10_purple_tex.material | 2 ++ .../Materials/Presets/MacBeth/11_yellow_green.material | 1 - .../Materials/Presets/MacBeth/11_yellow_green_tex.material | 2 ++ .../Materials/Presets/MacBeth/12_orange_yellow.material | 1 - .../Presets/MacBeth/12_orange_yellow_tex.material | 2 ++ .../Assets/Materials/Presets/MacBeth/13_blue.material | 1 - .../Assets/Materials/Presets/MacBeth/13_blue_tex.material | 2 ++ .../Assets/Materials/Presets/MacBeth/14_green.material | 1 - .../Assets/Materials/Presets/MacBeth/14_green_tex.material | 2 ++ .../Assets/Materials/Presets/MacBeth/15_red.material | 7 +++---- .../Assets/Materials/Presets/MacBeth/15_red_sRGB.tif | 4 ++-- .../Assets/Materials/Presets/MacBeth/15_red_tex.material | 2 ++ .../Assets/Materials/Presets/MacBeth/16_yellow.material | 1 - .../Materials/Presets/MacBeth/16_yellow_tex.material | 2 ++ .../Assets/Materials/Presets/MacBeth/17_magenta.material | 1 - .../Materials/Presets/MacBeth/17_magenta_tex.material | 2 ++ .../Assets/Materials/Presets/MacBeth/18_cyan.material | 1 - .../Assets/Materials/Presets/MacBeth/18_cyan_tex.material | 2 ++ .../Materials/Presets/MacBeth/19_white_9-5_0-05D.material | 1 - .../Presets/MacBeth/19_white_9-5_0-05D_tex.material | 2 ++ .../Presets/MacBeth/20_neutral_8-0_0-23D.material | 1 - .../Presets/MacBeth/20_neutral_8-0_0-23D_tex.material | 2 ++ .../Presets/MacBeth/21_neutral_6-5_0-44D.material | 1 - .../Presets/MacBeth/21_neutral_6-5_0-44D_tex.material | 2 ++ .../Presets/MacBeth/22_neutral_5-0_0-70D.material | 1 - .../Presets/MacBeth/22_neutral_5-0_0-70D_tex.material | 2 ++ .../Presets/MacBeth/23_neutral_3-5_1-05D.material | 1 - .../Presets/MacBeth/23_neutral_3-5_1-05D_tex.material | 2 ++ .../Materials/Presets/MacBeth/24_black_2-0_1-50D.material | 1 - .../Presets/MacBeth/24_black_2-0_1-50D_tex.material | 2 ++ 47 files changed, 51 insertions(+), 26 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/00_illuminant_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/00_illuminant_tex.material index 22b9c9f4f6..191073e26a 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/00_illuminant_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/00_illuminant_tex.material @@ -5,6 +5,7 @@ "materialTypeVersion": 4, "properties": { "baseColor": { + "textureBlendMode": "Lerp", "textureMap": "00_illuminant_sRGB.tif" } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/01_dark_skin.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/01_dark_skin.material index 534d4f0e85..46666228bf 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/01_dark_skin.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/01_dark_skin.material @@ -11,7 +11,6 @@ 0.056122682988643646, 1.0 ], - "textureMap": "01_dark_skin_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/01_dark_skin_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/01_dark_skin_tex.material index 172f6ea142..487ef2c279 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/01_dark_skin_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/01_dark_skin_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "01_dark_skin_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/02_light_skin.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/02_light_skin.material index 13831b6c55..bd6f235f51 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/02_light_skin.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/02_light_skin.material @@ -11,7 +11,6 @@ 0.21953155100345612, 1.0 ], - "textureMap": "02_light_skin_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/02_light_skin_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/02_light_skin_tex.material index bd886e2dfe..f452446dad 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/02_light_skin_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/02_light_skin_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "02_light_skin_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/03_blue_sky.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/03_blue_sky.material index 47afe4d792..fad628e885 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/03_blue_sky.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/03_blue_sky.material @@ -11,7 +11,6 @@ 0.33716335892677307, 1.0 ], - "textureMap": "03_blue_sky_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/03_blue_sky_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/03_blue_sky_tex.material index 0760647c9d..9a64b15f79 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/03_blue_sky_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/03_blue_sky_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "03_blue_sky_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/04_foliage_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/04_foliage_tex.material index bb83083003..406508701d 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/04_foliage_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/04_foliage_tex.material @@ -11,6 +11,7 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", "textureMap": "04_foliage_sRGB.tif" } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/05_blue_flower_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/05_blue_flower_tex.material index 5f83eecd82..5e9085f53f 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/05_blue_flower_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/05_blue_flower_tex.material @@ -11,6 +11,7 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", "textureMap": "05_blue_flower_sRGB.tif" } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/06_bluish_green.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/06_bluish_green.material index fd20326fe2..a8e411ddcd 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/06_bluish_green.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/06_bluish_green.material @@ -11,7 +11,6 @@ 0.40723279118537903, 1.0 ], - "textureMap": "06_bluish_green_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/06_bluish_green_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/06_bluish_green_tex.material index a5d7541fe2..63392a2ced 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/06_bluish_green_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/06_bluish_green_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "06_bluish_green_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/07_orange_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/07_orange_tex.material index 7ebc7ab081..c39a5283f5 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/07_orange_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/07_orange_tex.material @@ -11,6 +11,7 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", "textureMap": "07_orange_sRGB.tif" } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/08_purplish_blue.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/08_purplish_blue.material index 4884aef6ab..4abdf60285 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/08_purplish_blue.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/08_purplish_blue.material @@ -11,7 +11,6 @@ 0.39157700538635254, 1.0 ], - "textureMap": "08_purplish_blue_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/08_purplish_blue_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/08_purplish_blue_tex.material index 6722af151c..867065b3c8 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/08_purplish_blue_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/08_purplish_blue_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "08_purplish_blue_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/09_moderate_red.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/09_moderate_red.material index 1a49b6339b..0e38da555b 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/09_moderate_red.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/09_moderate_red.material @@ -11,7 +11,6 @@ 0.12213321030139923, 1.0 ], - "textureMap": "09_moderate_red_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/09_moderate_red_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/09_moderate_red_tex.material index cddceff49a..5beb254b70 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/09_moderate_red_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/09_moderate_red_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "09_moderate_red_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/10_purple.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/10_purple.material index 792881c65c..98ba44f372 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/10_purple.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/10_purple.material @@ -11,7 +11,6 @@ 0.1412680298089981, 1.0 ], - "textureMap": "10_purple_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/10_purple_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/10_purple_tex.material index 09e57d0cae..0e2b397bbf 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/10_purple_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/10_purple_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "10_purple_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/11_yellow_green.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/11_yellow_green.material index ec49ed13d2..e31941cea0 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/11_yellow_green.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/11_yellow_green.material @@ -11,7 +11,6 @@ 0.0481727309525013, 1.0 ], - "textureMap": "11_yellow_green_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/11_yellow_green_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/11_yellow_green_tex.material index 35e77c9ced..ff46c8d451 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/11_yellow_green_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/11_yellow_green_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "11_yellow_green_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/12_orange_yellow.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/12_orange_yellow.material index 6c7fcd08cd..101fadbe5d 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/12_orange_yellow.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/12_orange_yellow.material @@ -11,7 +11,6 @@ 0.02217135950922966, 1.0 ], - "textureMap": "12_orange_yellow_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/12_orange_yellow_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/12_orange_yellow_tex.material index 9a198e2d84..96d112c42b 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/12_orange_yellow_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/12_orange_yellow_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "12_orange_yellow_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/13_blue.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/13_blue.material index 91d337919f..cc607f8812 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/13_blue.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/13_blue.material @@ -11,7 +11,6 @@ 0.29176774621009827, 1.0 ], - "textureMap": "13_blue_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/13_blue_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/13_blue_tex.material index b294d8d2d4..51ffbee6ed 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/13_blue_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/13_blue_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "13_blue_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/14_green.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/14_green.material index 29bb867531..22ea9ceb44 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/14_green.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/14_green.material @@ -11,7 +11,6 @@ 0.06480506807565689, 1.0 ], - "textureMap": "14_green_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/14_green_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/14_green_tex.material index 8e2df1342f..703b755f8e 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/14_green_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/14_green_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "14_green_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/15_red.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/15_red.material index 553d1584a5..3f689a9ee8 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/15_red.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/15_red.material @@ -6,12 +6,11 @@ "properties": { "baseColor": { "color": [ - 0.43414968252182007, - 0.029556725174188614, - 0.03955138474702835, + 0.43244872157, + 0.0297351510059, + 0.0399429307193, 1.0 ], - "textureMap": "15_red_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/15_red_sRGB.tif b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/15_red_sRGB.tif index eccc30b408..4c150db62f 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/15_red_sRGB.tif +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/15_red_sRGB.tif @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:19e05a0f796d3a9de91ae56b4e802af8e6ad683b79275365c3220564f9eea05c -size 19460 +oid sha256:b53b8ca6b7062239398820aef6fb4145a0b6c8c7e3aae90c17b6b87f806d3579 +size 19426 diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/15_red_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/15_red_tex.material index a3b472c083..83d2983bec 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/15_red_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/15_red_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "15_red_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/16_yellow.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/16_yellow.material index a28aa13685..5dc609aa14 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/16_yellow.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/16_yellow.material @@ -11,7 +11,6 @@ 0.00802624598145485, 1.0 ], - "textureMap": "16_yellow_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/16_yellow_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/16_yellow_tex.material index c7fa73d87b..79dc6ccdcd 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/16_yellow_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/16_yellow_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "16_yellow_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/17_magenta.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/17_magenta.material index d30ef62a63..1401e77bd6 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/17_magenta.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/17_magenta.material @@ -11,7 +11,6 @@ 0.30498206615448, 1.0 ], - "textureMap": "17_magenta_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/17_magenta_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/17_magenta_tex.material index e4c3b35e2e..cfba129671 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/17_magenta_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/17_magenta_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "17_magenta_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/18_cyan.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/18_cyan.material index efd9aa4005..8a98ff95b5 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/18_cyan.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/18_cyan.material @@ -11,7 +11,6 @@ 0.3813229501247406, 1.0 ], - "textureMap": "18_cyan_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/18_cyan_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/18_cyan_tex.material index 2975d48196..a16b776687 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/18_cyan_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/18_cyan_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "18_cyan_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/19_white_9-5_0-05D.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/19_white_9-5_0-05D.material index 462e969d65..11dbd6b84d 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/19_white_9-5_0-05D.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/19_white_9-5_0-05D.material @@ -11,7 +11,6 @@ 0.8713664412498474, 1.0 ], - "textureMap": "19_white_9-5_0-05D_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/19_white_9-5_0-05D_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/19_white_9-5_0-05D_tex.material index 452a891639..424366ced6 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/19_white_9-5_0-05D_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/19_white_9-5_0-05D_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "19_white_9-5_0-05D_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/20_neutral_8-0_0-23D.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/20_neutral_8-0_0-23D.material index cc8a1b1b14..63ba366588 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/20_neutral_8-0_0-23D.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/20_neutral_8-0_0-23D.material @@ -11,7 +11,6 @@ 0.5840848684310913, 1.0 ], - "textureMap": "20_neutral_8-0_0-23D_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/20_neutral_8-0_0-23D_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/20_neutral_8-0_0-23D_tex.material index d46a64105e..5cd5c32c7b 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/20_neutral_8-0_0-23D_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/20_neutral_8-0_0-23D_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "20_neutral_8-0_0-23D_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/21_neutral_6-5_0-44D.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/21_neutral_6-5_0-44D.material index 462259b193..4e7379e704 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/21_neutral_6-5_0-44D.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/21_neutral_6-5_0-44D.material @@ -11,7 +11,6 @@ 0.35640496015548706, 1.0 ], - "textureMap": "21_neutral_6-5_0-44D_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/21_neutral_6-5_0-44D_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/21_neutral_6-5_0-44D_tex.material index 4072adf8cf..276177699a 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/21_neutral_6-5_0-44D_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/21_neutral_6-5_0-44D_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "21_neutral_6-5_0-44D_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/22_neutral_5-0_0-70D.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/22_neutral_5-0_0-70D.material index a5b5cf4127..894c3826c3 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/22_neutral_5-0_0-70D.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/22_neutral_5-0_0-70D.material @@ -11,7 +11,6 @@ 0.191195547580719, 1.0 ], - "textureMap": "22_neutral_5-0_0-70D_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/22_neutral_5-0_0-70D_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/22_neutral_5-0_0-70D_tex.material index 7dc6016eed..b365408fae 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/22_neutral_5-0_0-70D_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/22_neutral_5-0_0-70D_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "22_neutral_5-0_0-70D_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/23_neutral_3-5_1-05D.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/23_neutral_3-5_1-05D.material index e69f1a7827..33a89bae94 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/23_neutral_3-5_1-05D.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/23_neutral_3-5_1-05D.material @@ -11,7 +11,6 @@ 0.09083695709705353, 1.0 ], - "textureMap": "23_neutral_3-5_1-05D_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/23_neutral_3-5_1-05D_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/23_neutral_3-5_1-05D_tex.material index 2611311790..ddade882b3 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/23_neutral_3-5_1-05D_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/23_neutral_3-5_1-05D_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "23_neutral_3-5_1-05D_sRGB.tif", "useTexture": true } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/24_black_2-0_1-50D.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/24_black_2-0_1-50D.material index 1222c09018..0e7f6a7bc1 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/24_black_2-0_1-50D.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/24_black_2-0_1-50D.material @@ -11,7 +11,6 @@ 0.0318913571536541, 1.0 ], - "textureMap": "24_black_2-0_1-50D_sRGB.tif", "useTexture": false } } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/24_black_2-0_1-50D_tex.material b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/24_black_2-0_1-50D_tex.material index c60f696b58..a3c95a8e71 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/24_black_2-0_1-50D_tex.material +++ b/Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/24_black_2-0_1-50D_tex.material @@ -11,6 +11,8 @@ 1.0, 1.0 ], + "textureBlendMode": "Lerp", + "textureMap": "24_black_2-0_1-50D_sRGB.tif", "useTexture": true } } From 9d6dc1ac637eb50ad2cd9868fd91720be2de2f48 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Mon, 6 Dec 2021 16:38:42 -0800 Subject: [PATCH 119/128] add ATTENUATION_RADIUS_MODE constant with its 2 available options of automatic or explicit Signed-off-by: jromnoa <80134229+jromnoa@users.noreply.github.com> --- .../PythonTests/Atom/atom_utils/atom_constants.py | 13 +++++++++++++ .../tests/hydra_AtomGPU_AreaLightScreenshotTest.py | 8 +++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py index 59a07cf7bc..400349c5ee 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py @@ -18,6 +18,12 @@ LIGHT_TYPES = { 'simple_spot': 7, } +# Attenuation Radius Mode options for the Light component. +ATTENUATION_RADIUS_MODE = { + 'automatic': 1, + 'explicit': 0, +} + class AtomComponentProperties: """ @@ -249,7 +255,14 @@ class AtomComponentProperties: def light(property: str = 'name') -> str: """ Light component properties. + - 'Attenuation Radius Mode' controls whether the attenuation radius is calculated automatically or explicitly. + - 'Color' the RGB value to set for the color of the light. + - 'Enable shadow' toggle for enabling shadows for the light. + - 'Enable shutters' toggle for enabling shutters for the light. + - 'Inner angle' inner angle value for the shutters (in degrees) + - 'Intensity' the intensity of the light in the set photometric unit (float with no ceiling). - 'Light type' from atom_constants.py LIGHT_TYPES + - 'Outer angle' outer angle value for the shutters (in degrees) :param property: From the last element of the property tree path. Default 'name' for component name string. :return: Full property path OR component name if no property specified. """ diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_AreaLightScreenshotTest.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_AreaLightScreenshotTest.py index 03f842f9b4..a56c72e46c 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_AreaLightScreenshotTest.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_AreaLightScreenshotTest.py @@ -78,7 +78,7 @@ def AtomGPU_LightComponent_AreaLightScreenshotsMatchGoldenImages(): from editor_python_test_tools.editor_entity_utils import EditorEntity from editor_python_test_tools.utils import Report, Tracer, TestHelper - from Atom.atom_utils.atom_constants import AtomComponentProperties, LIGHT_TYPES + from Atom.atom_utils.atom_constants import AtomComponentProperties, ATTENUATION_RADIUS_MODE, LIGHT_TYPES from Atom.atom_utils.atom_component_helper import ( initial_viewport_setup, create_basic_atom_rendering_scene, enter_exit_game_mode_take_screenshot) @@ -138,10 +138,12 @@ def AtomGPU_LightComponent_AreaLightScreenshotsMatchGoldenImages(): light_component.get_component_property_value(AtomComponentProperties.light('Intensity')) == 0.0) # 7. Set the Attenuation Radius Mode property of the Light component to 1 (automatic). - light_component.set_component_property_value(AtomComponentProperties.light('Attenuation Radius Mode'), 1) + light_component.set_component_property_value( + AtomComponentProperties.light('Attenuation Radius Mode'), ATTENUATION_RADIUS_MODE['automatic']) Report.result( Tests.light_component_attenuation_radius_property_set, - light_component.get_component_property_value(AtomComponentProperties.light('Attenuation Radius Mode')) == 1) + light_component.get_component_property_value( + AtomComponentProperties.light('Attenuation Radius Mode')) == ATTENUATION_RADIUS_MODE['automatic']) # 8. Enter game mode and take a screenshot then exit game mode. enter_exit_game_mode_take_screenshot("AreaLight_2.ppm", Tests.enter_game_mode, Tests.exit_game_mode) From 523691497d505a586519700fe495caa85f528631 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Mon, 6 Dec 2021 16:43:07 -0800 Subject: [PATCH 120/128] call AtomComponentProperties.light(), AtomComponentProperties.directional_light(), etc. as is for its component name, rather than make a component name variable Signed-off-by: jromnoa <80134229+jromnoa@users.noreply.github.com> --- .../hydra_AtomGPU_SpotLightScreenshotTest.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py index 0c099dc04d..fbfb6e3468 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_SpotLightScreenshotTest.py @@ -123,22 +123,22 @@ def AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages(): # Test steps begin. # 1. Find the Directional Light entity then disable its Directional Light component. - directional_light_name = AtomComponentProperties.directional_light() - directional_light_entity = EditorEntity.find_editor_entity(directional_light_name) - directional_light_component = directional_light_entity.get_components_of_type([directional_light_name])[0] + directional_light_entity = EditorEntity.find_editor_entity(AtomComponentProperties.directional_light()) + directional_light_component = directional_light_entity.get_components_of_type( + [AtomComponentProperties.directional_light()])[0] directional_light_component.disable_component() Report.critical_result(Tests.directional_light_component_disabled, not directional_light_component.is_enabled()) # 2. Disable Global Skylight (IBL) component on the Global Skylight (IBL) entity. - global_skylight_name = AtomComponentProperties.global_skylight() - global_skylight_entity = EditorEntity.find_editor_entity(global_skylight_name) - global_skylight_component = global_skylight_entity.get_components_of_type([global_skylight_name])[0] + global_skylight_entity = EditorEntity.find_editor_entity(AtomComponentProperties.global_skylight()) + global_skylight_component = global_skylight_entity.get_components_of_type( + [AtomComponentProperties.global_skylight()])[0] global_skylight_component.disable_component() Report.critical_result(Tests.global_skylight_component_disabled, not global_skylight_component.is_enabled()) # 3. Disable HDRi Skybox component on the Global Skylight (IBL) entity. - hdri_skybox_name = AtomComponentProperties.hdri_skybox() - hdri_skybox_component = global_skylight_entity.get_components_of_type([hdri_skybox_name])[0] + hdri_skybox_component = global_skylight_entity.get_components_of_type( + [AtomComponentProperties.hdri_skybox()])[0] hdri_skybox_component.disable_component() Report.critical_result(Tests.hdri_skybox_component_disabled, not hdri_skybox_component.is_enabled()) @@ -151,8 +151,7 @@ def AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages(): Report.critical_result(Tests.spot_light_entity_created, spot_light_entity.exists()) # 5. Attach a Light component to the Spot Light entity. - light_name = AtomComponentProperties.light() - light_component = spot_light_entity.add_component(light_name) + light_component = spot_light_entity.add_component(AtomComponentProperties.light()) Report.critical_result(Tests.light_component_added, light_component.is_enabled()) # 6. Set the Light component Light Type to Spot (disk). From 1cef580cadf503ea83bf67110f9bc4390f58976b Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Mon, 6 Dec 2021 17:12:06 -0600 Subject: [PATCH 121/128] Material editor asynchronously loads lighting and model presets changed several sequential blocking loads into asynchronous loads to improve material editor startup time Signed-off-by: Guthrie Adams --- .../Viewport/MaterialViewportComponent.cpp | 122 ++++++++---------- .../Viewport/MaterialViewportComponent.h | 12 ++ 2 files changed, 63 insertions(+), 71 deletions(-) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp index c8df123d0d..35f5067cd0 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -135,11 +134,19 @@ namespace MaterialEditor { AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); MaterialViewportRequestBus::Handler::BusDisconnect(); + ClearContent(); + } + void MaterialViewportComponent::ClearContent() + { + AZ::Data::AssetBus::MultiHandler::BusDisconnect(); + + m_lightingPresetAssets.clear(); m_lightingPresetVector.clear(); m_lightingPresetLastSavePathMap.clear(); m_lightingPresetSelection.reset(); + m_modelPresetAssets.clear(); m_modelPresetVector.clear(); m_modelPresetLastSavePathMap.clear(); m_modelPresetSelection.reset(); @@ -151,84 +158,36 @@ namespace MaterialEditor MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnBeginReloadContent); - const AZStd::string selectedLightingPresetNameOld = m_viewportSettings->m_selectedLightingPresetName; - - m_lightingPresetVector.clear(); - m_lightingPresetLastSavePathMap.clear(); - m_lightingPresetSelection.reset(); - - const AZStd::string selectedModelPresetNameOld = m_viewportSettings->m_selectedModelPresetName; - - m_modelPresetVector.clear(); - m_modelPresetLastSavePathMap.clear(); - m_modelPresetSelection.reset(); - - AZStd::vector lightingAssetInfoVector; - AZStd::vector modelAssetInfoVector; + ClearContent(); // Enumerate and load all the relevant preset files in the project. // (The files are stored in a temporary list instead of processed in the callback because deep operations inside // AssetCatalogRequestBus::EnumerateAssets can lead to deadlocked) - AZ::Data::AssetCatalogRequests::AssetEnumerationCB enumerateCB = [&lightingAssetInfoVector, &modelAssetInfoVector]([[maybe_unused]] const AZ::Data::AssetId id, const AZ::Data::AssetInfo& info) + AZ::Data::AssetCatalogRequests::AssetEnumerationCB enumerateCB = [this]([[maybe_unused]] const AZ::Data::AssetId id, const AZ::Data::AssetInfo& info) { if (AzFramework::StringFunc::EndsWith(info.m_relativePath.c_str(), ".lightingpreset.azasset")) { - lightingAssetInfoVector.push_back(info); + m_lightingPresetAssets[info.m_assetId] = { info.m_assetId, info.m_assetType }; + AZ::Data::AssetBus::MultiHandler::BusConnect(info.m_assetId); } else if (AzFramework::StringFunc::EndsWith(info.m_relativePath.c_str(), ".modelpreset.azasset")) { - modelAssetInfoVector.push_back(info); + m_modelPresetAssets[info.m_assetId] = { info.m_assetId, info.m_assetType }; + AZ::Data::AssetBus::MultiHandler::BusConnect(info.m_assetId); } }; AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::EnumerateAssets, nullptr, enumerateCB, nullptr); - for (const auto& info : lightingAssetInfoVector) + for (auto& assetPair : m_lightingPresetAssets) { - if (info.m_assetId.IsValid()) - { - AZ::Data::Asset asset = AZ::RPI::AssetUtils::LoadAssetById( - info.m_assetId, AZ::RPI::AssetUtils::TraceLevel::Warning); - if (asset) - { - const AZ::Render::LightingPreset* preset = asset->GetDataAs(); - if (preset) - { - auto presetPtr = AddLightingPreset(*preset); - m_lightingPresetLastSavePathMap[presetPtr] = AZ::RPI::AssetUtils::GetSourcePathByAssetId(info.m_assetId); - AZ_TracePrintf("Material Editor", "Loaded viewport configuration: %s.\n", info.m_relativePath.c_str()); - } - } - } + assetPair.second.QueueLoad(); } - for (const auto& info : modelAssetInfoVector) + for (auto& assetPair : m_modelPresetAssets) { - if (info.m_assetId.IsValid()) - { - AZ::Data::Asset asset = - AZ::RPI::AssetUtils::LoadAssetById(info.m_assetId, AZ::RPI::AssetUtils::TraceLevel::Warning); - if (asset) - { - const AZ::Render::ModelPreset* preset = asset->GetDataAs(); - if (preset) - { - auto presetPtr = AddModelPreset(*preset); - m_modelPresetLastSavePathMap[presetPtr] = AZ::RPI::AssetUtils::GetSourcePathByAssetId(info.m_assetId); - AZ_TracePrintf("Material Editor", "Loaded viewport configuration: %s.\n", info.m_relativePath.c_str()); - } - } - } + assetPair.second.QueueLoad(); } - - // If there was a prior selection, this will keep the same configuration selected. - // Otherwise, these strings are empty and the operation will be ignored. - SelectLightingPresetByName(selectedLightingPresetNameOld); - SelectModelPresetByName(selectedModelPresetNameOld); - - MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnEndReloadContent); - - AZ_TracePrintf("Material Editor", "Finished loading viewport configurations.\n"); } AZ::Render::LightingPresetPtr MaterialViewportComponent::AddLightingPreset(const AZ::Render::LightingPreset& preset) @@ -237,12 +196,6 @@ namespace MaterialEditor auto presetPtr = m_lightingPresetVector.back(); MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnLightingPresetAdded, presetPtr); - - if (m_lightingPresetVector.size() == 1) - { - SelectLightingPreset(presetPtr); - } - return presetPtr; } @@ -314,12 +267,6 @@ namespace MaterialEditor auto presetPtr = m_modelPresetVector.back(); MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnModelPresetAdded, presetPtr); - - if (m_modelPresetVector.size() == 1) - { - SelectModelPreset(presetPtr); - } - return presetPtr; } @@ -443,6 +390,39 @@ namespace MaterialEditor return m_viewportSettings->m_displayMapperOperationType; } + inline void MaterialViewportComponent::OnAssetReady(AZ::Data::Asset asset) + { + if (AZ::Data::Asset anyAsset = asset) + { + if (const auto lightingPreset = anyAsset->GetDataAs()) + { + auto presetPtr = AddLightingPreset(*lightingPreset); + const auto& presetPath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(anyAsset.GetId()); + m_lightingPresetAssets[anyAsset.GetId()] = anyAsset; + m_lightingPresetLastSavePathMap[presetPtr] = presetPath; + AZ_TracePrintf("Material Editor", "Loaded Preset: %s\n", presetPath.c_str()); + } + + if (const auto modelPreset = anyAsset->GetDataAs()) + { + auto presetPtr = AddModelPreset(*modelPreset); + const auto& presetPath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(anyAsset.GetId()); + m_modelPresetAssets[anyAsset.GetId()] = anyAsset; + m_modelPresetLastSavePathMap[presetPtr] = presetPath; + AZ_TracePrintf("Material Editor", "Loaded Preset: %s\n", presetPath.c_str()); + } + } + + AZ::Data::AssetBus::MultiHandler::BusDisconnect(asset.GetId()); + if (!AZ::Data::AssetBus::MultiHandler::BusIsConnected()) + { + SelectLightingPresetByName(m_viewportSettings->m_selectedLightingPresetName); + SelectModelPresetByName(m_viewportSettings->m_selectedModelPresetName); + MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnEndReloadContent); + AZ_TracePrintf("Material Editor", "Finished loading viewport configurations.\n"); + } + } + void MaterialViewportComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile) { AZ::TickBus::QueueFunction([this]() { diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.h index a4f94c3546..07385d842d 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportComponent.h @@ -11,8 +11,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -22,6 +24,7 @@ namespace MaterialEditor class MaterialViewportComponent : public AZ::Component , private MaterialViewportRequestBus::Handler + , private AZ::Data::AssetBus::MultiHandler , private AzFramework::AssetCatalogEventBus::Handler { public: @@ -46,6 +49,8 @@ namespace MaterialEditor void Deactivate() override; //////////////////////////////////////////////////////////////////////// + void ClearContent(); + //////////////////////////////////////////////////////////////////////// // MaterialViewportRequestBus::Handler overrides ... void ReloadContent() override; @@ -82,14 +87,21 @@ namespace MaterialEditor AZ::Render::DisplayMapperOperationType GetDisplayMapperOperationType() const override; //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// + // AZ::Data::AssetBus::MultiHandler overrides ... + void OnAssetReady(AZ::Data::Asset asset) override; + //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// // AzFramework::AssetCatalogEventBus::Handler overrides ... void OnCatalogLoaded(const char* catalogFile) override; //////////////////////////////////////////////////////////////////////// + AZStd::unordered_map> m_lightingPresetAssets; AZ::Render::LightingPresetPtrVector m_lightingPresetVector; AZ::Render::LightingPresetPtr m_lightingPresetSelection; + AZStd::unordered_map> m_modelPresetAssets; AZ::Render::ModelPresetPtrVector m_modelPresetVector; AZ::Render::ModelPresetPtr m_modelPresetSelection; From 27d5f662f9ede679a82da032a331e558df6f4e4b Mon Sep 17 00:00:00 2001 From: Jonathan Capes Date: Tue, 7 Dec 2021 01:15:45 -0800 Subject: [PATCH 122/128] Update default project to include PrefabBuilder (#5619) Signed-off-by: Jonathan Capes --- Templates/DefaultProject/Template/Code/enabled_gems.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/Templates/DefaultProject/Template/Code/enabled_gems.cmake b/Templates/DefaultProject/Template/Code/enabled_gems.cmake index 833fe57660..e0902a5989 100644 --- a/Templates/DefaultProject/Template/Code/enabled_gems.cmake +++ b/Templates/DefaultProject/Template/Code/enabled_gems.cmake @@ -22,6 +22,7 @@ set(ENABLED_GEMS Multiplayer PhysX PrimitiveAssets + PrefabBuilder SaveData ScriptCanvasPhysics ScriptEvents From 201777c1d18e28b2ec27a3b812aa0a03b57db47f Mon Sep 17 00:00:00 2001 From: Nicholas Lawson <70027408+lawsonamzn@users.noreply.github.com> Date: Tue, 7 Dec 2021 08:42:52 -0800 Subject: [PATCH 123/128] ASTC (Ios texture compressor) for mac was built in debug. (#6182) * Updates the mac version of ASTC Encoder to actually use release build Signed-off-by: lawsonamzn <70027408+lawsonamzn@users.noreply.github.com> --- cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index a7dcf115eb..994f42e983 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -40,7 +40,7 @@ ly_associate_package(PACKAGE_NAME libpng-1.6.37-mac ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-mac TARGETS libsamplerate PACKAGE_HASH b912af40c0ac197af9c43d85004395ba92a6a859a24b7eacd920fed5854a97fe) ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev5-mac TARGETS ZLIB PACKAGE_HASH b6fea9c79b8bf106d4703b67fecaa133f832ad28696c2ceef45fb5f20013c096) ly_associate_package(PACKAGE_NAME squish-ccr-deb557d-rev1-mac TARGETS squish-ccr PACKAGE_HASH 155bfbfa17c19a9cd2ef025de14c5db598f4290045d5b0d83ab58cb345089a77) -ly_associate_package(PACKAGE_NAME astc-encoder-3.2-rev2-mac TARGETS astc-encoder PACKAGE_HASH 06f129d26995845824f1fb906a5135b2c71d44d66c768342af85fa28a175906f) +ly_associate_package(PACKAGE_NAME astc-encoder-3.2-rev5-mac TARGETS astc-encoder PACKAGE_HASH bdb1146cc6bbacc07901564fe884529d7cacc9bb44895597327341d3b9833ab0) ly_associate_package(PACKAGE_NAME ISPCTexComp-36b80aa-rev1-mac TARGETS ISPCTexComp PACKAGE_HASH 8a4e93277b8face6ea2fd57c6d017bdb55643ed3d6387110bc5f6b3b884dd169) ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev4-mac TARGETS lz4 PACKAGE_HASH 891ff630bf34f7ab1d8eaee2ea0a8f1fca89dbdc63fca41ee592703dd488a73b) ly_associate_package(PACKAGE_NAME azslc-1.7.34-rev1-mac TARGETS azslc PACKAGE_HASH a9d81946b42ffa55c0d14d6a9249b3340e59a8fb8835e7a96c31df80f14723bc) From aad16acf1f126f061ccf51fd40692225c015037d Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Tue, 7 Dec 2021 10:44:12 -0600 Subject: [PATCH 124/128] Jobify the draw item list sort in View::FinalizeDrawLists (#6176) Jobification of the sort saves 0.7ms/frame on the HighInstanceTest on my pc. Make MeshFeatureProcessor update of the mesh cull bounds part of the job work rather than part of the simulate work. This saves 0.1ms/frame on the HighInstanceTest Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- .../Code/Source/AuxGeom/AuxGeomDrawQueue.cpp | 4 -- .../Code/Source/Mesh/MeshFeatureProcessor.cpp | 29 ++++++------ .../RHI/Code/Source/RHI/DrawListContext.cpp | 2 + .../RHI/Code/Source/RHI/FrameScheduler.cpp | 8 +++- .../Code/Source/RHI/FrameGraphCompiler.cpp | 3 +- Gems/Atom/RHI/DX12/Code/Source/RHI/Scope.cpp | 4 +- .../Atom/RPI.Public/FeatureProcessor.h | 5 ++- .../RPI/Code/Source/RPI.Public/Culling.cpp | 44 ++++++++++++++----- .../RPI/Code/Source/RPI.Public/Pass/Pass.cpp | 6 ++- .../Source/RPI.Public/Pass/PassSystem.cpp | 1 - .../Source/RPI.Public/Pass/RasterPass.cpp | 1 + .../Atom/RPI/Code/Source/RPI.Public/Scene.cpp | 20 ++++----- Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp | 15 ++++++- 13 files changed, 92 insertions(+), 50 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp index 5cc43e9013..f17e15dafa 100644 --- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp @@ -671,8 +671,6 @@ namespace AZ AZ::u8 width, int32_t viewProjOverrideIndex) { - AZ_PROFILE_SCOPE(AzRender, "AuxGeomDrawQueue: DrawPrimitiveWithSharedVerticesCommon"); - // grab a mutex lock for the rest of this function so that a commit cannot happen during it and // other threads can't add geometry during it AZStd::lock_guard lock(m_buffersWriteLock); @@ -743,8 +741,6 @@ namespace AZ AZ::u8 width, int32_t viewProjOverrideIndex) { - AZ_PROFILE_SCOPE(AzRender, "AuxGeomDrawQueue: DrawPrimitiveWithSharedVerticesCommon"); - AZ_Assert(indexCount >= verticesPerPrimitiveType && (indexCount % verticesPerPrimitiveType == 0), "Index count must be at least %d and must be a multiple of %d", verticesPerPrimitiveType, verticesPerPrimitiveType); diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index 112eff64a8..262e003cdb 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -77,8 +77,8 @@ namespace AZ void MeshFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket& packet) { AZ_PROFILE_SCOPE(RPI, "MeshFeatureProcessor: Simulate"); - AZ_UNUSED(packet); + AZ::Job* parentJob = packet.m_parentJob; AZStd::concurrency_check_scope scopeCheck(m_meshDataChecker); const auto iteratorRanges = m_modelData.GetParallelRanges(); @@ -87,6 +87,8 @@ namespace AZ { const auto jobLambda = [&]() -> void { + AZ_PROFILE_SCOPE(AzRender, "MeshFeatureProcessor: Simulate: Job"); + for (auto meshDataIter = iteratorRange.first; meshDataIter != iteratorRange.second; ++meshDataIter) { if (!meshDataIter->m_model) @@ -114,24 +116,22 @@ namespace AZ { meshDataIter->BuildCullable(); } + + if (meshDataIter->m_cullBoundsNeedsUpdate) + { + meshDataIter->UpdateCullBounds(m_transformService); + } } }; Job* executeGroupJob = aznew JobFunction(jobLambda, true, nullptr); // Auto-deletes - executeGroupJob->SetDependent(&jobCompletion); - executeGroupJob->Start(); + parentJob->StartAsChild(executeGroupJob); + } + { + AZ_PROFILE_SCOPE(AzRender, "MeshFeatureProcessor: Simulate: WaitForChildren"); + parentJob->WaitForChildren(); } - jobCompletion.StartAndWaitForCompletion(); m_forceRebuildDrawPackets = false; - - // CullingSystem::RegisterOrUpdateCullable() is not threadsafe, so need to do those updates in a single thread - for (ModelDataInstance& modelDataInstance : m_modelData) - { - if (modelDataInstance.m_model && modelDataInstance.m_cullBoundsNeedsUpdate) - { - modelDataInstance.UpdateCullBounds(m_transformService); - } - } } void MeshFeatureProcessor::OnBeginPrepareRender() @@ -1038,7 +1038,6 @@ namespace AZ void ModelDataInstance::UpdateDrawPackets(bool forceUpdate /*= false*/) { - AZ_PROFILE_SCOPE(AzRender, "ModelDataInstance:: UpdateDrawPackets"); for (auto& drawPacketList : m_drawPacketListsByLod) { for (auto& drawPacket : drawPacketList) @@ -1053,7 +1052,6 @@ namespace AZ void ModelDataInstance::BuildCullable() { - AZ_PROFILE_SCOPE(AzRender, "ModelDataInstance: BuildCullable"); AZ_Assert(m_cullableNeedsRebuild, "This function only needs to be called if the cullable to be rebuilt"); AZ_Assert(m_model, "The model has not finished loading yet"); @@ -1130,7 +1128,6 @@ namespace AZ void ModelDataInstance::UpdateCullBounds(const TransformServiceFeatureProcessor* transformService) { - AZ_PROFILE_SCOPE(AzRender, "ModelDataInstance: UpdateCullBounds"); AZ_Assert(m_cullBoundsNeedsUpdate, "This function only needs to be called if the culling bounds need to be rebuilt"); AZ_Assert(m_model, "The model has not finished loading yet"); diff --git a/Gems/Atom/RHI/Code/Source/RHI/DrawListContext.cpp b/Gems/Atom/RHI/Code/Source/RHI/DrawListContext.cpp index 5f92d52006..e7254937e4 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/DrawListContext.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/DrawListContext.cpp @@ -7,6 +7,7 @@ */ #include +#include #include namespace AZ @@ -86,6 +87,7 @@ namespace AZ void DrawListContext::FinalizeLists() { + AZ_PROFILE_SCOPE(RHI, "DrawListContext: FinalizeLists"); for (size_t i = 0; i < m_mergedListsByTag.size(); ++i) { if (m_drawListMask[i]) diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp index eb4fb46cc9..bb7ae4ca27 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp @@ -233,9 +233,10 @@ namespace AZ for (ScopeProducer* scopeProducer : m_scopeProducers) { + AZ_PROFILE_SCOPE(RHI, "FrameScheduler: PrepareProducers: Scope %s", scopeProducer->GetScopeId().GetCStr()); m_frameGraph->BeginScope(*scopeProducer->GetScope()); scopeProducer->SetupFrameGraphDependencies(*m_frameGraph); - + // All scopes depend on the root scope. if (scopeProducer->GetScopeId() != m_rootScopeId) { @@ -527,7 +528,10 @@ namespace AZ parentJob->StartAsChild(AZ::CreateJobFunction(AZStd::move(jobLambda), true, nullptr)); } - parentJob->WaitForChildren(); + { + AZ_PROFILE_SCOPE(RHI, "FrameScheduler: ExecuteGroupInternal: WaitForChildren"); + parentJob->WaitForChildren(); + } } m_frameGraphExecuter->EndGroup(groupIndex); diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp index 4ff7d581a4..a732b888ca 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp @@ -479,8 +479,7 @@ namespace AZ return; } - D3D12_RESOURCE_TRANSITION_BARRIER transition; - memset(&transition, 0, sizeof(D3D12_RESOURCE_TRANSITION_BARRIER)); // C4701 potentially unitialized local variable 'transition' used + D3D12_RESOURCE_TRANSITION_BARRIER transition = {0}; transition.pResource = image.GetMemoryView().GetMemory(); Scope& firstScope = static_cast(scopeAttachment->GetScope()); diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/Scope.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/Scope.cpp index b29018a2ac..e27a756054 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/Scope.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/Scope.cpp @@ -94,13 +94,13 @@ namespace AZ const bool Scope::IsStateSupportedByQueue(D3D12_RESOURCE_STATES state) const { - const D3D12_RESOURCE_STATES VALID_COMPUTE_QUEUE_RESOURCE_STATES = + constexpr D3D12_RESOURCE_STATES VALID_COMPUTE_QUEUE_RESOURCE_STATES = (D3D12_RESOURCE_STATE_UNORDERED_ACCESS | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_COPY_DEST | D3D12_RESOURCE_STATE_COPY_SOURCE); - const D3D12_RESOURCE_STATES VALID_GRAPHICS_QUEUE_RESOURCE_STATES = + constexpr D3D12_RESOURCE_STATES VALID_GRAPHICS_QUEUE_RESOURCE_STATES = (D3D12_RESOURCE_STATES)DX12_RESOURCE_STATE_VALID_API_MASK; switch (GetHardwareQueueClass()) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/FeatureProcessor.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/FeatureProcessor.h index ca188a6d42..caf3728c89 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/FeatureProcessor.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/FeatureProcessor.h @@ -22,10 +22,12 @@ #include #include #include -#include namespace AZ { + // forward declares + class Job; + namespace RPI { //! @class FeatureProcessor @@ -51,6 +53,7 @@ namespace AZ struct SimulatePacket { + AZ::Job* m_parentJob = nullptr; }; struct RenderPacket diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index 9dd4cf99b1..56401e7ce6 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -35,7 +35,7 @@ //Enables more detailed profiling descriptions within the culling system, but adds some performance overhead. //Enable this to more easily see which jobs are associated with which view. -//#define AZ_CULL_PROFILE_VERBOSE +//#define AZ_CULL_PROFILE_VERBOSE namespace AZ { @@ -44,6 +44,7 @@ namespace AZ AZ_CVAR(bool, r_CullInParallel, true, nullptr, ConsoleFunctorFlags::Null, ""); AZ_CVAR(uint32_t, r_CullWorkPerBatch, 500, nullptr, ConsoleFunctorFlags::Null, ""); +#ifdef AZ_CULL_DEBUG_ENABLED void DebugDrawWorldCoordinateAxes(AuxGeomDraw* auxGeom) { auxGeom->DrawCylinder(Vector3(.5, .0, .0), Vector3(1, 0, 0), 0.02f, 1.0f, Colors::Red, AuxGeomDraw::DrawStyle::Solid, AuxGeomDraw::DepthTest::Off); @@ -199,6 +200,7 @@ namespace AZ AZ_Assert(false, "invalid frustum, cannot draw"); } } +#endif //AZ_CULL_DEBUG_ENABLED CullingDebugContext::~CullingDebugContext() { @@ -283,7 +285,7 @@ namespace AZ const Scene& scene, View& view, Frustum& frustum, - [[maybe_unused]]void* maskedOcclusionCulling) + [[maybe_unused]] void* maskedOcclusionCulling) { AZStd::shared_ptr worklistData = AZStd::make_shared(); worklistData->m_debugCtx = &debugCtx; @@ -319,14 +321,16 @@ namespace AZ for (const AzFramework::IVisibilityScene::NodeData& nodeData : worklist) { //If a node is entirely contained within the frustum, then we can skip the fine grained culling. - bool nodeIsContainedInFrustum = ShapeIntersection::Contains(worklistData->m_frustum, nodeData.m_bounds); + bool nodeIsContainedInFrustum = + !worklistData->m_debugCtx->m_enableFrustumCulling || + ShapeIntersection::Contains(worklistData->m_frustum, nodeData.m_bounds); #ifdef AZ_CULL_PROFILE_VERBOSE - AZ_PROFILE_SCOPE(RPI, "process node (view: %s, skip fine cull: %d", - m_view->GetName().GetCStr(), nodeIsContainedInFrustum ? 1 : 0); + AZ_PROFILE_SCOPE(RPI, "process node (view: %s, skip fine cull: %ds", + worklistData->m_view->GetName().GetCStr(), nodeIsContainedInFrustum ? "true" : "false"); #endif - if (nodeIsContainedInFrustum || !worklistData->m_debugCtx->m_enableFrustumCulling) + if (nodeIsContainedInFrustum) { //Add all objects within this node to the view, without any extra culling for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries) @@ -392,7 +396,7 @@ namespace AZ } } } - +#ifdef AZ_CULL_DEBUG_ENABLED if (worklistData->m_debugCtx->m_debugDraw && (worklistData->m_view->GetName() == worklistData->m_debugCtx->m_currentViewSelectionName)) { AZ_PROFILE_SCOPE(RPI, "debug draw culling"); @@ -444,8 +448,10 @@ namespace AZ } } } +#endif } +#ifdef AZ_CULL_DEBUG_ENABLED if (worklistData->m_debugCtx->m_enableStats) { CullingDebugContext::CullStats& cullStats = worklistData->m_debugCtx->GetCullStatsForView(worklistData->m_view); @@ -455,6 +461,7 @@ namespace AZ cullStats.m_numVisibleCullables += numVisibleCullables; ++cullStats.m_numJobs; } +#endif //AZ_CULL_DEBUG_ENABLED } #if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED @@ -467,6 +474,10 @@ namespace AZ return MaskedOcclusionCulling::CullingResult::VISIBLE; } +#ifdef AZ_CULL_PROFILE_VERBOSE + AZ_PROFILE_SCOPE(RPI, "TestOcclusionCulling"); +#endif + if (visibleEntry->m_boundingVolume.Contains(worklistData->m_view->GetCameraTransform().GetTranslation())) { // camera is inside bounding volume @@ -516,10 +527,15 @@ namespace AZ } #endif - void CullingScene::ProcessCullablesCommon(const Scene& scene, View& view, AZ::Frustum& frustum, [[maybe_unused]]void*& maskedOcclusionCulling) + void CullingScene::ProcessCullablesCommon( + const Scene& scene [[maybe_unused]], + View& view, + AZ::Frustum& frustum [[maybe_unused]], + void*& maskedOcclusionCulling [[maybe_unused]]) { AZ_PROFILE_SCOPE(RPI, "CullingScene::ProcessCullablesCommon() - %s", view.GetName().GetCStr()); +#ifdef AZ_CULL_DEBUG_ENABLED if (m_debugCtx.m_freezeFrustums) { AZStd::lock_guard lock(m_debugCtx.m_frozenFrustumsMutex); @@ -544,7 +560,7 @@ namespace AZ CullingDebugContext::CullStats& cullStats = m_debugCtx.GetCullStatsForView(&view); cullStats.m_cameraViewToWorld = view.GetViewToWorldMatrix(); } - +#endif //AZ_CULL_DEBUG_ENABLED #if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED // setup occlusion culling, if necessary maskedOcclusionCulling = m_occlusionPlanes.empty() ? nullptr : view.GetMaskedOcclusionCulling(); @@ -806,6 +822,7 @@ namespace AZ beginCullingDescriptor, [&view]() { + AZ_PROFILE_SCOPE(RPI, "CullingScene: BeginCullingTaskGraph"); view->BeginCulling(); }); } @@ -823,6 +840,7 @@ namespace AZ { const auto cullingLambda = [&view]() { + AZ_PROFILE_SCOPE(RPI, "CullingScene: BeginCullingJob"); view->BeginCulling(); }; @@ -844,7 +862,11 @@ namespace AZ m_taskGraphActive = AZ::Interface::Get(); - if (m_taskGraphActive && m_taskGraphActive->IsTaskGraphActive()) + if(views.size() == 1) // avoid job overhead when only 1 job + { + views[0]->BeginCulling(); + } + else if (m_taskGraphActive && m_taskGraphActive->IsTaskGraphActive()) { BeginCullingTaskGraph(views); } @@ -853,6 +875,7 @@ namespace AZ BeginCullingJobs(views); } +#if AZ_CULL_DEBUG_ENABLED AuxGeomDrawPtr auxGeom; if (m_debugCtx.m_debugDraw) { @@ -885,6 +908,7 @@ namespace AZ m_debugCtx.m_frozenFrustums.clear(); } } +#endif } void CullingScene::EndCulling() diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index 4a135ab6d6..9155c0351a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -1288,6 +1288,7 @@ namespace AZ void Pass::FrameBegin(FramePrepareParams params) { + AZ_PROFILE_SCOPE(RPI, "Pass::FrameBegin() - %s", m_path.GetCStr()); AZ_RPI_BREAK_ON_TARGET_PASS; if (!IsEnabled()) @@ -1310,7 +1311,10 @@ namespace AZ // FrameBeginInternal needs to be the last function be called in FrameBegin because its implementation expects // all the attachments are imported to database (for example, ImageAttachmentPreview) - FrameBeginInternal(params); + { + AZ_PROFILE_SCOPE(RPI, "Pass::FrameBeginInternal()"); + FrameBeginInternal(params); + } // readback attachment with output state UpdateReadbackAttachment(params, false); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp index 39d0e879e1..1144f20f3b 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -312,7 +312,6 @@ namespace AZ Pass::FramePrepareParams params{ &frameGraphBuilder }; { - AZ_PROFILE_SCOPE(RPI, "Pass: FrameBegin"); m_rootPass->FrameBegin(params); } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RasterPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RasterPass.cpp index 5001951377..fa2ee4be94 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RasterPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RasterPass.cpp @@ -146,6 +146,7 @@ namespace AZ void RasterPass::UpdateDrawList() { + AZ_PROFILE_SCOPE(RPI, "RasterPass::UpdateDrawList"); // DrawLists from dynamic draw AZStd::vector drawLists = DynamicDrawInterface::Get()->GetDrawListsForPass(this); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index 3e501c3d93..dafd990c21 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -400,10 +400,11 @@ namespace AZ for (FeatureProcessorPtr& fp : m_featureProcessors) { FeatureProcessor* featureProcessor = fp.get(); - const auto jobLambda = [this, featureProcessor]() + const auto jobLambda = [this, featureProcessor](AZ::Job& owner) { - - featureProcessor->Simulate(m_simulatePacket); + FeatureProcessor::SimulatePacket jobPacket = m_simulatePacket; + jobPacket.m_parentJob = &owner; + featureProcessor->Simulate(jobPacket); }; AZ::Job* simulationJob = AZ::CreateJobFunction(AZStd::move(jobLambda), true, nullptr); //auto-deletes @@ -516,7 +517,7 @@ namespace AZ collectDrawPacketsTG.Submit(&collectDrawPacketsTGEvent); // Launch CullingSystem::ProcessCullables() jobs (will run concurrently with FeatureProcessor::Render() jobs if m_parallelOctreeTraversal) - bool parallelOctreeTraversal = m_cullingScene->GetDebugContext().m_parallelOctreeTraversal; + const bool parallelOctreeTraversal = m_cullingScene->GetDebugContext().m_parallelOctreeTraversal; m_cullingScene->BeginCulling(m_renderPacket.m_views); static const AZ::TaskDescriptor processCullablesDescriptor{"AZ::RPI::Scene::ProcessCullables", "Graphics"}; AZ::TaskGraphEvent processCullablesTGEvent; @@ -576,6 +577,7 @@ namespace AZ } // Launch CullingSystem::ProcessCullables() jobs (will run concurrently with FeatureProcessor::Render() jobs) + const bool parallelOctreeTraversal = m_cullingScene->GetDebugContext().m_parallelOctreeTraversal; m_cullingScene->BeginCulling(m_renderPacket.m_views); for (ViewPtr& viewPtr : m_renderPacket.m_views) { @@ -584,7 +586,7 @@ namespace AZ m_cullingScene->ProcessCullablesJobs(*this, *viewPtr, thisJob); // can't call directly because ProcessCullables needs a parent job }, true, nullptr); //auto-deletes - if (m_cullingScene->GetDebugContext().m_parallelOctreeTraversal) + if (parallelOctreeTraversal) { processCullablesJob->SetDependent(collectDrawPacketsCompletion); processCullablesJob->Start(); @@ -731,20 +733,19 @@ namespace AZ // Add dynamic draw data for all the views if (m_dynamicDrawSystem) { - AZ_PROFILE_SCOPE(RPI, "DynamicDraw SubmitDrawData"); m_dynamicDrawSystem->SubmitDrawData(this, m_renderPacket.m_views); } } { - AZ_PROFILE_BEGIN(RPI, "FinalizeDrawLists"); - if (jobPolicy == RHI::JobPolicy::Serial) + AZ_PROFILE_SCOPE(RPI, "FinalizeDrawLists"); + if (jobPolicy == RHI::JobPolicy::Serial || + m_renderPacket.m_views.size() <= 1) // FinalizeDrawListsX both immediately wait for the job to complete, skip job if only 1 job would be generated { for (auto& view : m_renderPacket.m_views) { view->FinalizeDrawLists(); } - AZ_PROFILE_END(RPI); } else { @@ -756,7 +757,6 @@ namespace AZ { FinalizeDrawListsJobs(); } - AZ_PROFILE_END(RPI); } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp index a5c67b6210..e1d564c8ac 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED @@ -260,15 +262,25 @@ namespace AZ void View::SortFinalizedDrawLists() { + AZ_PROFILE_SCOPE(RPI, "View: SortFinalizedDrawLists"); RHI::DrawListsByTag& drawListsByTag = m_drawListContext.GetMergedDrawListsByTag(); + AZ::JobCompletion jobCompletion; for (size_t idx = 0; idx < drawListsByTag.size(); ++idx) { if (drawListsByTag[idx].size() > 1) { - SortDrawList(drawListsByTag[idx], RHI::DrawListTag(idx)); + auto jobLambda = [this, &drawListsByTag, idx]() + { + AZ_PROFILE_SCOPE(RPI, "View: SortDrawList Job"); + SortDrawList(drawListsByTag[idx], RHI::DrawListTag(idx)); + }; + Job* jobSortDrawList = aznew JobFunction(jobLambda, true, nullptr); // Auto-deletes + jobSortDrawList->SetDependent(&jobCompletion); + jobSortDrawList->Start(); } } + jobCompletion.StartAndWaitForCompletion(); } void View::SortDrawList(RHI::DrawList& drawList, RHI::DrawListTag tag) @@ -433,6 +445,7 @@ namespace AZ void View::BeginCulling() { #if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED + AZ_PROFILE_SCOPE(RPI, "View: ClearMaskedOcclusionBuffer"); m_maskedOcclusionCulling->ClearBuffer(); #endif } From 72b55392593e3be865361edead6cdffeab02fc4d Mon Sep 17 00:00:00 2001 From: amzn-phist <52085794+amzn-phist@users.noreply.github.com> Date: Tue, 7 Dec 2021 12:28:17 -0600 Subject: [PATCH 125/128] Add verbosity option to some o3de.py sub-commands (#6079) * Add verbosity option to some o3de.py sub-commands - Added the -v/-vv option to the most commonly used o3de sub-commands - Adds a custom argparse Action to make it easy to add verbosity option to other commands as needed. - Sets up parent-child loggers so that when verbosity is changed in a sub-command it will be applied globally to all logger instances. Also: - Fixes up many warnings, PEP8 improvements Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Update the log format in o3de script modules - Use a bit nicer format than the default, which was harder to read. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> --- scripts/o3de.py | 32 +++++---- scripts/o3de/o3de/cmake.py | 6 +- scripts/o3de/o3de/disable_gem.py | 14 ++-- scripts/o3de/o3de/download.py | 6 +- scripts/o3de/o3de/enable_gem.py | 13 ++-- scripts/o3de/o3de/engine_properties.py | 5 +- scripts/o3de/o3de/engine_template.py | 57 ++++++++++------ scripts/o3de/o3de/gem_properties.py | 4 +- scripts/o3de/o3de/get_registration.py | 13 ++-- scripts/o3de/o3de/global_project.py | 7 +- scripts/o3de/o3de/manifest.py | 28 +++++--- scripts/o3de/o3de/print_registration.py | 6 +- scripts/o3de/o3de/project_properties.py | 14 ++-- scripts/o3de/o3de/register.py | 33 +++++----- scripts/o3de/o3de/repo.py | 4 +- scripts/o3de/o3de/sha256.py | 14 ++-- scripts/o3de/o3de/utils.py | 86 +++++++++++++++++++------ scripts/o3de/o3de/validation.py | 29 +++++---- 18 files changed, 236 insertions(+), 135 deletions(-) diff --git a/scripts/o3de.py b/scripts/o3de.py index 05c3b53ba6..bf3bd32a52 100755 --- a/scripts/o3de.py +++ b/scripts/o3de.py @@ -7,20 +7,25 @@ # import argparse +import logging import pathlib import sys +logger = logging.getLogger('o3de') -def add_args(parser, subparsers) -> None: + +def add_args(parser: argparse.ArgumentParser) -> None: """ add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be invoked by o3de.py Ex o3de.py can invoke the register downloadable commands by importing register, call add_args and execute: python o3de.py register --gem-path "C:/TestGem" - :param parser: the caller instantiates a parser and passes it in here - :param subparsers: the caller instantiates subparsers and passes it in here + :param parser: the caller instantiates an ArgumentParser and passes it in here """ + subparsers = parser.add_subparsers(help='To get help on a sub-command:\no3de.py -h', + title='Sub-Commands') + # As o3de.py shares the same name as the o3de package attempting to use a regular # from o3de import line tries to import from the current o3de.py script and not the package # So the {current script directory} / 'o3de' is added to the front of the sys.path @@ -28,24 +33,25 @@ def add_args(parser, subparsers) -> None: o3de_package_dir = (script_dir / 'o3de').resolve() # add the scripts/o3de directory to the front of the sys.path sys.path.insert(0, str(o3de_package_dir)) - from o3de import engine_properties, engine_template, gem_properties, global_project, register, print_registration, get_registration, \ + from o3de import engine_properties, engine_template, gem_properties, \ + global_project, register, print_registration, get_registration, \ enable_gem, disable_gem, project_properties, sha256, download # Remove the temporarily added path sys.path = sys.path[1:] - # global_project + # global project global_project.add_args(subparsers) - # engine templaate + # engine template engine_template.add_args(subparsers) - # register + # registration register.add_args(subparsers) - # show + # show registration print_registration.add_args(subparsers) - # get-registered + # get registration get_registration.add_args(subparsers) # add a gem to a project @@ -74,11 +80,8 @@ if __name__ == "__main__": # parse the command line args the_parser = argparse.ArgumentParser() - # add subparsers - the_subparsers = the_parser.add_subparsers(help='sub-command help') - # add args to the parser - add_args(the_parser, the_subparsers) + add_args(the_parser) # parse args the_args = the_parser.parse_args() @@ -89,7 +92,8 @@ if __name__ == "__main__": sys.exit(1) # run - ret = the_args.func(the_args) + ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 + logger.info('Success!' if ret == 0 else 'Completed with issues: result {}'.format(ret)) # return sys.exit(ret) diff --git a/scripts/o3de/o3de/cmake.py b/scripts/o3de/o3de/cmake.py index ffac496387..ec970d06f4 100644 --- a/scripts/o3de/o3de/cmake.py +++ b/scripts/o3de/o3de/cmake.py @@ -13,10 +13,10 @@ import logging import os import pathlib -from o3de import manifest +from o3de import manifest, utils -logger = logging.getLogger() -logging.basicConfig() +logger = logging.getLogger('o3de.cmake') +logging.basicConfig(format=utils.LOG_FORMAT) enable_gem_start_marker = 'set(ENABLED_GEMS' enable_gem_end_marker = ')' diff --git a/scripts/o3de/o3de/disable_gem.py b/scripts/o3de/o3de/disable_gem.py index 158507fca1..0b0e465d12 100644 --- a/scripts/o3de/o3de/disable_gem.py +++ b/scripts/o3de/o3de/disable_gem.py @@ -15,10 +15,10 @@ import os import pathlib import sys -from o3de import cmake, manifest +from o3de import cmake, manifest, utils -logger = logging.getLogger() -logging.basicConfig() +logger = logging.getLogger('o3de.disable_gem') +logging.basicConfig(format=utils.LOG_FORMAT) def disable_gem_in_project(gem_name: str = None, @@ -73,7 +73,6 @@ def disable_gem_in_project(gem_name: str = None, logger.error(f'Gem Path {gem_path} does not exist.') return 1 - # Read gem.json from the gem path gem_json_data = manifest.get_gem_json_data(gem_path=gem_path, project_path=project_path) if not gem_json_data: @@ -116,6 +115,10 @@ def add_parser_args(parser): Ex. Directly run from this file alone with: python disable_gem.py --project-path D:/Test --gem-name Atom :param parser: the caller passes an argparse parser like instance to this method """ + + # Sub-commands should declare their own verbosity flag, if desired + utils.add_verbosity_arg(parser) + group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-pp', '--project-path', type=pathlib.Path, required=False, help='The path to the project.') @@ -155,8 +158,6 @@ def main(): # parse the command line args the_parser = argparse.ArgumentParser() - # add subparsers - # add args to the parser add_parser_args(the_parser) @@ -165,6 +166,7 @@ def main(): # run ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 + logger.info('Success!' if ret == 0 else 'Completed with issues: result {}'.format(ret)) # return sys.exit(ret) diff --git a/scripts/o3de/o3de/download.py b/scripts/o3de/o3de/download.py index e88355bf06..8e28561e50 100644 --- a/scripts/o3de/o3de/download.py +++ b/scripts/o3de/o3de/download.py @@ -24,8 +24,9 @@ from datetime import datetime from o3de import manifest, repo, utils, validation, register -logger = logging.getLogger() -logging.basicConfig() +logger = logging.getLogger('o3de.download') +logging.basicConfig(format=utils.LOG_FORMAT) + def unzip_manifest_json_data(download_zip_path: pathlib.Path, zip_file_name: str) -> dict: json_data = {} @@ -38,6 +39,7 @@ def unzip_manifest_json_data(download_zip_path: pathlib.Path, zip_file_name: str return json_data + def validate_downloaded_zip_sha256(download_uri_json_data: dict, download_zip_path: pathlib.Path, manifest_json_name) -> int: # if the json has a sha256 check it against a sha256 of the zip diff --git a/scripts/o3de/o3de/enable_gem.py b/scripts/o3de/o3de/enable_gem.py index 1614dc4eda..fc4dc6e9cf 100644 --- a/scripts/o3de/o3de/enable_gem.py +++ b/scripts/o3de/o3de/enable_gem.py @@ -16,10 +16,10 @@ import os import pathlib import sys -from o3de import cmake, manifest, register, validation +from o3de import cmake, manifest, register, validation, utils -logger = logging.getLogger() -logging.basicConfig() +logger = logging.getLogger('o3de.enable_gem') +logging.basicConfig(format=utils.LOG_FORMAT) def enable_gem_in_project(gem_name: str = None, @@ -132,6 +132,10 @@ def add_parser_args(parser): Ex. Directly run from this file alone with: python enable_gem.py --project-path "D:/TestProject" --gem-path "D:/TestGem" :param parser: the caller passes an argparse parser like instance to this method """ + + # Sub-commands should declare their own verbosity flag, if desired + utils.add_verbosity_arg(parser) + group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-pp', '--project-path', type=pathlib.Path, required=False, help='The path to the project.') @@ -171,8 +175,6 @@ def main(): # parse the command line args the_parser = argparse.ArgumentParser() - # add subparsers - # add args to the parser add_parser_args(the_parser) @@ -181,6 +183,7 @@ def main(): # run ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 + logger.info('Success!' if ret == 0 else 'Completed with issues: result {}'.format(ret)) # return sys.exit(ret) diff --git a/scripts/o3de/o3de/engine_properties.py b/scripts/o3de/o3de/engine_properties.py index 92930dbb1c..3ba30e4bf8 100644 --- a/scripts/o3de/o3de/engine_properties.py +++ b/scripts/o3de/o3de/engine_properties.py @@ -15,8 +15,9 @@ import logging from o3de import manifest, utils -logger = logging.getLogger() -logging.basicConfig() +logger = logging.getLogger('o3de.engine_properties') +logging.basicConfig(format=utils.LOG_FORMAT) + def edit_engine_props(engine_path: pathlib.Path = None, engine_name: str = None, diff --git a/scripts/o3de/o3de/engine_template.py b/scripts/o3de/o3de/engine_template.py index e93f972301..369086c9c3 100755 --- a/scripts/o3de/o3de/engine_template.py +++ b/scripts/o3de/o3de/engine_template.py @@ -20,8 +20,8 @@ import re from o3de import manifest, register, validation, utils -logger = logging.getLogger() -logging.basicConfig() +logger = logging.getLogger('o3de.engine_template') +logging.basicConfig(format=utils.LOG_FORMAT) binary_file_ext = { '.pak', @@ -86,6 +86,7 @@ restricted_platforms = { template_file_name = 'template.json' this_script_parent = pathlib.Path(os.path.dirname(os.path.realpath(__file__))) + def _replace_license_text(source_data: str): while '{BEGIN_LICENSE}' in source_data: start = source_data.find('{BEGIN_LICENSE}') @@ -181,7 +182,7 @@ def _execute_template_json(json_data: dict, # regular copy if not templated for copy_file in json_data['copyFiles']: # construct the input file name - in_file = template_path / 'Template' /copy_file['file'] + in_file = template_path / 'Template' / copy_file['file'] # the file can be marked as optional, if it is and it does not exist skip if copy_file['isOptional'] and copy_file['isOptional'] == 'true': @@ -246,7 +247,7 @@ def _execute_restricted_template_json(json_data: dict, for copy_file in json_data['copyFiles']: # construct the input file name in_file = template_restricted_path / restricted_platform / template_restricted_platform_relative_path\ - / template_name / 'Template'/ copy_file['file'] + / template_name / 'Template' / copy_file['file'] # the file can be marked as optional, if it is and it does not exist skip if copy_file['isOptional'] and copy_file['isOptional'] == 'true': @@ -364,7 +365,7 @@ def create_template(source_path: pathlib.Path, keep_restricted_in_template: bool = False, keep_license_text: bool = False, replace: list = None, - force: bool = False) -> int: + force: bool = False) -> int: """ Create a template from a source directory using replacement @@ -1205,12 +1206,12 @@ def create_from_template(destination_path: pathlib.Path, # something is wrong with either the --template-restricted-platform-relative or the template is. if template_restricted_platform_relative_path != template_json_restricted_platform_relative_path: logger.error(f'The supplied --template-restricted-platform-relative-path' - f' "{template_restricted_platform_relative_path}" does not match the' - f' templates.json "restricted_platform_relative_path". Either' - f' --template-restricted-platform-relative-path is incorrect or the templates' - f' "restricted_platform_relative_path" is wrong. Note that since this template' - f' specifies "restricted_platform_relative_path" it need not be supplied and' - f' "{template_json_restricted_platform_relative_path}" will be used.') + f' "{template_restricted_platform_relative_path}" does not match the' + f' templates.json "restricted_platform_relative_path". Either' + f' --template-restricted-platform-relative-path is incorrect or the templates' + f' "restricted_platform_relative_path" is wrong. Note that since this template' + f' specifies "restricted_platform_relative_path" it need not be supplied and' + f' "{template_json_restricted_platform_relative_path}" will be used.') return 1 else: # The user has not supplied --template-restricted-platform-relative-path, try to read it from @@ -1306,7 +1307,7 @@ def create_from_template(destination_path: pathlib.Path, os.makedirs(destination_restricted_path, exist_ok=True) # read the restricted_name from the destination restricted.json - restricted_json = destination_restricted_path / restricted.json + restricted_json = destination_restricted_path / 'restricted.json' if not os.path.isfile(restricted_json): with open(restricted_json, 'w') as s: restricted_json_data = {} @@ -1956,7 +1957,6 @@ def create_gem(gem_path: pathlib.Path, replacements.append(("${NameLower}", gem_name.lower())) replacements.append(("${SanitizedCppName}", sanitized_cpp_name)) - # module id is a uuid with { and - if module_id: replacements.append(("${ModuleClassId}", module_id)) @@ -2157,8 +2157,13 @@ def add_args(subparsers) -> None: call add_args and execute: python o3de.py create-gem --gem-path TestGem :param subparsers: the caller instantiates subparsers and passes it in here """ + # turn a directory into a template create_template_subparser = subparsers.add_parser('create-template') + + # Sub-commands should declare their own verbosity flag, if desired + utils.add_verbosity_arg(create_template_subparser) + create_template_subparser.add_argument('-sp', '--source-path', type=pathlib.Path, required=True, help='The path to the source that you want to make into a template') create_template_subparser.add_argument('-tp', '--template-path', type=pathlib.Path, required=False, @@ -2233,6 +2238,10 @@ def add_args(subparsers) -> None: # create from template create_from_template_subparser = subparsers.add_parser('create-from-template') + + # Sub-commands should declare their own verbosity flag, if desired + utils.add_verbosity_arg(create_from_template_subparser) + create_from_template_subparser.add_argument('-dp', '--destination-path', type=pathlib.Path, required=True, help='The path to where you want the template instantiated,' ' can be absolute or relative to the current working directory.' @@ -2316,6 +2325,10 @@ def add_args(subparsers) -> None: # creation of a project from a template (like create from template but makes project assumptions) create_project_subparser = subparsers.add_parser('create-project') + + # Sub-commands should declare their own verbosity flag, if desired + utils.add_verbosity_arg(create_project_subparser) + create_project_subparser.add_argument('-pp', '--project-path', type=pathlib.Path, required=True, help='The location of the project you wish to create from the template,' ' can be an absolute path or relative to the current working directory.' @@ -2330,7 +2343,7 @@ def add_args(subparsers) -> None: group = create_project_subparser.add_mutually_exclusive_group(required=False) group.add_argument('-tp', '--template-path', type=pathlib.Path, required=False, default=None, - help='the path to the template you want to instance, can be absolute or' + help='The path to the template you want to instance, can be absolute or' ' relative to default templates path') group.add_argument('-tn', '--template-name', type=str, required=False, default=None, @@ -2340,7 +2353,7 @@ def add_args(subparsers) -> None: group = create_project_subparser.add_mutually_exclusive_group(required=False) group.add_argument('-prp', '--project-restricted-path', type=pathlib.Path, required=False, default=None, - help='path to the projects restricted folder, can be absolute or relative to' + help='The path to the projects restricted folder, can be absolute or relative to' ' the default restricted projects directory') group.add_argument('-prn', '--project-restricted-name', type=str, required=False, default=None, @@ -2351,7 +2364,7 @@ def add_args(subparsers) -> None: group.add_argument('-trp', '--template-restricted-path', type=pathlib.Path, required=False, default=None, help='The templates restricted path can be absolute or relative to' - 'the default restricted templates directory') + ' the default restricted templates directory') group.add_argument('-trn', '--template-restricted-name', type=str, required=False, default=None, help='The name of the registered templates restricted path. If supplied this will resolve' @@ -2413,6 +2426,10 @@ def add_args(subparsers) -> None: # creation of a gem from a template (like create from template but makes gem assumptions) create_gem_subparser = subparsers.add_parser('create-gem') + + # Sub-commands should declare their own verbosity flag, if desired + utils.add_verbosity_arg(create_gem_subparser) + create_gem_subparser.add_argument('-gp', '--gem-path', type=pathlib.Path, required=True, help='The gem path, can be absolute or relative to the current working directory') create_gem_subparser.add_argument('-gn', '--gem-name', type=str, @@ -2512,16 +2529,18 @@ if __name__ == "__main__": the_parser = argparse.ArgumentParser() # add subparsers - the_subparsers = the_parser.add_subparsers(help='sub-command help', dest='command', required=True) + subparsers = the_parser.add_subparsers(help='To get help on a sub-command:\nengine_template.py -h', + title='Sub-Commands', dest='command', required=True) - # add args to the parser - add_args(the_subparsers) + # add args to the parsers + add_args(subparsers) # parse args the_args = the_parser.parse_args() # run ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 + logger.info('Success!' if ret == 0 else 'Completed with issues: result {}'.format(ret)) # return sys.exit(ret) diff --git a/scripts/o3de/o3de/gem_properties.py b/scripts/o3de/o3de/gem_properties.py index faaa4f86ec..423dc47115 100644 --- a/scripts/o3de/o3de/gem_properties.py +++ b/scripts/o3de/o3de/gem_properties.py @@ -15,8 +15,8 @@ import logging from o3de import manifest, utils -logger = logging.getLogger() -logging.basicConfig() +logger = logging.getLogger('o3de.gem_properties') +logging.basicConfig(format=utils.LOG_FORMAT) def update_values_in_key_list(existing_values: list, new_values: list or str, remove_values: list or str, diff --git a/scripts/o3de/o3de/get_registration.py b/scripts/o3de/o3de/get_registration.py index 8b8d53a8b0..675d1d009e 100644 --- a/scripts/o3de/o3de/get_registration.py +++ b/scripts/o3de/o3de/get_registration.py @@ -12,17 +12,18 @@ import sys from o3de import manifest + def _run_get_registered(args: argparse) -> str or pathlib.Path: if args.override_home_folder: manifest.override_home_folder = args.override_home_folder return manifest.get_registered(args.engine_name, - args.project_name, - args.gem_name, - args.template_name, - args.default_folder, - args.repo_name, - args.restricted_name) + args.project_name, + args.gem_name, + args.template_name, + args.default_folder, + args.repo_name, + args.restricted_name) def add_parser_args(parser): diff --git a/scripts/o3de/o3de/global_project.py b/scripts/o3de/o3de/global_project.py index 9463306912..7ff90bead4 100644 --- a/scripts/o3de/o3de/global_project.py +++ b/scripts/o3de/o3de/global_project.py @@ -14,14 +14,15 @@ import re import pathlib import json -from o3de import manifest, validation +from o3de import manifest, validation, utils -logger = logging.getLogger() -logging.basicConfig() +logger = logging.getLogger('o3de.global_project') +logging.basicConfig(format=utils.LOG_FORMAT) DEFAULT_BOOTSTRAP_SETREG = pathlib.Path('~/.o3de/Registry/bootstrap.setreg').expanduser() PROJECT_PATH_KEY = ('Amazon', 'AzCore', 'Bootstrap', 'project_path') + def get_json_data(input_path: pathlib.Path): setreg_json_data = {} # If the output_path exist validate that it is a valid json file diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index e46b819a7c..ab48915fe4 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -18,8 +18,8 @@ import hashlib from o3de import validation, utils -logger = logging.getLogger() -logging.basicConfig() +logger = logging.getLogger('o3de.manifest') +logging.basicConfig(format=utils.LOG_FORMAT) # Directory methods override_home_folder = None @@ -41,6 +41,7 @@ def get_o3de_folder() -> pathlib.Path: o3de_folder.mkdir(parents=True, exist_ok=True) return o3de_folder + def get_o3de_user_folder() -> pathlib.Path: o3de_user_folder = get_home_folder() / 'O3DE' o3de_user_folder.mkdir(parents=True, exist_ok=True) @@ -177,6 +178,7 @@ def get_default_o3de_manifest_json_data() -> dict: return json_data + def get_o3de_manifest() -> pathlib.Path: manifest_path = get_o3de_folder() / 'o3de_manifest.json' if not manifest_path.is_file(): @@ -228,11 +230,11 @@ def save_o3de_manifest(json_data: dict, manifest_path: pathlib.Path = None) -> b def get_gems_from_subdirectories(external_subdirs: list) -> list: - ''' + """ Helper Method for scanning a set of external subdirectories for gem.json files - ''' + """ def is_gem_subdirectory(subdir_files): - for name in files: + for name in subdir_files: if name == 'gem.json': return True return False @@ -285,13 +287,14 @@ def get_repos() -> list: json_data = load_o3de_manifest() return json_data['repos'] if 'repos' in json_data else [] + # engine.json queries def get_engine_projects() -> list: engine_path = get_this_engine_path() engine_object = get_engine_json_data(engine_path=engine_path) if engine_object: return list(map(lambda rel_path: (pathlib.Path(engine_path) / rel_path).as_posix(), - engine_object['projects'])) if 'projects' in engine_object else [] + engine_object['projects'])) if 'projects' in engine_object else [] return [] @@ -313,7 +316,7 @@ def get_engine_templates() -> list: engine_object = get_engine_json_data(engine_path=engine_path) if engine_object: return list(map(lambda rel_path: (pathlib.Path(engine_path) / rel_path).as_posix(), - engine_object['templates'])) if 'templates' in engine_object else [] + engine_object['templates'])) if 'templates' in engine_object else [] return [] @@ -335,7 +338,7 @@ def get_project_external_subdirectories(project_path: pathlib.Path) -> list: project_object = get_project_json_data(project_path=project_path) if project_object: return list(map(lambda rel_path: (pathlib.Path(project_path) / rel_path).as_posix(), - project_object['external_subdirectories'])) if 'external_subdirectories' in project_object else [] + project_object['external_subdirectories'])) if 'external_subdirectories' in project_object else [] return [] @@ -343,7 +346,7 @@ def get_project_templates(project_path: pathlib.Path) -> list: project_object = get_project_json_data(project_path=project_path) if project_object: return list(map(lambda rel_path: (pathlib.Path(project_path) / rel_path).as_posix(), - project_object['templates'])) if 'templates' in project_object else [] + project_object['templates'])) if 'templates' in project_object else [] return [] @@ -433,6 +436,7 @@ def get_templates_for_generic_creation(): # temporary until we have a better wa return list(filter(filter_project_and_gem_templates_out, get_all_templates())) + def get_json_file_path(object_typename: str, object_path: str or pathlib.Path) -> pathlib.Path: if not object_typename or not object_path: @@ -468,6 +472,7 @@ def get_json_data_file(object_json: pathlib.Path, return None + def get_json_data(object_typename: str, object_path: str or pathlib.Path, object_validator: callable) -> dict or None: @@ -538,6 +543,7 @@ def get_restricted_json_data(restricted_name: str = None, restricted_path: str o return get_json_data('restricted', restricted_path, validation.valid_o3de_restricted_json) + def get_repo_json_data(repo_uri: str) -> dict or None: if not repo_uri: logger.error('Must specify a Repo Uri.') @@ -547,7 +553,8 @@ def get_repo_json_data(repo_uri: str) -> dict or None: return get_json_data_file(repo_json, "Repo", validation.valid_o3de_repo_json) -def get_repo_path(repo_uri: str, cache_folder: str = None) -> pathlib.Path: + +def get_repo_path(repo_uri: str, cache_folder: str or pathlib.Path = None) -> pathlib.Path: if not cache_folder: cache_folder = get_o3de_cache_folder() @@ -555,6 +562,7 @@ def get_repo_path(repo_uri: str, cache_folder: str = None) -> pathlib.Path: repo_sha256 = hashlib.sha256(repo_manifest.encode()) return cache_folder / str(repo_sha256.hexdigest() + '.json') + def get_registered(engine_name: str = None, project_name: str = None, gem_name: str = None, diff --git a/scripts/o3de/o3de/print_registration.py b/scripts/o3de/o3de/print_registration.py index 4b4c9d6515..f81decb6c3 100644 --- a/scripts/o3de/o3de/print_registration.py +++ b/scripts/o3de/o3de/print_registration.py @@ -14,10 +14,10 @@ import pathlib import sys import urllib.parse -from o3de import manifest, validation +from o3de import manifest, validation, utils -logger = logging.getLogger() -logging.basicConfig() +logger = logging.getLogger('o3de.print_registration') +logging.basicConfig(format=utils.LOG_FORMAT) def get_project_path(project_path: pathlib.Path, project_name: str) -> pathlib.Path: diff --git a/scripts/o3de/o3de/project_properties.py b/scripts/o3de/o3de/project_properties.py index 04731ad3de..bbddd5adab 100644 --- a/scripts/o3de/o3de/project_properties.py +++ b/scripts/o3de/o3de/project_properties.py @@ -15,8 +15,9 @@ import logging from o3de import manifest, utils -logger = logging.getLogger() -logging.basicConfig() +logger = logging.getLogger('o3de.project_properties') +logging.basicConfig(format=utils.LOG_FORMAT) + def get_project_props(name: str = None, path: pathlib.Path = None) -> dict: proj_json = manifest.get_project_json_data(project_name=name, project_path=path) @@ -26,6 +27,7 @@ def get_project_props(name: str = None, path: pathlib.Path = None) -> dict: return None return proj_json + def edit_project_props(proj_path: pathlib.Path = None, proj_name: str = None, new_name: str = None, @@ -71,9 +73,9 @@ def edit_project_props(proj_path: pathlib.Path = None, tag_list = replace_tags.split() if isinstance(replace_tags, str) else replace_tags proj_json['user_tags'] = tag_list - return 0 if manifest.save_o3de_manifest(proj_json, pathlib.Path(proj_path) / 'project.json') else 1 + def _edit_project_props(args: argparse) -> int: return edit_project_props(args.project_path, args.project_name, @@ -86,6 +88,7 @@ def _edit_project_props(args: argparse) -> int: args.delete_tags, args.replace_tags) + def add_parser_args(parser): group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-pp', '--project-path', type=pathlib.Path, required=False, @@ -112,10 +115,12 @@ def add_parser_args(parser): help='Replace entirety of user_tags property with space delimited list of values') parser.set_defaults(func=_edit_project_props) + def add_args(subparsers) -> None: enable_project_props_subparser = subparsers.add_parser('edit-project-properties') add_parser_args(enable_project_props_subparser) - + + def main(): the_parser = argparse.ArgumentParser() add_parser_args(the_parser) @@ -123,5 +128,6 @@ def main(): ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 sys.exit(ret) + if __name__ == "__main__": main() diff --git a/scripts/o3de/o3de/register.py b/scripts/o3de/o3de/register.py index 62a342f948..7625ee8ba9 100644 --- a/scripts/o3de/o3de/register.py +++ b/scripts/o3de/o3de/register.py @@ -23,8 +23,8 @@ import urllib.request from o3de import get_registration, manifest, repo, utils, validation -logger = logging.getLogger() -logging.basicConfig() +logger = logging.getLogger('o3de.register') +logging.basicConfig(format=utils.LOG_FORMAT) def register_shipped_engine_o3de_objects(force: bool = False) -> int: @@ -306,9 +306,9 @@ def register_o3de_object_path(json_data: dict, try: paths_to_remove.append(o3de_object_path.relative_to(save_path.parent)) except ValueError: - pass # It is not an error if a relative path cannot be formed + pass # It is not an error if a relative path cannot be formed manifest_data[o3de_object_key] = list(filter(lambda p: pathlib.Path(p) not in paths_to_remove, - manifest_data.setdefault(o3de_object_key, []))) + manifest_data.setdefault(o3de_object_key, []))) if remove: if save_path: @@ -732,14 +732,14 @@ def register(engine_path: pathlib.Path = None, logger.error(f'Gem path cannot be empty.') return 1 result = result or register_gem_path(json_data, gem_path, remove, - external_subdir_engine_path, external_subdir_project_path) + external_subdir_engine_path, external_subdir_project_path) if isinstance(external_subdir_path, pathlib.PurePath): if not external_subdir_path: logger.error(f'External Subdirectory path is None.') return 1 result = result or register_external_subdirectory(json_data, external_subdir_path, remove, - external_subdir_engine_path, external_subdir_project_path) + external_subdir_engine_path, external_subdir_project_path) if isinstance(template_path, pathlib.PurePath): if not template_path: @@ -841,6 +841,10 @@ def add_parser_args(parser): Ex. Directly run from this file alone with: python register.py --engine-path "C:/o3de" :param parser: the caller passes an argparse parser like instance to this method """ + + # Sub-commands should declare their own verbosity flag, if desired + utils.add_verbosity_arg(parser) + group = parser.add_mutually_exclusive_group(required=True) group.add_argument('--this-engine', action='store_true', required=False, default=False, @@ -888,18 +892,18 @@ def add_parser_args(parser): help='Refresh the repo cache.') parser.add_argument('-ohf', '--override-home-folder', type=pathlib.Path, required=False, - help='By default the home folder is the user folder, override it to this folder.') + help='By default the home folder is the user folder, override it to this folder.') parser.add_argument('-r', '--remove', action='store_true', required=False, - default=False, - help='Remove entry.') + default=False, + help='Remove entry.') parser.add_argument('-f', '--force', action='store_true', default=False, - help='For the update of the registration field being modified.') + help='For the update of the registration field being modified.') - external_subdir_group = parser.add_argument_group(title='external-subdirectory', - description='path arguments to use with the --external-subdirectory option') + external_subdir_group = parser.add_argument_group(title='external-subdirectory', + description='path arguments to use with the --external-subdirectory option') external_subdir_path_group = external_subdir_group.add_mutually_exclusive_group() external_subdir_path_group.add_argument('-esep', '--external-subdirectory-engine-path', type=pathlib.Path, - help='If supplied, registers the external subdirectory with the engine.json at' \ + help='If supplied, registers the external subdirectory with the engine.json at' \ ' the engine-path location') external_subdir_path_group.add_argument('-espp', '--external-subdirectory-project-path', type=pathlib.Path) parser.set_defaults(func=_run_register) @@ -924,8 +928,6 @@ def main(): # parse the command line args the_parser = argparse.ArgumentParser() - # add subparsers - # add args to the parser add_parser_args(the_parser) @@ -934,6 +936,7 @@ def main(): # run ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 + logger.info('Success!' if ret == 0 else 'Completed with issues: result {}'.format(ret)) # return sys.exit(ret) diff --git a/scripts/o3de/o3de/repo.py b/scripts/o3de/o3de/repo.py index 22c7c54c8f..41c2d235d9 100644 --- a/scripts/o3de/o3de/repo.py +++ b/scripts/o3de/o3de/repo.py @@ -15,8 +15,8 @@ import hashlib from datetime import datetime from o3de import manifest, utils, validation -logger = logging.getLogger() -logging.basicConfig() +logger = logging.getLogger('o3de.repo') +logging.basicConfig(format=utils.LOG_FORMAT) def process_add_o3de_repo(file_name: str or pathlib.Path, diff --git a/scripts/o3de/o3de/sha256.py b/scripts/o3de/o3de/sha256.py index b8f8e522d4..c2eaae073f 100644 --- a/scripts/o3de/o3de/sha256.py +++ b/scripts/o3de/o3de/sha256.py @@ -15,8 +15,8 @@ import sys from o3de import utils -logger = logging.getLogger() -logging.basicConfig() +logger = logging.getLogger('o3de.sha256') +logging.basicConfig(format=utils.LOG_FORMAT) def sha256(file_path: str or pathlib.Path, @@ -35,7 +35,7 @@ def sha256(file_path: str or pathlib.Path, logger.error(f'Json path {json_path} does not exist.') return 1 - sha256 = hashlib.sha256(file_path.open('rb').read()).hexdigest() + the_sha256 = hashlib.sha256(file_path.open('rb').read()).hexdigest() if json_path: with json_path.open('r') as s: @@ -44,7 +44,7 @@ def sha256(file_path: str or pathlib.Path, except json.JSONDecodeError as e: logger.error(f'Failed to read Json path {json_path}: {str(e)}') return 1 - json_data.update({"sha256": sha256}) + json_data.update({"sha256": the_sha256}) utils.backup_file(json_path) with json_path.open('w') as s: try: @@ -53,7 +53,7 @@ def sha256(file_path: str or pathlib.Path, logger.error(f'Failed to write Json path {json_path}: {str(e)}') return 1 else: - print(sha256) + print(the_sha256) return 0 @@ -70,9 +70,9 @@ def add_parser_args(parser): :param parser: the caller passes an argparse parser like instance to this method """ parser.add_argument('-f', '--file-path', type=str, required=True, - help='The path to the file you want to sha256.') + help='The path to the file you want to sha256.') parser.add_argument('-j', '--json-path', type=str, required=False, - help='optional path to an o3de json file to add the "sha256" element to.') + help='Optional path to an o3de json file to add the "sha256" element to.') parser.set_defaults(func=_run_sha256) diff --git a/scripts/o3de/o3de/utils.py b/scripts/o3de/o3de/utils.py index 6f1dd8b2c5..6628e6c946 100644 --- a/scripts/o3de/o3de/utils.py +++ b/scripts/o3de/o3de/utils.py @@ -8,6 +8,7 @@ """ This file contains utility functions """ +import argparse import sys import uuid import os @@ -17,11 +18,54 @@ import urllib.request import logging import zipfile -logger = logging.getLogger() -logging.basicConfig() +LOG_FORMAT = '[%(levelname)s] %(name)s: %(message)s' + +logger = logging.getLogger('o3de.utils') +logging.basicConfig(format=LOG_FORMAT) COPY_BUFSIZE = 64 * 1024 + +class VerbosityAction(argparse.Action): + def __init__(self, + option_strings, + dest, + default=None, + required=False, + help=None): + super().__init__( + option_strings=option_strings, + dest=dest, + nargs=0, + default=default, + required=required, + help=help, + ) + + def __call__(self, parser, namespace, values, option_string=None): + count = getattr(namespace, self.dest, None) + if count is None: + count = self.default + count += 1 + setattr(namespace, self.dest, count) + # get the parent logger instance + log = logging.getLogger('o3de') + if count >= 2: + log.setLevel(logging.DEBUG) + elif count == 1: + log.setLevel(logging.INFO) + + +def add_verbosity_arg(parser: argparse.ArgumentParser) -> None: + """ + Add a consistent/common verbosity option to an arg parser + :param parser: The ArgumentParser to modify + :return: None + """ + parser.add_argument('-v', dest='verbosity', action=VerbosityAction, default=0, + help='Additional logging verbosity, can be -v or -vv') + + def copyfileobj(fsrc, fdst, callback, length=0): # This is functionally the same as the python shutil copyfileobj but # allows for a callback to return the download progress in blocks and allows @@ -43,10 +87,11 @@ def copyfileobj(fsrc, fdst, callback, length=0): return 1 return 0 + def validate_identifier(identifier: str) -> bool: """ - Determine if the identifier supplied is valid. - :param identifier: the name which needs to to checked + Determine if the identifier supplied is valid + :param identifier: the name which needs to be checked :return: bool: if the identifier is valid or not """ if not identifier: @@ -65,7 +110,7 @@ def validate_identifier(identifier: str) -> bool: def sanitize_identifier_for_cpp(identifier: str) -> str: """ Convert the provided identifier to a valid C++ identifier - :param identifier: the name which needs to to sanitized + :param identifier: the name which needs to be sanitized :return: str: sanitized identifier """ if not identifier: @@ -81,8 +126,8 @@ def sanitize_identifier_for_cpp(identifier: str) -> str: def validate_uuid4(uuid_string: str) -> bool: """ - Determine if the uuid supplied is valid. - :param uuid_string: the uuid which needs to to checked + Determine if the uuid supplied is valid + :param uuid_string: the uuid which needs to be checked :return: bool: if the uuid is valid or not """ try: @@ -117,11 +162,13 @@ def backup_folder(folder: str or pathlib.Path) -> None: if backup_folder_name.is_dir(): renamed = True + def download_file(parsed_uri, download_path: pathlib.Path, force_overwrite: bool = False, download_progress_callback = None) -> int: """ + Download file :param parsed_uri: uniform resource identifier to zip file to download :param download_path: location path on disk to download file - :download_progress_callback: callback called with the download progress as a percentage, returns true to request to cancel the download + :param download_progress_callback: callback called with the download progress as a percentage, returns true to request to cancel the download """ if download_path.is_file(): if not force_overwrite: @@ -142,10 +189,12 @@ def download_file(parsed_uri, download_path: pathlib.Path, force_overwrite: bool download_file_size = s.headers['content-length'] except KeyError: pass + def download_progress(downloaded_bytes): if download_progress_callback: return download_progress_callback(int(downloaded_bytes), int(download_file_size)) return False + with download_path.open('wb') as f: download_cancelled = copyfileobj(s, f, download_progress) if download_cancelled: @@ -183,13 +232,12 @@ def download_zip_file(parsed_uri, download_zip_path: pathlib.Path, force_overwri def find_ancestor_file(target_file_name: pathlib.PurePath, start_path: pathlib.Path, max_scan_up_range: int=0) -> pathlib.Path or None: """ - Find a file with the given name in the ancestor directories by walking up the starting path until the file is found. - - :param target_file_name: Name of the file to find. - :param start_path: path to start looking for the file. + Find a file with the given name in the ancestor directories by walking up the starting path until the file is found + :param target_file_name: Name of the file to find + :param start_path: path to start looking for the file :param max_scan_up_range: maximum number of directories to scan upwards when searching for target file if the value is 0, then there is no max - :return: Path to the file or None if not found. + :return: Path to the file or None if not found """ current_path = pathlib.Path(start_path) candidate_path = current_path / target_file_name @@ -211,17 +259,17 @@ def find_ancestor_file(target_file_name: pathlib.PurePath, start_path: pathlib.P return candidate_path if candidate_path.exists() else None + def find_ancestor_dir_containing_file(target_file_name: pathlib.PurePath, start_path: pathlib.Path, max_scan_up_range: int=0) -> pathlib.Path or None: """ - Find nearest ancestor directory that contains the file with the given name by walking up - from the starting path. - - :param target_file_name: Name of the file to find. - :param start_path: path to start looking for the file. + Find the nearest ancestor directory that contains the file with the given name by walking up + from the starting path + :param target_file_name: Name of the file to find + :param start_path: path to start looking for the file :param max_scan_up_range: maximum number of directories to scan upwards when searching for target file if the value is 0, then there is no max - :return: Path to the directory containing file or None if not found. + :return: Path to the directory containing file or None if not found """ ancestor_file = find_ancestor_file(target_file_name, start_path, max_scan_up_range) return ancestor_file.parent if ancestor_file else None diff --git a/scripts/o3de/o3de/validation.py b/scripts/o3de/o3de/validation.py index 5c683f0667..cd0958a250 100644 --- a/scripts/o3de/o3de/validation.py +++ b/scripts/o3de/o3de/validation.py @@ -11,6 +11,7 @@ This file validating o3de object json files import json import pathlib + def valid_o3de_json_dict(json_data: dict, key: str) -> bool: return key in json_data @@ -23,9 +24,9 @@ def valid_o3de_repo_json(file_name: str or pathlib.Path) -> bool: with file_name.open('r') as f: try: json_data = json.load(f) - test = json_data['repo_name'] - test = json_data['origin'] - except (json.JSONDecodeError, KeyError) as e: + _ = json_data['repo_name'] + _ = json_data['origin'] + except (json.JSONDecodeError, KeyError): return False return True @@ -38,8 +39,8 @@ def valid_o3de_engine_json(file_name: str or pathlib.Path) -> bool: with file_name.open('r') as f: try: json_data = json.load(f) - test = json_data['engine_name'] - except (json.JSONDecodeError, KeyError) as e: + _ = json_data['engine_name'] + except (json.JSONDecodeError, KeyError): return False return True @@ -52,8 +53,8 @@ def valid_o3de_project_json(file_name: str or pathlib.Path) -> bool: with file_name.open('r') as f: try: json_data = json.load(f) - test = json_data['project_name'] - except (json.JSONDecodeError, KeyError) as e: + _ = json_data['project_name'] + except (json.JSONDecodeError, KeyError): return False return True @@ -66,8 +67,8 @@ def valid_o3de_gem_json(file_name: str or pathlib.Path) -> bool: with file_name.open('r') as f: try: json_data = json.load(f) - test = json_data['gem_name'] - except (json.JSONDecodeError, KeyError) as e: + _ = json_data['gem_name'] + except (json.JSONDecodeError, KeyError): return False return True @@ -76,11 +77,12 @@ def valid_o3de_template_json(file_name: str or pathlib.Path) -> bool: file_name = pathlib.Path(file_name).resolve() if not file_name.is_file(): return False + with file_name.open('r') as f: try: json_data = json.load(f) - test = json_data['template_name'] - except (json.JSONDecodeError, KeyError) as e: + _ = json_data['template_name'] + except (json.JSONDecodeError, KeyError): return False return True @@ -89,10 +91,11 @@ def valid_o3de_restricted_json(file_name: str or pathlib.Path) -> bool: file_name = pathlib.Path(file_name).resolve() if not file_name.is_file(): return False + with file_name.open('r') as f: try: json_data = json.load(f) - test = json_data['restricted_name'] - except (json.JSONDecodeError, KeyError) as e: + _ = json_data['restricted_name'] + except (json.JSONDecodeError, KeyError): return False return True From 3405cee2efebba807ccf8cbebec6017031809340 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Tue, 7 Dec 2021 10:46:30 -0800 Subject: [PATCH 126/128] GUI for engine force registration and renaming (#6184) Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../ProjectManager/Source/Application.cpp | 86 ++++++++ .../Tools/ProjectManager/Source/Application.h | 1 + Code/Tools/ProjectManager/Source/EngineInfo.h | 5 +- .../Source/EngineSettingsScreen.cpp | 5 +- .../Source/GemRepo/GemRepoScreen.cpp | 19 +- .../ProjectManager/Source/ProjectUtils.cpp | 19 ++ .../ProjectManager/Source/ProjectUtils.h | 9 + .../ProjectManager/Source/PythonBindings.cpp | 185 ++++++++++-------- .../ProjectManager/Source/PythonBindings.h | 12 +- .../Source/PythonBindingsInterface.h | 24 ++- scripts/o3de/o3de/engine_properties.py | 5 + scripts/o3de/o3de/manifest.py | 105 +++++----- 12 files changed, 321 insertions(+), 154 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/Application.cpp b/Code/Tools/ProjectManager/Source/Application.cpp index 29e0df3c3a..08a812999f 100644 --- a/Code/Tools/ProjectManager/Source/Application.cpp +++ b/Code/Tools/ProjectManager/Source/Application.cpp @@ -21,6 +21,7 @@ #include #include #include +#include namespace O3DE::ProjectManager { @@ -111,6 +112,11 @@ namespace O3DE::ProjectManager } } + if (!RegisterEngine(interactive)) + { + return false; + } + const AZ::CommandLine* commandLine = GetCommandLine(); AZ_Assert(commandLine, "Failed to get command line"); @@ -165,6 +171,86 @@ namespace O3DE::ProjectManager return m_entity != nullptr; } + bool Application::RegisterEngine(bool interactive) + { + // get this engine's info + auto engineInfoOutcome = m_pythonBindings->GetEngineInfo(); + if (!engineInfoOutcome) + { + if (interactive) + { + QMessageBox::critical(nullptr, + QObject::tr("Failed to get engine info"), + QObject::tr("A valid engine.json could not be found or loaded. " + "Please verify a valid engine.json file exists in %1") + .arg(GetEngineRoot())); + } + + AZ_Error("Project Manager", false, "Failed to get engine info"); + return false; + } + + EngineInfo engineInfo = engineInfoOutcome.GetValue(); + if (engineInfo.m_registered) + { + return true; + } + + bool forceRegistration = false; + + // check if an engine with this name is already registered + auto existingEngineResult = m_pythonBindings->GetEngineInfo(engineInfo.m_name); + if (existingEngineResult) + { + if (!interactive) + { + AZ_Error("Project Manager", false, "An engine with the name %s is already registered with the path %s", + engineInfo.m_name.toUtf8().constData(), engineInfo.m_path.toUtf8().constData()); + return false; + } + + // get the updated engine name unless the user wants to cancel + bool okPressed = false; + const EngineInfo& otherEngineInfo = existingEngineResult.GetValue(); + + engineInfo.m_name = QInputDialog::getText(nullptr, + QObject::tr("Engine '%1' already registered").arg(engineInfo.m_name), + QObject::tr("An engine named '%1' is already registered.

" + "Current path
%2

" + "New path
%3

" + "Press 'OK' to force registration, or provide a new engine name below.
" + "Alternatively, press `Cancel` to close the Project Manager and resolve the issue manually.") + .arg(engineInfo.m_name, otherEngineInfo.m_path, engineInfo.m_path), + QLineEdit::Normal, + engineInfo.m_name, + &okPressed); + + if (!okPressed) + { + // user elected not to change the name or force registration + return false; + } + + forceRegistration = true; + } + + auto registerOutcome = m_pythonBindings->SetEngineInfo(engineInfo, forceRegistration); + if (!registerOutcome) + { + if (interactive) + { + ProjectUtils::DisplayDetailedError(QObject::tr("Failed to register engine"), registerOutcome); + } + + AZ_Error("Project Manager", false, "Failed to register engine %s : %s", + engineInfo.m_path.toUtf8().constData(), registerOutcome.GetError().first.c_str()); + + return false; + } + + return true; + } + void Application::TearDown() { if (m_entity) diff --git a/Code/Tools/ProjectManager/Source/Application.h b/Code/Tools/ProjectManager/Source/Application.h index ad55694b18..8f633b28c4 100644 --- a/Code/Tools/ProjectManager/Source/Application.h +++ b/Code/Tools/ProjectManager/Source/Application.h @@ -34,6 +34,7 @@ namespace O3DE::ProjectManager private: bool InitLog(const char* logName); + bool RegisterEngine(bool interactive); AZStd::unique_ptr m_pythonBindings; QSharedPointer m_app; diff --git a/Code/Tools/ProjectManager/Source/EngineInfo.h b/Code/Tools/ProjectManager/Source/EngineInfo.h index 5fd3faf2ea..c28aede030 100644 --- a/Code/Tools/ProjectManager/Source/EngineInfo.h +++ b/Code/Tools/ProjectManager/Source/EngineInfo.h @@ -25,13 +25,16 @@ namespace O3DE::ProjectManager QString m_name; QString m_thirdPartyPath; - // from o3de_manifest.json QString m_path; + + // from o3de_manifest.json QString m_defaultProjectsFolder; QString m_defaultGemsFolder; QString m_defaultTemplatesFolder; QString m_defaultRestrictedFolder; + bool m_registered = false; + bool IsValid() const; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp index c7df00f423..26f5b8ae11 100644 --- a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -114,10 +115,10 @@ namespace O3DE::ProjectManager engineInfo.m_defaultGemsFolder = m_defaultGems->lineEdit()->text(); engineInfo.m_defaultTemplatesFolder = m_defaultProjectTemplates->lineEdit()->text(); - bool result = PythonBindingsInterface::Get()->SetEngineInfo(engineInfo); + auto result = PythonBindingsInterface::Get()->SetEngineInfo(engineInfo); if (!result) { - QMessageBox::critical(this, tr("Engine Settings"), tr("Failed to save engine settings.")); + ProjectUtils::DisplayDetailedError(tr("Failed to save engine settings"), result, this); } } else diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index f62c30c280..843538d9da 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -92,8 +93,7 @@ namespace O3DE::ProjectManager return; } - AZ::Outcome < void, - AZStd::pair> addGemRepoResult = PythonBindingsInterface::Get()->AddGemRepo(repoUri); + auto addGemRepoResult = PythonBindingsInterface::Get()->AddGemRepo(repoUri); if (addGemRepoResult.IsSuccess()) { Reinit(); @@ -102,20 +102,7 @@ namespace O3DE::ProjectManager else { QString failureMessage = tr("Failed to add gem repo: %1.").arg(repoUri); - if (!addGemRepoResult.GetError().second.empty()) - { - QMessageBox addRepoError; - addRepoError.setIcon(QMessageBox::Critical); - addRepoError.setWindowTitle(failureMessage); - addRepoError.setText(addGemRepoResult.GetError().first.c_str()); - addRepoError.setDetailedText(addGemRepoResult.GetError().second.c_str()); - addRepoError.exec(); - } - else - { - QMessageBox::critical(this, failureMessage, addGemRepoResult.GetError().first.c_str()); - } - + ProjectUtils::DisplayDetailedError(failureMessage, addGemRepoResult, this); AZ_Error("Project Manager", false, failureMessage.toUtf8()); } } diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp index b7748d8aa2..209140a004 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp @@ -659,5 +659,24 @@ namespace O3DE::ProjectManager return AZ::Success(QString(projectBuildPath.c_str())); } + void DisplayDetailedError(const QString& title, const AZ::Outcome>& outcome, QWidget* parent) + { + const AZStd::string& generalError = outcome.GetError().first; + const AZStd::string& detailedError = outcome.GetError().second; + + if (!detailedError.empty()) + { + QMessageBox errorDialog(parent); + errorDialog.setIcon(QMessageBox::Critical); + errorDialog.setWindowTitle(title); + errorDialog.setText(generalError.c_str()); + errorDialog.setDetailedText(detailedError.c_str()); + errorDialog.exec(); + } + else + { + QMessageBox::critical(parent, title, generalError.c_str()); + } + } } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.h b/Code/Tools/ProjectManager/Source/ProjectUtils.h index 713803c20b..8602ffa692 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.h +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.h @@ -98,5 +98,14 @@ namespace O3DE::ProjectManager */ AZ::IO::FixedMaxPath GetEditorExecutablePath(const AZ::IO::PathView& projectPath); + + /** + * Display a dialog with general and detailed sections for the given AZ::Outcome + * @param title Dialog title + * @param outcome The AZ::Outcome with general and detailed error messages + * @param parent Optional QWidget parent + */ + void DisplayDetailedError(const QString& title, const AZ::Outcome>& outcome, QWidget* parent = nullptr); + } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 12f97e6d2e..00ece7396d 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -312,6 +312,7 @@ namespace O3DE::ProjectManager m_register = pybind11::module::import("o3de.register"); m_manifest = pybind11::module::import("o3de.manifest"); m_engineTemplate = pybind11::module::import("o3de.engine_template"); + m_engineProperties = pybind11::module::import("o3de.engine_properties"); m_enableGemProject = pybind11::module::import("o3de.enable_gem"); m_disableGemProject = pybind11::module::import("o3de.disable_gem"); m_editProjectProperties = pybind11::module::import("o3de.project_properties"); @@ -319,9 +320,6 @@ namespace O3DE::ProjectManager m_repo = pybind11::module::import("o3de.repo"); m_pathlib = pybind11::module::import("pathlib"); - // make sure the engine is registered - RegisterThisEngine(); - m_pythonStarted = !PyErr_Occurred(); return m_pythonStarted; } @@ -346,36 +344,6 @@ namespace O3DE::ProjectManager return !PyErr_Occurred(); } - bool PythonBindings::RegisterThisEngine() - { - bool registrationResult = true; // already registered is considered successful - bool pythonResult = ExecuteWithLock( - [&] - { - // check current engine path against all other registered engines - // to see if we are already registered - auto allEngines = m_manifest.attr("get_engines")(); - if (pybind11::isinstance(allEngines)) - { - for (auto engine : allEngines) - { - AZ::IO::FixedMaxPath enginePath(Py_To_String(engine)); - if (enginePath.Compare(m_enginePath) == 0) - { - return; - } - } - } - - auto result = m_register.attr("register")(QString_To_Py_Path(QString(m_enginePath.c_str()))); - registrationResult = (result.cast() == 0); - }); - - bool finalResult = (registrationResult && pythonResult); - AZ_Assert(finalResult, "Registration of this engine failed!"); - return finalResult; - } - AZ::Outcome PythonBindings::ExecuteWithLockErrorHandling(AZStd::function executionCallback) { if (!Py_IsInitialized()) @@ -407,16 +375,22 @@ namespace O3DE::ProjectManager return ExecuteWithLockErrorHandling(executionCallback).IsSuccess(); } - AZ::Outcome PythonBindings::GetEngineInfo() + EngineInfo PythonBindings::EngineInfoFromPath(pybind11::handle enginePath) { EngineInfo engineInfo; - bool result = ExecuteWithLock([&] { - auto enginePath = m_manifest.attr("get_this_engine_path")(); + try + { + auto engineData = m_manifest.attr("get_engine_json_data")(pybind11::none(), enginePath); + if (pybind11::isinstance(engineData)) + { + engineInfo.m_version = Py_To_String_Optional(engineData, "O3DEVersion", "0.0.0.0"); + engineInfo.m_name = Py_To_String_Optional(engineData, "engine_name", "O3DE"); + engineInfo.m_path = Py_To_String(enginePath); + } auto o3deData = m_manifest.attr("load_o3de_manifest")(); if (pybind11::isinstance(o3deData)) { - engineInfo.m_path = Py_To_String(enginePath); auto defaultGemsFolder = m_manifest.attr("get_o3de_gems_folder")(); engineInfo.m_defaultGemsFolder = Py_To_String_Optional(o3deData, "default_gems_folder", Py_To_String(defaultGemsFolder)); @@ -433,19 +407,59 @@ namespace O3DE::ProjectManager engineInfo.m_thirdPartyPath = Py_To_String_Optional(o3deData, "default_third_party_folder", Py_To_String(defaultThirdPartyFolder)); } - auto engineData = m_manifest.attr("get_engine_json_data")(pybind11::none(), enginePath); - if (pybind11::isinstance(engineData)) + // check if engine path is registered + auto allEngines = m_manifest.attr("get_engines")(); + if (pybind11::isinstance(allEngines)) { - try + const AZ::IO::FixedMaxPath enginePathFixed(Py_To_String(enginePath)); + for (auto engine : allEngines) { - engineInfo.m_version = Py_To_String_Optional(engineData, "O3DEVersion", "0.0.0.0"); - engineInfo.m_name = Py_To_String_Optional(engineData, "engine_name", "O3DE"); - } - catch ([[maybe_unused]] const std::exception& e) - { - AZ_Warning("PythonBindings", false, "Failed to get EngineInfo from %s", Py_To_String(enginePath)); + AZ::IO::FixedMaxPath otherEnginePath(Py_To_String(engine)); + if (otherEnginePath.Compare(enginePathFixed) == 0) + { + engineInfo.m_registered = true; + break; + } } } + } + catch ([[maybe_unused]] const std::exception& e) + { + AZ_Warning("PythonBindings", false, "Failed to get EngineInfo from %s", Py_To_String(enginePath)); + } + return engineInfo; + } + + AZ::Outcome PythonBindings::GetEngineInfo() + { + EngineInfo engineInfo; + + bool result = ExecuteWithLock([&] { + auto enginePath = m_manifest.attr("get_this_engine_path")(); + engineInfo = EngineInfoFromPath(enginePath); + }); + + if (!result || !engineInfo.IsValid()) + { + return AZ::Failure(); + } + else + { + return AZ::Success(AZStd::move(engineInfo)); + } + } + + AZ::Outcome PythonBindings::GetEngineInfo(const QString& engineName) + { + EngineInfo engineInfo; + bool result = ExecuteWithLock([&] { + auto enginePathResult = m_manifest.attr("get_registered")(QString_To_Py_String(engineName)); + + // if a valid registered object is not found None is returned + if (!pybind11::isinstance(enginePathResult)) + { + engineInfo = EngineInfoFromPath(enginePathResult); + } }); if (!result || !engineInfo.IsValid()) @@ -458,10 +472,32 @@ namespace O3DE::ProjectManager } } - bool PythonBindings::SetEngineInfo(const EngineInfo& engineInfo) + IPythonBindings::DetailedOutcome PythonBindings::SetEngineInfo(const EngineInfo& engineInfo, bool force) { - bool result = ExecuteWithLock([&] { - auto registrationResult = m_register.attr("register")( + bool registrationSuccess = false; + bool pythonSuccess = ExecuteWithLock([&] { + + EngineInfo currentEngine = EngineInfoFromPath(QString_To_Py_Path(engineInfo.m_path)); + + // be kind to source control and avoid needlessly updating engine.json + if (currentEngine.IsValid() && + (currentEngine.m_name.compare(engineInfo.m_name) != 0 || currentEngine.m_version.compare(engineInfo.m_version) != 0)) + { + auto enginePropsResult = m_engineProperties.attr("edit_engine_props")( + QString_To_Py_Path(engineInfo.m_path), + pybind11::none(), // existing engine_name + QString_To_Py_String(engineInfo.m_name), + QString_To_Py_String(engineInfo.m_version) + ); + + if (enginePropsResult.cast() != 0) + { + // do not proceed with registration + return; + } + } + + auto result = m_register.attr("register")( QString_To_Py_Path(engineInfo.m_path), pybind11::none(), // project_path pybind11::none(), // gem_path @@ -474,16 +510,22 @@ namespace O3DE::ProjectManager QString_To_Py_Path(engineInfo.m_defaultGemsFolder), QString_To_Py_Path(engineInfo.m_defaultTemplatesFolder), pybind11::none(), // default_restricted_folder - QString_To_Py_Path(engineInfo.m_thirdPartyPath) - ); + QString_To_Py_Path(engineInfo.m_thirdPartyPath), + pybind11::none(), // external_subdir_engine_path + pybind11::none(), // external_subdir_project_path + false, // remove + force + ); - if (registrationResult.cast() != 0) - { - result = false; - } + registrationSuccess = result.cast() == 0; }); - return result; + if (pythonSuccess && registrationSuccess) + { + return AZ::Success(); + } + + return AZ::Failure(GetErrorPair()); } AZ::Outcome PythonBindings::GetGemInfo(const QString& path, const QString& projectPath) @@ -1064,7 +1106,7 @@ namespace O3DE::ProjectManager return result && refreshResult; } - AZ::Outcome> PythonBindings::AddGemRepo(const QString& repoUri) + IPythonBindings::DetailedOutcome PythonBindings::AddGemRepo(const QString& repoUri) { bool registrationResult = false; bool result = ExecuteWithLock( @@ -1080,7 +1122,7 @@ namespace O3DE::ProjectManager if (!result || !registrationResult) { - return AZ::Failure>(GetSimpleDetailedErrorPair()); + return AZ::Failure(GetErrorPair()); } return AZ::Success(); @@ -1170,13 +1212,10 @@ namespace O3DE::ProjectManager return gemRepoInfo; } -//#define MOCK_GEM_REPO_INFO true - AZ::Outcome, AZStd::string> PythonBindings::GetAllGemRepoInfos() { QVector gemRepos; -#ifndef MOCK_GEM_REPO_INFO auto result = ExecuteWithLockErrorHandling( [&] { @@ -1189,18 +1228,6 @@ namespace O3DE::ProjectManager { return AZ::Failure(result.GetError().c_str()); } -#else - GemRepoInfo mockJohnRepo("JohnCreates", "John Smith", QDateTime(QDate(2021, 8, 31), QTime(11, 57)), true); - mockJohnRepo.m_summary = "John's Summary. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sollicitudin dapibus urna"; - mockJohnRepo.m_repoUri = "https://github.com/o3de/o3de"; - mockJohnRepo.m_additionalInfo = "John's additional info. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sollicitu."; - gemRepos.push_back(mockJohnRepo); - - GemRepoInfo mockJaneRepo("JanesGems", "Jane Doe", QDateTime(QDate(2021, 9, 10), QTime(18, 23)), false); - mockJaneRepo.m_summary = "Jane's Summary."; - mockJaneRepo.m_repoUri = "https://github.com/o3de/o3de.org"; - gemRepos.push_back(mockJaneRepo); -#endif // MOCK_GEM_REPO_INFO std::sort(gemRepos.begin(), gemRepos.end()); return AZ::Success(AZStd::move(gemRepos)); @@ -1261,7 +1288,7 @@ namespace O3DE::ProjectManager return AZ::Success(AZStd::move(gemInfos)); } - AZ::Outcome> PythonBindings::DownloadGem( + IPythonBindings::DetailedOutcome PythonBindings::DownloadGem( const QString& gemName, std::function gemProgressCallback, bool force) { // This process is currently limited to download a single gem at a time. @@ -1290,12 +1317,12 @@ namespace O3DE::ProjectManager if (!result.IsSuccess()) { - AZStd::pair pythonRunError(result.GetError(), result.GetError()); - return AZ::Failure>(AZStd::move(pythonRunError)); + IPythonBindings::ErrorPair pythonRunError(result.GetError(), result.GetError()); + return AZ::Failure(AZStd::move(pythonRunError)); } else if (!downloadSucceeded) { - return AZ::Failure>(GetSimpleDetailedErrorPair()); + return AZ::Failure(GetErrorPair()); } return AZ::Success(); @@ -1322,13 +1349,13 @@ namespace O3DE::ProjectManager return result && updateAvaliableResult; } - AZStd::pair PythonBindings::GetSimpleDetailedErrorPair() + IPythonBindings::ErrorPair PythonBindings::GetErrorPair() { AZStd::string detailedString = m_pythonErrorStrings.size() == 1 ? "" : AZStd::accumulate(m_pythonErrorStrings.begin(), m_pythonErrorStrings.end(), AZStd::string("")); - return AZStd::pair(m_pythonErrorStrings.front(), detailedString); + return IPythonBindings::ErrorPair(m_pythonErrorStrings.front(), detailedString); } void PythonBindings::AddErrorString(AZStd::string errorString) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h index 48841b6565..e2a8109128 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.h +++ b/Code/Tools/ProjectManager/Source/PythonBindings.h @@ -35,7 +35,8 @@ namespace O3DE::ProjectManager // Engine AZ::Outcome GetEngineInfo() override; - bool SetEngineInfo(const EngineInfo& engineInfo) override; + AZ::Outcome GetEngineInfo(const QString& engineName) override; + DetailedOutcome SetEngineInfo(const EngineInfo& engineInfo, bool force = false) override; // Gem AZ::Outcome GetGemInfo(const QString& path, const QString& projectPath = {}) override; @@ -62,12 +63,12 @@ namespace O3DE::ProjectManager // Gem Repos AZ::Outcome RefreshGemRepo(const QString& repoUri) override; bool RefreshAllGemRepos() override; - AZ::Outcome> AddGemRepo(const QString& repoUri) override; + DetailedOutcome AddGemRepo(const QString& repoUri) override; bool RemoveGemRepo(const QString& repoUri) override; AZ::Outcome, AZStd::string> GetAllGemRepoInfos() override; AZ::Outcome, AZStd::string> GetGemInfosForRepo(const QString& repoUri) override; AZ::Outcome, AZStd::string> GetGemInfosForAllRepos() override; - AZ::Outcome> DownloadGem( + DetailedOutcome DownloadGem( const QString& gemName, std::function gemProgressCallback, bool force = false) override; void CancelDownload() override; bool IsGemUpdateAvaliable(const QString& gemName, const QString& lastUpdated) override; @@ -80,14 +81,14 @@ namespace O3DE::ProjectManager AZ::Outcome ExecuteWithLockErrorHandling(AZStd::function executionCallback); bool ExecuteWithLock(AZStd::function executionCallback); + EngineInfo EngineInfoFromPath(pybind11::handle enginePath); GemInfo GemInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath); GemRepoInfo GetGemRepoInfo(pybind11::handle repoUri); ProjectInfo ProjectInfoFromPath(pybind11::handle path); ProjectTemplateInfo ProjectTemplateInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath); AZ::Outcome GemRegistration(const QString& gemPath, const QString& projectPath, bool remove = false); - bool RegisterThisEngine(); bool StopPython(); - AZStd::pair GetSimpleDetailedErrorPair(); + IPythonBindings::ErrorPair GetErrorPair(); bool m_pythonStarted = false; @@ -96,6 +97,7 @@ namespace O3DE::ProjectManager AZStd::recursive_mutex m_lock; pybind11::handle m_engineTemplate; + pybind11::handle m_engineProperties; pybind11::handle m_cmake; pybind11::handle m_register; pybind11::handle m_manifest; diff --git a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h index c7c8af2ce1..a42ff310c3 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h +++ b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h @@ -31,6 +31,10 @@ namespace O3DE::ProjectManager IPythonBindings() = default; virtual ~IPythonBindings() = default; + //! First string in pair is general error, second is detailed + using ErrorPair = AZStd::pair; + using DetailedOutcome = AZ::Outcome; + /** * Get whether Python was started or not. All Python functionality will fail if Python * failed to start. @@ -49,17 +53,25 @@ namespace O3DE::ProjectManager // Engine /** - * Get info about the engine + * Get info about the current engine * @return an outcome with EngineInfo on success */ virtual AZ::Outcome GetEngineInfo() = 0; /** - * Set info about the engine - * @param engineInfo an EngineInfo object + * Get info about an engine by name + * @param engineName The name of the engine to get info about + * @return an outcome with EngineInfo on success */ - virtual bool SetEngineInfo(const EngineInfo& engineInfo) = 0; + virtual AZ::Outcome GetEngineInfo(const QString& engineName) = 0; + /** + * Set info about the engine + * @param force True to force registration even if an engine with the same name is already registered + * @param engineInfo an EngineInfo object + * @return a detailed error outcome on failure. + */ + virtual DetailedOutcome SetEngineInfo(const EngineInfo& engineInfo, bool force = false) = 0; // Gems @@ -202,7 +214,7 @@ namespace O3DE::ProjectManager * @param repoUri the absolute filesystem path or url to the gem repo. * @return an outcome with a pair of string error and detailed messages on failure. */ - virtual AZ::Outcome> AddGemRepo(const QString& repoUri) = 0; + virtual DetailedOutcome AddGemRepo(const QString& repoUri) = 0; /** * Unregisters this gem repo with the current engine. @@ -237,7 +249,7 @@ namespace O3DE::ProjectManager * @param force should we forcibly overwrite the old version of the gem. * @return an outcome with a pair of string error and detailed messages on failure. */ - virtual AZ::Outcome> DownloadGem( + virtual DetailedOutcome DownloadGem( const QString& gemName, std::function gemProgressCallback, bool force = false) = 0; /** diff --git a/scripts/o3de/o3de/engine_properties.py b/scripts/o3de/o3de/engine_properties.py index 3ba30e4bf8..636e32704e 100644 --- a/scripts/o3de/o3de/engine_properties.py +++ b/scripts/o3de/o3de/engine_properties.py @@ -26,6 +26,11 @@ def edit_engine_props(engine_path: pathlib.Path = None, if not engine_path and not engine_name: logger.error(f'Either a engine path or a engine name must be supplied to lookup engine.json') return 1 + + if not new_name and not new_version: + logger.error('A new engine name or new version, or both must be supplied.') + return 1 + if not engine_path: engine_path = manifest.get_registered(engine_name=engine_name) diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index ab48915fe4..6c470a7c65 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -607,75 +607,90 @@ def get_registered(engine_name: str = None, engine_path = pathlib.Path(engine).resolve() engine_json = engine_path / 'engine.json' - with engine_json.open('r') as f: - try: - engine_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warning(f'{engine_json} failed to load: {str(e)}') - else: - this_engines_name = engine_json_data['engine_name'] - if this_engines_name == engine_name: - return engine_path + if not pathlib.Path(engine_json).is_file(): + logger.warning(f'{engine_json} does not exist') + else: + with engine_json.open('r') as f: + try: + engine_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warning(f'{engine_json} failed to load: {str(e)}') + else: + this_engines_name = engine_json_data['engine_name'] + if this_engines_name == engine_name: + return engine_path elif isinstance(project_name, str): projects = get_all_projects() for project_path in projects: project_path = pathlib.Path(project_path).resolve() project_json = project_path / 'project.json' - with project_json.open('r') as f: - try: - project_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warning(f'{project_json} failed to load: {str(e)}') - else: - this_projects_name = project_json_data['project_name'] - if this_projects_name == project_name: - return project_path + if not pathlib.Path(project_json).is_file(): + logger.warning(f'{project_json} does not exist') + else: + with project_json.open('r') as f: + try: + project_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warning(f'{project_json} failed to load: {str(e)}') + else: + this_projects_name = project_json_data['project_name'] + if this_projects_name == project_name: + return project_path elif isinstance(gem_name, str): gems = get_all_gems(project_path) for gem_path in gems: gem_path = pathlib.Path(gem_path).resolve() gem_json = gem_path / 'gem.json' - with gem_json.open('r') as f: - try: - gem_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warning(f'{gem_json} failed to load: {str(e)}') - else: - this_gems_name = gem_json_data['gem_name'] - if this_gems_name == gem_name: - return gem_path + if not pathlib.Path(gem_json).is_file(): + logger.warning(f'{gem_json} does not exist') + else: + with gem_json.open('r') as f: + try: + gem_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warning(f'{gem_json} failed to load: {str(e)}') + else: + this_gems_name = gem_json_data['gem_name'] + if this_gems_name == gem_name: + return gem_path elif isinstance(template_name, str): templates = get_all_templates(project_path) for template_path in templates: template_path = pathlib.Path(template_path).resolve() template_json = template_path / 'template.json' - with template_json.open('r') as f: - try: - template_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warning(f'{template_path} failed to load: {str(e)}') - else: - this_templates_name = template_json_data['template_name'] - if this_templates_name == template_name: - return template_path + if not pathlib.Path(template_json).is_file(): + logger.warning(f'{template_json} does not exist') + else: + with template_json.open('r') as f: + try: + template_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warning(f'{template_path} failed to load: {str(e)}') + else: + this_templates_name = template_json_data['template_name'] + if this_templates_name == template_name: + return template_path elif isinstance(restricted_name, str): restricted = get_all_restricted(project_path) for restricted_path in restricted: restricted_path = pathlib.Path(restricted_path).resolve() restricted_json = restricted_path / 'restricted.json' - with restricted_json.open('r') as f: - try: - restricted_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warning(f'{restricted_json} failed to load: {str(e)}') - else: - this_restricted_name = restricted_json_data['restricted_name'] - if this_restricted_name == restricted_name: - return restricted_path + if not pathlib.Path(restricted_json).is_file(): + logger.warning(f'{restricted_json} does not exist') + else: + with restricted_json.open('r') as f: + try: + restricted_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warning(f'{restricted_json} failed to load: {str(e)}') + else: + this_restricted_name = restricted_json_data['restricted_name'] + if this_restricted_name == restricted_name: + return restricted_path elif isinstance(default_folder, str): if default_folder == 'engines': From 7c96bc4f1f34dfde8b6bc597d8683cdf29b1bbcb Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue, 7 Dec 2021 13:00:47 -0600 Subject: [PATCH 127/128] =?UTF-8?q?Fix=20loaded=20procprefabs=20not=20goin?= =?UTF-8?q?g=20through=20the=20asset=20hint=20fixup=20process=E2=80=A6=20(?= =?UTF-8?q?#6077)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix loaded procprefabs not going through the asset hint fixup process for all versions of LoadInstanceFromPrefabDom. Fixes procprefab asset references not working when pressing Ctrl+G in the editor Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add unit test Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add missing include Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> --- .../Prefab/PrefabDomUtils.cpp | 52 ++--- .../Tests/Prefab/PrefabAssetFixupTests.cpp | 185 ++++++++++++++++++ .../Tests/aztoolsframeworktests_files.cmake | 2 +- 3 files changed, 214 insertions(+), 25 deletions(-) create mode 100644 Code/Framework/AzToolsFramework/Tests/Prefab/PrefabAssetFixupTests.cpp diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.cpp index a84d6bf706..83e8d2e4be 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.cpp @@ -150,6 +150,24 @@ namespace AzToolsFramework return result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success; } + // some assets may come in from the JSON serialzier with no AssetID, but have an asset hint + // this attempts to fix up the assets using the assetHint field + void FixUpInvalidAssets(AZ::Data::Asset& asset) + { + if (!asset.GetId().IsValid() && !asset.GetHint().empty()) + { + AZ::Data::AssetId assetId; + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + assetId, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, asset.GetHint().c_str(), + AZ::Data::s_invalidAssetType, false); + + if (assetId.IsValid()) + { + asset.Create(assetId, false); + } + } + } + bool LoadInstanceFromPrefabDom(Instance& instance, const PrefabDom& prefabDom, LoadFlags flags) { // When entities are rebuilt they are first destroyed. As a result any assets they were exclusively holding on to will @@ -164,13 +182,17 @@ namespace AzToolsFramework entityIdMapper.SetEntityIdGenerationApproach(InstanceEntityIdMapper::EntityIdGenerationApproach::Random); } + auto tracker = AZ::Data::SerializedAssetTracker{}; + tracker.SetAssetFixUp(&FixUpInvalidAssets); + AZ::JsonDeserializerSettings settings; // The InstanceEntityIdMapper is registered twice because it's used in several places during deserialization where one is // specific for the InstanceEntityIdMapper and once for the generic JsonEntityIdMapper. Because the Json Serializer's meta // data has strict typing and doesn't look for inheritance both have to be explicitly added so they're found both locations. settings.m_metadata.Add(static_cast(&entityIdMapper)); settings.m_metadata.Add(&entityIdMapper); - + settings.m_metadata.Add(tracker); + AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::Load(instance, prefabDom, settings); @@ -203,13 +225,16 @@ namespace AzToolsFramework entityIdMapper.SetEntityIdGenerationApproach(InstanceEntityIdMapper::EntityIdGenerationApproach::Random); } + auto tracker = AZ::Data::SerializedAssetTracker{}; + tracker.SetAssetFixUp(&FixUpInvalidAssets); + AZ::JsonDeserializerSettings settings; // The InstanceEntityIdMapper is registered twice because it's used in several places during deserialization where one is // specific for the InstanceEntityIdMapper and once for the generic JsonEntityIdMapper. Because the Json Serializer's meta // data has strict typing and doesn't look for inheritance both have to be explicitly added so they're found both locations. settings.m_metadata.Add(static_cast(&entityIdMapper)); settings.m_metadata.Add(&entityIdMapper); - settings.m_metadata.Create(); + settings.m_metadata.Add(tracker); AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::Load(instance, prefabDom, settings); @@ -246,29 +271,8 @@ namespace AzToolsFramework entityIdMapper.SetEntityIdGenerationApproach(InstanceEntityIdMapper::EntityIdGenerationApproach::Random); } - // some assets may come in from the JSON serialzier with no AssetID, but have an asset hint - // this attempts to fix up the assets using the assetHint field - auto fixUpInvalidAssets = [](AZ::Data::Asset& asset) - { - if (!asset.GetId().IsValid() && !asset.GetHint().empty()) - { - AZ::Data::AssetId assetId; - AZ::Data::AssetCatalogRequestBus::BroadcastResult( - assetId, - &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, - asset.GetHint().c_str(), - AZ::Data::s_invalidAssetType, - false); - - if (assetId.IsValid()) - { - asset.Create(assetId, false); - } - } - }; - auto tracker = AZ::Data::SerializedAssetTracker{}; - tracker.SetAssetFixUp(fixUpInvalidAssets); + tracker.SetAssetFixUp(&FixUpInvalidAssets); AZ::JsonDeserializerSettings settings; // The InstanceEntityIdMapper is registered twice because it's used in several places during deserialization where one is diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabAssetFixupTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabAssetFixupTests.cpp new file mode 100644 index 0000000000..379392553e --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabAssetFixupTests.cpp @@ -0,0 +1,185 @@ +/* + * 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 + +namespace UnitTest +{ + using PrefabInstantiateTest = PrefabTestFixture; + + struct MockAsset : AZ::Data::AssetData + { + AZ_RTTI(MockAsset, "{DAB98A3F-1714-4B95-AACB-8C150B0D0628}", AZ::Data::AssetData); + + AZ_CLASS_ALLOCATOR(MockAsset, AZ::SystemAllocator, 0); + + static void Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class()->Field("data", &MockAsset::m_data); + } + } + float m_data = 1.f; + }; + + struct MockAssetComponent : AZ::Component + { + AZ_COMPONENT(MockAssetComponent, "{D81B0D06-B495-479E-832A-A63079FD6D37}"); + + static void Reflect(AZ::ReflectContext* context) + { + MockAsset::Reflect(context); + + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Field("asset", &MockAssetComponent::m_asset); + } + } + + void Activate() override{} + void Deactivate() override{} + + AZ::Data::Asset m_asset; + }; + + class MockAssetHandler : public AZ::Data::AssetHandler + { + public: + AZ_CLASS_ALLOCATOR(MockAssetHandler, AZ::SystemAllocator, 0); + + AZ::Data::AssetPtr CreateAsset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override + { + (void)id; + EXPECT_TRUE(type == azrtti_typeid()); + if (type == azrtti_typeid()) + { + return aznew MockAsset(); + } + return nullptr; + } + + LoadResult LoadAssetData(const AZ::Data::Asset&, AZStd::shared_ptr, const AZ::Data::AssetFilterCB&) override + { + return LoadResult::Error; + } + + void DestroyAsset(AZ::Data::AssetPtr ptr) override + { + EXPECT_TRUE(ptr->GetType() == azrtti_typeid()); + delete ptr; + } + + void GetHandledAssetTypes(AZStd::vector& assetTypes) override + { + assetTypes.push_back(azrtti_typeid()); + } + }; + + struct PrefabFixupTest : PrefabInstantiateTest + { + void SetUpEditorFixtureImpl() override + { + PrefabInstantiateTest::SetUpEditorFixtureImpl(); + + AZ::SerializeContext* context = nullptr; + + AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationBus::Events::GetSerializeContext); + + ASSERT_NE(context, nullptr); + + MockAssetComponent::Reflect(context); + + AZ::Data::AssetManager::Instance().RegisterHandler(&m_handler, azrtti_typeid()); + + auto entity = aznew AZ::Entity(); + auto mockAssetComponent = entity->CreateComponent(); + + mockAssetComponent->m_asset = + AZ::Data::Asset(AZ::Uuid::CreateNull(), AZ::Data::AssetType::CreateNull(), "test.asset"); + + auto newInstance = AZ::Interface::Get()->CreatePrefab({ entity }, {}, "test.prefab"); + + AZStd::string prefabString; + ASSERT_TRUE(m_prefabLoaderInterface->SaveTemplateToString(newInstance->GetTemplateId(), prefabString)); + m_prefabSystemComponent->RemoveAllTemplates(); + + AZ::Outcome readPrefabFileResult = AZ::JsonSerializationUtils::ReadJsonString(prefabString); + + ASSERT_TRUE(readPrefabFileResult.IsSuccess()); + + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + m_assetId, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, "test.asset", azrtti_typeid(), + true); // True to register the asset and generate an AssetId for lookup + + m_prefabDom = readPrefabFileResult.TakeValue(); + } + + void TearDownEditorFixtureImpl() override + { + PrefabInstantiateTest::TearDownEditorFixtureImpl(); + + AZ::Data::AssetManager::Instance().UnregisterHandler(&m_handler); + } + + void CheckInstance(const Instance& instance) + { + const AZ::Entity* loadedEntity = nullptr; + instance.GetConstEntities( + [&loadedEntity](const AZ::Entity& entity) + { + loadedEntity = &entity; + + return false; + }); + + auto loadedComponent = loadedEntity->FindComponent(); + + ASSERT_NE(loadedComponent, nullptr); + + ASSERT_STREQ(loadedComponent->m_asset.GetHint().c_str(), "test.asset"); + ASSERT_EQ(loadedComponent->m_asset->GetId(), m_assetId); + } + + MockAssetHandler m_handler; + PrefabDom m_prefabDom; + AZ::Data::AssetId m_assetId; + }; + + TEST_F(PrefabFixupTest, Test_LoadInstanceFromPrefabDom_Overload1) + { + Instance instance; + ASSERT_TRUE(PrefabDomUtils::LoadInstanceFromPrefabDom(instance, m_prefabDom)); + + CheckInstance(instance); + } + + TEST_F(PrefabFixupTest, Test_LoadInstanceFromPrefabDom_Overload2) + { + Instance instance; + AZStd::vector> referencedAssets; + ASSERT_TRUE(PrefabDomUtils::LoadInstanceFromPrefabDom(instance, m_prefabDom, referencedAssets)); + + CheckInstance(instance); + } + + TEST_F(PrefabFixupTest, Test_LoadInstanceFromPrefabDom_Overload3) + { + Instance instance; + AZStd::vector> referencedAssets; + Instance::EntityList entityList; + (PrefabDomUtils::LoadInstanceFromPrefabDom(instance, entityList, m_prefabDom)); + + CheckInstance(instance); + } +} diff --git a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake index 1a8819b188..31c70c81a0 100644 --- a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake +++ b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake @@ -74,7 +74,7 @@ set(FILES Prefab/PrefabEntityAliasTests.cpp Prefab/PrefabInstanceToTemplatePropagatorTests.cpp Prefab/PrefabInstantiateTests.cpp - Prefab/PrefabInstantiateTests.cpp + Prefab/PrefabAssetFixupTests.cpp Prefab/PrefabLoadTemplateTests.cpp Prefab/PrefabTestComponent.cpp Prefab/PrefabTestComponent.h From 577280cc11209041a747ee8221944148561ff61d Mon Sep 17 00:00:00 2001 From: moudgils <47460854+moudgils@users.noreply.github.com> Date: Tue, 7 Dec 2021 11:45:55 -0800 Subject: [PATCH 128/128] Disable shaders for metal compilation until the issues are addressed properly (#6222) * Disabling shaders for metal compilation until the issue is fixed properly. Signed-off-by: moudgils <47460854+moudgils@users.noreply.github.com> * Adding a missed shader Signed-off-by: moudgils <47460854+moudgils@users.noreply.github.com> --- .../PostProcessing/DepthOfFieldWriteFocusDepthFromGpu.shader | 3 ++- Gems/AtomTressFX/Assets/Shaders/HairRenderingFillPPLL.shader | 3 ++- .../Assets/Shaders/HairShortCutGeometryDepthAlpha.shader | 3 ++- .../Assets/Shaders/Terrain/TerrainPBR_ForwardPass.shader | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/DepthOfFieldWriteFocusDepthFromGpu.shader b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/DepthOfFieldWriteFocusDepthFromGpu.shader index 92243acb87..5b927869d9 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/DepthOfFieldWriteFocusDepthFromGpu.shader +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/DepthOfFieldWriteFocusDepthFromGpu.shader @@ -10,6 +10,7 @@ "type" : "Compute" } ] - } + }, + "DisabledRHIBackends": ["metal"] } diff --git a/Gems/AtomTressFX/Assets/Shaders/HairRenderingFillPPLL.shader b/Gems/AtomTressFX/Assets/Shaders/HairRenderingFillPPLL.shader index e4859eca9b..fc4974fae2 100644 --- a/Gems/AtomTressFX/Assets/Shaders/HairRenderingFillPPLL.shader +++ b/Gems/AtomTressFX/Assets/Shaders/HairRenderingFillPPLL.shader @@ -39,5 +39,6 @@ "type": "Fragment" } ] - } + }, + "DisabledRHIBackends": ["metal"] } diff --git a/Gems/AtomTressFX/Assets/Shaders/HairShortCutGeometryDepthAlpha.shader b/Gems/AtomTressFX/Assets/Shaders/HairShortCutGeometryDepthAlpha.shader index 7cd1f44510..d2d34fb1cd 100644 --- a/Gems/AtomTressFX/Assets/Shaders/HairShortCutGeometryDepthAlpha.shader +++ b/Gems/AtomTressFX/Assets/Shaders/HairShortCutGeometryDepthAlpha.shader @@ -41,5 +41,6 @@ "type": "Fragment" } ] - } + }, + "DisabledRHIBackends": ["metal"] } diff --git a/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.shader b/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.shader index 66072567ec..0f7455f957 100644 --- a/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.shader +++ b/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.shader @@ -44,5 +44,6 @@ ] }, - "DrawList" : "forward" + "DrawList" : "forward", + "DisabledRHIBackends": ["metal"] }