Integrating up through commit 90f050496

This commit is contained in:
alexpete
2021-04-07 14:03:29 -07:00
parent 8f2ed080a9
commit c2cbd430fe
2694 changed files with 285622 additions and 176874 deletions
@@ -43,7 +43,6 @@ namespace ScriptCanvasEditor
virtual AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasAsset> LoadAsset(AZStd::string_view graphPath) = 0;
virtual AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasFunctionAsset> LoadFunctionAsset(AZStd::string_view graphPath) = 0;
virtual AZ::Outcome<ScriptCanvas::Translation::LuaAssetResult, AZStd::string> CreateLuaAsset(const AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasAsset>& editAsset, AZStd::string_view graphPathForRawLuaFile) = 0;
virtual AZ::Outcome<ScriptCanvas::Translation::LuaAssetResult, AZStd::string> CreateLuaFunctionAsset(const AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasFunctionAsset>& editAsset, AZStd::string_view graphPathForRawLuaFile) = 0;
virtual AZ::Outcome<AZ::Data::Asset<ScriptCanvas::RuntimeAsset>, AZStd::string> CreateRuntimeAsset(const AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasAsset>& editAsset) = 0;
virtual AZ::Outcome<AZ::Data::Asset<ScriptCanvas::SubgraphInterfaceAsset>, AZStd::string> CreateFunctionRuntimeAsset(const AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasFunctionAsset>& editAsset) = 0;
};
@@ -83,7 +83,7 @@ namespace ScriptCanvasEditor
{
m_editorAssetRegistry.Register<ScriptCanvasAsset, ScriptCanvasAssetHandler, ScriptCanvasAssetDescription>();
m_editorAssetRegistry.Register<ScriptCanvasEditor::ScriptCanvasFunctionAsset, ScriptCanvasFunctionAssetHandler, ScriptCanvasEditor::ScriptCanvasFunctionDescription>();
m_editorAssetRegistry.Register<ScriptCanvas::SubgraphInterfaceAsset, ScriptCanvas::SubgraphInterfaceAssetHandler, ScriptCanvas::RuntimeFunctionAssetDescription>();
m_editorAssetRegistry.Register<ScriptCanvas::SubgraphInterfaceAsset, ScriptCanvas::SubgraphInterfaceAssetHandler, ScriptCanvas::SubgraphInterfaceAssetDescription>();
AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect();
EditorAssetConversionBus::Handler::BusConnect();
@@ -165,11 +165,6 @@ namespace ScriptCanvasEditor
return ScriptCanvasBuilder::CreateLuaAsset(editAsset->GetScriptCanvasEntity(), editAsset->GetId(), graphPathForRawLuaFile);
}
AZ::Outcome<ScriptCanvas::Translation::LuaAssetResult, AZStd::string> EditorAssetSystemComponent::CreateLuaFunctionAsset(const AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasFunctionAsset>& editAsset, AZStd::string_view graphPathForRawLuaFile)
{
return ScriptCanvasBuilder::CreateLuaAsset(editAsset->GetScriptCanvasEntity(), editAsset->GetId(), graphPathForRawLuaFile);
}
void EditorAssetSystemComponent::AddSourceFileOpeners([[maybe_unused]] const char* fullSourceFileName, const AZ::Uuid& sourceUuid, AzToolsFramework::AssetBrowser::SourceFileOpenerList& openers)
{
using namespace AzToolsFramework;
@@ -66,7 +66,6 @@ namespace ScriptCanvasEditor
AZ::Outcome<AZ::Data::Asset<ScriptCanvas::RuntimeAsset>, AZStd::string> CreateRuntimeAsset(const AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasAsset>& editAsset) override;
AZ::Outcome<AZ::Data::Asset<ScriptCanvas::SubgraphInterfaceAsset>, AZStd::string> CreateFunctionRuntimeAsset(const AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasFunctionAsset>& editAsset) override;
AZ::Outcome<ScriptCanvas::Translation::LuaAssetResult, AZStd::string> CreateLuaAsset(const AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasAsset>& editAsset, AZStd::string_view graphPathForRawLuaFile) override;
AZ::Outcome<ScriptCanvas::Translation::LuaAssetResult, AZStd::string> CreateLuaFunctionAsset(const AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasFunctionAsset>& editAsset, AZStd::string_view graphPathForRawLuaFile) override;
//////////////////////////////////////////////////////////////////////////
// ScriptCanvas::Grammar::RequestBus::Handler...
@@ -59,7 +59,7 @@ namespace ScriptCanvas
void RuntimeAssetSystemComponent::Activate()
{
m_runtimeAssetRegistry.Register<ScriptCanvas::RuntimeAsset, ScriptCanvas::RuntimeAssetHandler, ScriptCanvas::RuntimeAssetDescription>();
m_runtimeAssetRegistry.Register<ScriptCanvas::SubgraphInterfaceAsset, ScriptCanvas::SubgraphInterfaceAssetHandler, ScriptCanvas::RuntimeFunctionAssetDescription>();
m_runtimeAssetRegistry.Register<ScriptCanvas::SubgraphInterfaceAsset, ScriptCanvas::SubgraphInterfaceAssetHandler, ScriptCanvas::SubgraphInterfaceAssetDescription>();
}
void RuntimeAssetSystemComponent::Deactivate()
@@ -100,8 +100,9 @@ namespace ScriptCanvasBuilder
// or the fingerprint of the individual job is different.
size_t fingerprint = ScriptCanvas::BehaviorContextUtils::GenerateFingerprintForBehaviorContext();
builderDescriptor.m_analysisFingerprint = AZStd::string(m_scriptCanvasBuilder.GetFingerprintString())
.append(AZStd::string::format("|%zu", fingerprint));
.append(AZStd::string::format("|%lu", static_cast<uint64_t>(fingerprint)));
builderDescriptor.AddFlags(AssetBuilderSDK::AssetBuilderDesc::BF_DeleteLastKnownGoodProductOnFailure, s_scriptCanvasProcessJobKey);
builderDescriptor.m_productsToKeepOnFailure[s_scriptCanvasProcessJobKey] = { AZ_CRC("SubgraphInterface", 0xdfe6dc72) };
m_scriptCanvasBuilder.BusConnect(builderDescriptor.m_busId);
AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBus::Handler::RegisterBuilderInformation, builderDescriptor);
@@ -123,6 +124,7 @@ namespace ScriptCanvasBuilder
// or the fingerprint of the individual job is different.
builderDescriptor.m_analysisFingerprint = m_scriptCanvasFunctionBuilder.GetFingerprintString();
builderDescriptor.AddFlags(AssetBuilderSDK::AssetBuilderDesc::BF_DeleteLastKnownGoodProductOnFailure, s_scriptCanvasProcessJobKey);
builderDescriptor.m_productsToKeepOnFailure[s_scriptCanvasProcessJobKey] = { AZ_CRC("SubgraphInterface", 0xdfe6dc72) };
AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBus::Handler::RegisterBuilderInformation, builderDescriptor);
ScriptCanvas::Grammar::RequestBus::Handler::BusConnect();
AzToolsFramework::ToolsAssetSystemBus::Broadcast(&AzToolsFramework::ToolsAssetSystemRequests::RegisterSourceAssetType, azrtti_typeid<ScriptCanvasEditor::ScriptCanvasFunctionAsset>(), ScriptCanvasEditor::ScriptCanvasFunctionAsset::Description::GetFileFilter<ScriptCanvasEditor::ScriptCanvasFunctionAsset>());
@@ -86,41 +86,31 @@ namespace ScriptCanvasBuilder
assetDataStream->Open(AZStd::move(fileBuffer));
}
m_sourceDependencies.clear();
AZStd::unordered_multimap<AZStd::string, AssetBuilderSDK::SourceFileDependency> sourceFileDependencies;
m_processEditorAssetDependencies.clear();
auto assetFilter = [&response](const AZ::Data::AssetFilterInfo& filterInfo)
auto assetFilter = [this, &response](const AZ::Data::AssetFilterInfo& filterInfo)
{
if (filterInfo.m_assetType == azrtti_typeid<ScriptCanvasEditor::ScriptCanvasAsset>() ||
filterInfo.m_assetType == azrtti_typeid<ScriptCanvasEditor::ScriptCanvasFunctionAsset>() ||
filterInfo.m_assetType == azrtti_typeid<ScriptEvents::ScriptEventsAsset>() ||
filterInfo.m_assetType == azrtti_typeid<ScriptCanvas::SubgraphInterfaceAsset>()) // this required, since nodes reference this, rather than the editor asset
// force load these before processing
if (filterInfo.m_assetType == azrtti_typeid<ScriptCanvas::SubgraphInterfaceAsset>()
|| filterInfo.m_assetType == azrtti_typeid<ScriptEvents::ScriptEventsAsset>())
{
this->m_processEditorAssetDependencies.push_back(filterInfo);
}
// these trigger re-processing
if (filterInfo.m_assetType == azrtti_typeid<ScriptCanvasEditor::ScriptCanvasAsset>()
|| filterInfo.m_assetType == azrtti_typeid<ScriptEvents::ScriptEventsAsset>()
|| filterInfo.m_assetType == azrtti_typeid<ScriptCanvas::SubgraphInterfaceAsset>())
{
AssetBuilderSDK::SourceFileDependency dependency;
dependency.m_sourceFileDependencyUUID = filterInfo.m_assetId.m_guid;
response.m_sourceFileDependencyList.push_back(dependency);
/*AssetBuilderSDK::SourceFileDependency dependency;
dependency.m_sourceFileDependencyUUID = asset.GetId().m_guid;
if (asset.GetType() == azrtti_typeid<ScriptEvents::ScriptEventsAsset>())
{
sourceFileDependencies.emplace("Script Events", dependency);
}
else
{
sourceFileDependencies.emplace(s_scriptCanvasProcessJobKey, dependency);
}
this->m_sourceDependencies.push_back(asset);*/
}
// Asset filter always returns false to prevent parsing dependencies, but makes note of the script canvas dependencies
return false;
};
AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasAsset> asset;
asset.Create(AZ::Data::AssetId(AZ::Uuid::CreateRandom()));
if (m_editorAssetHandler->LoadAssetDataFromStream(asset, assetDataStream, assetFilter) != AZ::Data::AssetHandler::LoadResult::LoadComplete)
@@ -135,9 +125,20 @@ namespace ScriptCanvasBuilder
auto* scriptCanvasEntity = asset.Get()->GetScriptCanvasEntity();
auto* sourceGraph = AZ::EntityUtils::FindFirstDerivedComponent<ScriptCanvasEditor::Graph>(scriptCanvasEntity);
AZ_Assert(sourceGraph, "Graph component is missing from entity.");
struct EntityIdComparer
{
bool operator()(AZ::Entity* lhs, AZ::Entity* rhs)
{
AZ::EntityId lhsEntityId = lhs != nullptr ? lhs->GetId() : AZ::EntityId();
AZ::EntityId rhsEntityId = rhs != nullptr ? rhs->GetId() : AZ::EntityId();
return lhsEntityId < rhsEntityId;
}
};
const AZStd::set<AZ::Entity*, EntityIdComparer> sortedEntities(sourceGraph->GetGraphData()->m_nodes.begin(), sourceGraph->GetGraphData()->m_nodes.end());
size_t fingerprint = 0;
const AZStd::set<AZ::Entity*> sortedEntities(sourceGraph->GetGraphData()->m_nodes.begin(), sourceGraph->GetGraphData()->m_nodes.end());
for (auto& nodeEntity : sortedEntities)
for (const auto& nodeEntity : sortedEntities)
{
if (auto nodeComponent = AZ::EntityUtils::FindFirstDerivedComponent<ScriptCanvas::Node>(nodeEntity))
{
@@ -145,6 +146,8 @@ namespace ScriptCanvasBuilder
}
}
m_processEditorAssetDependencies.clear();
for (const AssetBuilderSDK::PlatformInfo& info : request.m_enabledPlatforms)
{
if (info.HasTag("tools"))
@@ -164,11 +167,13 @@ namespace ScriptCanvasBuilder
jobDescriptor.m_jobKey = s_scriptCanvasProcessJobKey;
jobDescriptor.SetPlatformIdentifier(info.m_identifier.c_str());
jobDescriptor.m_additionalFingerprintInfo = AZStd::string(GetFingerprintString()).append("|").append(AZStd::to_string(static_cast<AZ::u64>(fingerprint)));
// Graph process job needs to wait until its dependency asset job finished
for (const auto& sourceDependency : sourceFileDependencies)
for (const auto& processingDependency : response.m_sourceFileDependencyList)
{
jobDescriptor.m_jobDependencyList.emplace_back(sourceDependency.first, info.m_identifier.c_str(), AssetBuilderSDK::JobDependencyType::Order, sourceDependency.second);
jobDescriptor.m_jobDependencyList.emplace_back(s_scriptCanvasProcessJobKey, info.m_identifier.c_str(), AssetBuilderSDK::JobDependencyType::Order, processingDependency);
}
response.m_createJobOutputs.push_back(jobDescriptor);
}
@@ -260,7 +265,6 @@ namespace ScriptCanvasBuilder
assetDataStream->Open(AZStd::move(fileBuffer));
}
AZ::SerializeContext* context{};
AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
@@ -288,15 +292,16 @@ namespace ScriptCanvasBuilder
jobProduct.m_productAssetType = azrtti_typeid<ScriptCanvasEditor::ScriptCanvasAsset>();
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
{
// force load all dependencies into memory
for (auto& dependency : m_sourceDependencies)
for (auto& dependency : m_processEditorAssetDependencies)
{
auto depAsset = AZ::Data::AssetManager::Instance().GetAsset(dependency.GetId(), dependency.GetType(), AZ::Data::AssetLoadBehavior::PreLoad);
auto depAsset = AZ::Data::AssetManager::Instance().GetAsset(dependency.m_assetId, dependency.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad);
depAsset.BlockUntilLoadComplete();
}
@@ -320,7 +325,23 @@ namespace ScriptCanvasBuilder
auto saveOutcome = SaveRuntimeAsset(input, input.runtimeDataOut);
if (saveOutcome.IsSuccess())
{
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
// save function interface
AzFramework::StringFunc::Path::StripExtension(fileNameOnly);
ScriptCanvas::SubgraphInterfaceData functionInterface;
functionInterface.m_name = fileNameOnly;
functionInterface.m_interface = AZStd::move(input.interfaceOut);
input.assetHandler = m_subgraphInterfaceHandler;
AzFramework::StringFunc::Path::ReplaceExtension(input.runtimeScriptCanvasOutputPath, ScriptCanvas::SubgraphInterfaceAsset::GetFileExtension());
auto saveInterfaceOutcome = SaveSubgraphInterface(input, functionInterface);
if (saveInterfaceOutcome.IsSuccess())
{
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
}
else
{
AZ_Error(s_scriptCanvasBuilder, false, saveInterfaceOutcome.GetError().data());
}
}
else
{
@@ -56,6 +56,9 @@ namespace ScriptCanvasBuilder
ChangeScriptRequirementToAsset,
RemoveDebugVariablesFromRelease,
FailJobsOnMissingLKG,
QuantumLeap,
DependencyArguments,
DependencyRequirementsData,
// add new entries above
Current,
};
@@ -172,7 +175,7 @@ namespace ScriptCanvasBuilder
AZ::Data::AssetHandler* m_runtimeAssetHandler = nullptr;
AZ::Data::AssetHandler* m_subgraphInterfaceHandler = nullptr;
mutable AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>> m_sourceDependencies;
mutable AZStd::vector<AZ::Data::AssetFilterInfo> m_processEditorAssetDependencies;
// cached on first time query
mutable AZStd::string m_fingerprintString;
};
@@ -80,8 +80,8 @@ namespace ScriptCanvasBuilder
request.assetId = scriptAssetId;
request.graph = sourceGraph;
request.name = fileNameOnly;
request.rawSaveDebugOutput = ScriptCanvas::Grammar::s_saveRawTranslationOuputToFile;
request.printModelToConsole = ScriptCanvas::Grammar::s_printAbstractCodeModel;
request.rawSaveDebugOutput = ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile;
request.printModelToConsole = ScriptCanvas::Grammar::g_printAbstractCodeModel;
request.path = fullPath;
bool pathFound = false;
@@ -129,7 +129,7 @@ namespace ScriptCanvasBuilder
result.m_scriptAsset = asset;
result.m_runtimeInputs = AZStd::move(translation.m_runtimeInputs);
result.m_debugMap = AZStd::move(translation.m_debugMap);
result.m_dependencies = translationResult.m_model->GetDependencies();
result.m_dependencies = translationResult.m_model->GetOrderedDependencies();
result.m_parseDuration = translationResult.m_parseDuration;
result.m_translationDuration = translation.m_duration;
return AZ::Success(result);
@@ -547,8 +547,8 @@ namespace ScriptCanvasBuilder
request.namespacePath = input.namespacePath;
request.assetId = input.assetID;
request.graph = sourceGraph;
request.rawSaveDebugOutput = ScriptCanvas::Grammar::s_saveRawTranslationOuputToFile;
request.printModelToConsole = ScriptCanvas::Grammar::s_printAbstractCodeModel;
request.rawSaveDebugOutput = ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile;
request.printModelToConsole = ScriptCanvas::Grammar::g_printAbstractCodeModel;
ScriptCanvas::Translation::Result translationResult = TranslateToLua(request);
auto outcome = translationResult.IsSuccess(ScriptCanvas::Translation::TargetFlags::Lua);
@@ -592,9 +592,10 @@ namespace ScriptCanvasBuilder
const AZ::Data::Asset<AZ::ScriptAsset> scriptAsset(scriptAssetId, jobProduct.m_productAssetType, {});
input.runtimeDataOut.m_script = scriptAsset;
const ScriptCanvas::DependencyReport& dependencyReport = translationResult.m_model->GetDependencies();
const ScriptCanvas::OrderedDependencies& orderedDependencies = translationResult.m_model->GetOrderedDependencies();
const ScriptCanvas::DependencyReport& dependencyReport = orderedDependencies.source;
for (const auto& subgraphAssetID : dependencyReport.userSubgraphAssetIds)
for (const auto& subgraphAssetID : orderedDependencies.orderedAssetIds)
{
const AZ::Data::AssetId dependentSubgraphAssetID(subgraphAssetID.m_guid, AZ_CRC("RuntimeData", 0x163310ae));
const AZ::Data::Asset<ScriptCanvas::RuntimeAsset> subgraphAsset(dependentSubgraphAssetID, azrtti_typeid<ScriptCanvas::RuntimeAsset>(), {});
@@ -13,7 +13,6 @@
#include "precompiled.h"
#include "platform.h"
#include <Asset/AssetDescription.h>
#include <Asset/Functions/ScriptCanvasFunctionAsset.h>
#include <AssetBuilderSDK/SerializationDependencies.h>
@@ -22,9 +21,10 @@
#include <AzCore/IO/IOUtils.h>
#include <AzCore/Math/Uuid.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/string/conversions.h>
#include <AzFramework/Script/ScriptComponent.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <Builder/ScriptCanvasBuilderWorker.h>
#include <ScriptCanvas/Asset/Functions/RuntimeFunctionAssetHandler.h>
#include <ScriptCanvas/Asset/RuntimeAssetHandler.h>
#include <ScriptCanvas/Assets/Functions/ScriptCanvasFunctionAssetHandler.h>
@@ -37,8 +37,6 @@
#include <ScriptCanvas/Results/ErrorText.h>
#include <ScriptCanvas/Utils/BehaviorContextUtils.h>
#include <Builder/ScriptCanvasBuilderWorker.h>
namespace ScriptCanvasBuilder
{
void FunctionWorker::Activate(const AssetHandlers& handlers)
@@ -124,6 +122,8 @@ namespace ScriptCanvasBuilder
AZStd::hash_combine(fingerprint, nodeComponent->GenerateFingerprint());
}
}
#if defined(FUNCTION_LEGACY_SUPPORT_ENABLED)
for (const AssetBuilderSDK::PlatformInfo& info : request.m_enabledPlatforms)
{
if (info.HasTag("tools"))
@@ -135,15 +135,14 @@ namespace ScriptCanvasBuilder
copyDescriptor.SetPlatformIdentifier(info.m_identifier.c_str());
copyDescriptor.m_additionalFingerprintInfo = AZStd::string(GetFingerprintString()).append("|").append(AZStd::to_string(static_cast<AZ::u64>(fingerprint)));
response.m_createJobOutputs.push_back(copyDescriptor);
}
}
AssetBuilderSDK::JobDescriptor jobDescriptor;
jobDescriptor.m_priority = 2;
jobDescriptor.m_critical = true;
jobDescriptor.m_jobKey = s_scriptCanvasProcessJobKey;
jobDescriptor.SetPlatformIdentifier(info.m_identifier.c_str());
jobDescriptor.m_additionalFingerprintInfo = AZStd::string(GetFingerprintString())
.append(AZStd::string::format("|%zu", fingerprint));
jobDescriptor.m_additionalFingerprintInfo = AZStd::string(GetFingerprintString()).append("|").append(AZStd::to_string(static_cast<AZ::u64>(fingerprint)));
// Function process job needs to wait until its dependency asset job finished
for (const auto& sourceDependency : response.m_sourceFileDependencyList)
{
@@ -152,6 +151,7 @@ namespace ScriptCanvasBuilder
}
response.m_createJobOutputs.push_back(jobDescriptor);
}
#endif
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
AZ_TracePrintf(s_scriptCanvasBuilder, "Finish Creating Job");
@@ -303,7 +303,6 @@ namespace ScriptCanvasBuilder
ScriptCanvas::SubgraphInterfaceData functionInterface;
functionInterface.m_name = fileNameOnly;
functionInterface.m_version = sourceDataComponent->m_functionDataComponentVersion;
functionInterface.m_interface = AZStd::move(input.interfaceOut);
// save function interface
+2 -2
View File
@@ -77,8 +77,8 @@ ly_add_target(
AZ::AzFramework
Gem::ScriptCanvasDebugger
AUTOGEN_RULES
*.ScriptCanvasNode.xml,ScriptCanvasNode_Header.jinja,$path/$fileprefix.generated.h
*.ScriptCanvasNode.xml,ScriptCanvasNode_Source.jinja,$path/$fileprefix.generated.cpp
*.ScriptCanvasGrammar.xml,ScriptCanvasGrammar_Header.jinja,$path/$fileprefix.generated.h
*.ScriptCanvasGrammar.xml,ScriptCanvasGrammar_Source.jinja,$path/$fileprefix.generated.cpp
*.ScriptCanvasNodeable.xml,ScriptCanvasNodeable_Header.jinja,$path/$fileprefix.generated.h
*.ScriptCanvasNodeable.xml,ScriptCanvasNodeable_Source.jinja,$path/$fileprefix.generated.cpp
)
@@ -711,7 +711,7 @@ namespace ScriptCanvasEditor
AZStd::string tempFilename;
AzFramework::StringFunc::Path::GetFullFileName(targetFilename.data(), tempFilename);
AZStd::string tempPath = AZStd::string::format("@cache@/scriptcanvas/%s.temp", tempFilename.data());
AZStd::string tempPath = AZStd::string::format("@usercache@/scriptcanvas/%s.temp", tempFilename.data());
AZStd::array<char, AZ::IO::MaxPathLength> resolvedPath{};
AZ::IO::FileIOBase::GetInstance()->ResolvePath(tempPath.data(), resolvedPath.data(), resolvedPath.size());
@@ -584,6 +584,74 @@ namespace ScriptCanvasEditor
return true;
}
void Graph::HandleFunctionDefinitionExtension(ScriptCanvas::Node* node, GraphCanvas::SlotId graphCanvasSlotId, const GraphCanvas::NodeId& nodeId)
{
// Special-case for the execution nodeling extensions, which are adding input/output data slots.
// We want to automatically promote them to variables so that the user can refer to them more easily
auto functionDefintionNode = azrtti_cast<ScriptCanvas::Nodes::Core::FunctionDefinitionNode*>(node);
if (functionDefintionNode && graphCanvasSlotId.IsValid())
{
GraphCanvas::Endpoint endpoint;
GraphCanvas::SlotRequestBus::EventResult(endpoint, graphCanvasSlotId, &GraphCanvas::SlotRequests::GetEndpoint);
const ScriptCanvas::Endpoint scEndpoint = ConvertToScriptCanvasEndpoint(endpoint);
if (scEndpoint.IsValid())
{
ScriptCanvas::Slot* slot = FindSlot(scEndpoint);
if (slot)
{
AZ::Vector2 position;
GraphCanvas::GeometryRequestBus::EventResult(position, nodeId, &GraphCanvas::GeometryRequests::GetPosition);
// First we need to automatically display the ShowSlotTypeSelector dialog so the user
// can assign a type and name to the slot they are adding
VariablePaletteRequests::SlotSetup selectedSlotSetup;
bool createSlot = false;
QPoint scenePoint(aznumeric_cast<int>(position.GetX()), aznumeric_cast<int>(position.GetY()));
VariablePaletteRequestBus::BroadcastResult(createSlot, &VariablePaletteRequests::ShowSlotTypeSelector, slot, scenePoint, selectedSlotSetup);
if (createSlot && !selectedSlotSetup.m_type.IsNull())
{
if (slot)
{
auto displayType = ScriptCanvas::Data::FromAZType(selectedSlotSetup.m_type);
if (displayType.IsValid())
{
slot->SetDisplayType(displayType);
}
if (!selectedSlotSetup.m_name.empty())
{
slot->Rename(selectedSlotSetup.m_name);
}
}
// Now that the slot has a valid type/name, we can actually promote it to a variable
if (PromoteToVariableAction(endpoint) /*&& slot->IsVariableReference()*/)
{
ScriptCanvas::GraphVariable* variable = slot->GetVariable();
if (variable)
{
// functions 2.0 set variable scope to function
auto connectionType = slot->GetConnectionType();
if (variable->GetScope() != ScriptCanvas::VariableFlags::Scope::Function)
{
variable->SetScope(ScriptCanvas::VariableFlags::Scope::Function);
}
}
}
}
else
{
RemoveSlot(endpoint);
}
}
}
}
}
AZ::Outcome<ScriptCanvas::Node*> Graph::ReplaceNodeByConfig(ScriptCanvas::Node* oldNode, const ScriptCanvas::NodeConfiguration& nodeConfig,
ScriptCanvas::ReplacementConnectionMap& remapConnections)
{
@@ -917,17 +985,6 @@ namespace ScriptCanvasEditor
if (remapVariableOutcome)
{
node->SetSlotVariableId(slot.GetId(), remapVariableOutcome.GetValue());
ScriptCanvas::GraphVariable* variable2 = nullptr;
ScriptCanvas::GraphVariableManagerRequestBus::EventResult(variable2, GetScriptCanvasId(), &ScriptCanvas::GraphVariableManagerRequests::FindVariableById, remapVariableOutcome.GetValue());
if (variable2)
{
if (IsRuntimeGraph())
{
variable2->RemoveScope(ScriptCanvas::VariableFlags::Scope::Output);
}
}
}
else
{
@@ -979,7 +1036,10 @@ namespace ScriptCanvasEditor
ScriptCanvas::Endpoint scTargetEndpoint = connection->GetTargetEndpoint();
GraphCanvas::Endpoint targetEndpoint = ConvertToGraphCanvasEndpoint(scTargetEndpoint);
ScriptCanvas::GraphNotificationBus::Event(GetScriptCanvasId(), &ScriptCanvas::GraphNotifications::OnDisonnectionComplete, connectionId);
DisconnectById(scConnectionId);
}
}
@@ -1003,6 +1063,12 @@ namespace ScriptCanvasEditor
scConnected = ConfigureConnectionUserData(scSourceEndpoint, scTargetEndpoint, connectionId);
}
if (scConnected)
{
ScriptCanvas::GraphNotificationBus::Event(GetScriptCanvasId(), &ScriptCanvas::GraphNotifications::OnConnectionComplete, connectionId);
}
return scConnected;
}
@@ -1777,38 +1843,21 @@ namespace ScriptCanvasEditor
if (isExecutionNodeling)
{
if (!IsFunctionGraph())
{
invalidNodes.insert(nodeId);
}
else
{
AZStd::any* userData = nullptr;
GraphCanvas::NodeRequestBus::EventResult(userData, nodeId, &GraphCanvas::NodeRequests::GetUserData);
AZ::EntityId scSourceNodeId = (userData && userData->is<AZ::EntityId>()) ? *AZStd::any_cast<AZ::EntityId>(userData) : AZ::EntityId();
AZStd::any* userData = nullptr;
GraphCanvas::NodeRequestBus::EventResult(userData, nodeId, &GraphCanvas::NodeRequests::GetUserData);
AZ::EntityId scSourceNodeId = (userData && userData->is<AZ::EntityId>()) ? *AZStd::any_cast<AZ::EntityId>(userData) : AZ::EntityId();
ScriptCanvas::Nodes::Core::FunctionDefinitionNode* nodeling = azrtti_cast<ScriptCanvas::Nodes::Core::FunctionDefinitionNode*>(FindNode(scSourceNodeId));
if (nodeling)
{
nodeling->RemapId();
}
if (nodeling)
{
nodeling->RemapId();
}
}
// Going to disallow all functions nodes inside of functions nodes until we sort out a dependency checking situation to avoid recursion.
bool isFunctionNode = false;
NodeDescriptorRequestBus::EventResult(isFunctionNode, nodeId, &NodeDescriptorRequests::IsType, NodeDescriptorType::FunctionNode);
if (isFunctionNode)
{
if (IsFunctionGraph())
{
invalidNodes.insert(nodeId);
}
}
// Show all hidden slots on a paste, as a temporary fix until I can sort out what I want this to work like.
GraphCanvas::NodeRequestBus::Event(nodeId, &GraphCanvas::NodeRequests::ShowAllSlots);
@@ -2021,6 +2070,21 @@ namespace ScriptCanvasEditor
{
ScriptCanvas::Endpoint scEndpoint = ConvertToScriptCanvasEndpoint(endpoint);
ScriptCanvas::Slot* slot = FindSlot(scEndpoint);
if (slot)
{
ScriptCanvas::GraphVariable* variable = slot->GetVariable();
if (variable && variable->GetScope() == ScriptCanvas::VariableFlags::Scope::Function)
{
bool success = false;
ScriptCanvas::GraphVariableManagerRequestBus::EventResult(success, GetScriptCanvasId(), &ScriptCanvas::GraphVariableManagerRequests::RemoveVariable, variable->GetVariableId());
if (!success)
{
AZ_Assert(success, "Failed to remove variable that corresponds to this slot");
}
}
}
ScriptCanvas::Node* canvasNode = FindNode(scEndpoint.GetNodeId());
if (canvasNode)
@@ -2198,36 +2262,18 @@ namespace ScriptCanvasEditor
AZStd::string inBoxText = "";
while (!nameAvailable)
// Special case to try re-using the slot name if this is on an execution nodeling, since the user had just
// given it a name already with the ShowSlotTypeSelector dialog
if (azrtti_istypeof<ScriptCanvas::Nodes::Core::FunctionDefinitionNode>(activeNode))
{
bool accepted = false;
QString name = QInputDialog::getText(mainWindow, "Variable Name", inBoxText.c_str(), QLineEdit::Normal, defaultName.c_str(), &accepted);
if (!accepted)
{
break;
}
if (!name.isEmpty())
{
variableName = name.toUtf8().data();
ScriptCanvas::GraphVariableManagerRequestBus::EventResult(nameAvailable, GetScriptCanvasId(), &ScriptCanvas::GraphVariableManagerRequests::IsNameAvailable, variableName);
if (!nameAvailable)
{
inBoxText = AZStd::string::format("\"%s\" is already in use.", variableName.c_str());
}
}
else
{
inBoxText = "Variable names cannot be empty.";
}
variableName = activeSlot->GetName();
ScriptCanvas::GraphVariableManagerRequestBus::EventResult(nameAvailable, GetScriptCanvasId(), &ScriptCanvas::GraphVariableManagerRequests::IsNameAvailable, variableName);
}
if (!nameAvailable)
while (!nameAvailable)
{
ReleaseVariableCounter(variableCounter);
return false;
variableName.append(" (duplicate)");
ScriptCanvas::GraphVariableManagerRequestBus::EventResult(nameAvailable, GetScriptCanvasId(), &ScriptCanvas::GraphVariableManagerRequests::IsNameAvailable, variableName);
}
ScriptCanvas::Datum variableDatum;
@@ -2250,16 +2296,15 @@ namespace ScriptCanvasEditor
AZ::Outcome<ScriptCanvas::VariableId, AZStd::string> addOutcome;
// #functions2 slot<->variable re-use the activeDatum, send the pointer (actually, all of the source slot information, and make a special conversion)
ScriptCanvas::GraphVariableManagerRequestBus::EventResult(addOutcome, GetScriptCanvasId(), &ScriptCanvas::GraphVariableManagerRequests::AddVariable, variableName, variableDatum);
if (addOutcome.IsSuccess())
{
GraphCanvas::DataSlotRequestBus::Event(endpoint.GetSlotId(), &GraphCanvas::DataSlotRequests::ConvertToReference);
if (activeSlot->IsVariableReference())
{
activeSlot->SetVariableReference(addOutcome.GetValue());
}
activeSlot->SetVariableReference(addOutcome.GetValue());
}
return addOutcome.IsSuccess();
@@ -2348,7 +2393,7 @@ namespace ScriptCanvasEditor
return false;
}
GraphCanvas::SlotId Graph::RequestExtension(const GraphCanvas::NodeId& nodeId, const GraphCanvas::ExtenderId& extenderId)
GraphCanvas::SlotId Graph::RequestExtension(const GraphCanvas::NodeId& nodeId, const GraphCanvas::ExtenderId& extenderId, GraphModelRequests::ExtensionRequestReason reason)
{
GraphCanvas::SlotId graphCanvasSlotId;
@@ -2363,8 +2408,20 @@ namespace ScriptCanvasEditor
ScriptCanvas::Node* canvasNode = AZ::EntityUtils::FindFirstDerivedComponent<ScriptCanvas::Node>(graphNodeEntity);
if (canvasNode)
{
ScriptCanvas::SlotId slotId = canvasNode->HandleExtension(extenderId);
SlotMappingRequestBus::EventResult(graphCanvasSlotId, nodeId, &SlotMappingRequests::MapToGraphCanvasId, slotId);
auto functionDefintionNode = azrtti_cast<ScriptCanvas::Nodes::Core::FunctionDefinitionNode*>(canvasNode);
if (functionDefintionNode && reason == GraphModelRequests::ExtensionRequestReason::ConnectionProposal)
{
}
else
{
ScriptCanvas::SlotId slotId = canvasNode->HandleExtension(extenderId);
if (slotId.IsValid())
{
SlotMappingRequestBus::EventResult(graphCanvasSlotId, nodeId, &SlotMappingRequests::MapToGraphCanvasId, slotId);
HandleFunctionDefinitionExtension(canvasNode, graphCanvasSlotId, nodeId);
}
}
}
}
@@ -3126,7 +3183,7 @@ namespace ScriptCanvasEditor
bool Graph::CanExposeEndpoint(const GraphCanvas::Endpoint& endpoint)
{
bool isEnabled = IsFunctionGraph();
bool isEnabled = false;
GraphCanvas::SlotType slotType;
GraphCanvas::SlotRequestBus::EventResult(slotType, endpoint.GetSlotId(), &GraphCanvas::SlotRequests::GetSlotType);
@@ -3171,6 +3228,10 @@ namespace ScriptCanvasEditor
isEnabled = false;
}
}
else
{
isEnabled = true;
}
bool isNodeling = false;
NodeDescriptorRequestBus::EventResult(isNodeling, endpoint.GetNodeId(), &NodeDescriptorRequests::IsType, NodeDescriptorType::FunctionDefinitionNode);
@@ -217,11 +217,6 @@ namespace ScriptCanvasEditor
ScriptCanvasMemoryAsset::pointer memoryAsset;
AssetTrackerRequestBus::BroadcastResult(memoryAsset, &AssetTrackerRequests::GetAsset, fileAssetId);
if (!memoryAsset)
{
AZ_Error("Script Canvas", false, AZStd::string::format("Could not find Script Canvas asset: %s", m_scriptCanvasAssetHolder.GetAssetHint().data()).c_str());
}
if (memoryAsset && memoryAsset->GetAsset().GetStatus() == AZ::Data::AssetData::AssetStatus::Ready)
{
OnScriptCanvasAssetReady(memoryAsset);
@@ -292,6 +287,7 @@ namespace ScriptCanvasEditor
}
*/
// #functions2 dependency-ctor-args make recursive
auto executionComponent = gameEntity->CreateComponent<ScriptCanvas::RuntimeComponent>(runtimeAsset);
ScriptCanvas::VariableData varData;
@@ -484,8 +480,8 @@ namespace ScriptCanvasEditor
/*! Start Variable Block Implementation */
void EditorScriptCanvasComponent::AddVariable(AZStd::string_view varName, const ScriptCanvas::GraphVariable& graphVariable)
{
bool exposeVariableToComponent = graphVariable.IsInScope(ScriptCanvas::VariableFlags::Scope::Input);
if (!exposeVariableToComponent)
// We only add component properties to the component
if (!graphVariable.IsComponentProperty())
{
return;
}
@@ -533,7 +529,7 @@ namespace ScriptCanvasEditor
const auto& variableId = varConfig.m_graphVariable.GetVariableId();
auto graphVariable = graphVarData.FindVariable(variableId);
if (!graphVariable || !graphVariable->IsInScope(ScriptCanvas::VariableFlags::Scope::Input))
if (!graphVariable->IsComponentProperty())
{
oldVariableIds.push_back(variableId);
}
@@ -79,7 +79,7 @@ namespace ScriptCanvasEditor
}
else if (auto functionTreeItem = azrtti_cast<const FunctionPaletteTreeItem*>(treeItem))
{
resultHash = ScriptCanvas::NodeUtils::ConstructFunctionNodeIdentifier(functionTreeItem->GetRuntimeAssetId());
resultHash = ScriptCanvas::NodeUtils::ConstructFunctionNodeIdentifier(functionTreeItem->GetAssetId());
}
return resultHash;
@@ -523,13 +523,13 @@ namespace ScriptCanvasEditor
ScriptCanvas::ValidationResults validationResults;
// Disable the s_saveRawTranslationOuputToFile CVar during Parse (not needed for upgrade) and restore to its set value after
bool saveRawTranslationOuputToFile = ScriptCanvas::Grammar::s_saveRawTranslationOuputToFile;
ScriptCanvas::Grammar::s_saveRawTranslationOuputToFile = false;
// Disable the g_saveRawTranslationOuputToFile CVar during Parse (not needed for upgrade) and restore to its set value after
bool saveRawTranslationOuputToFile = ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile;
ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false;
graph->Parse(validationResults);
ScriptCanvas::Grammar::s_saveRawTranslationOuputToFile = saveRawTranslationOuputToFile;
ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = saveRawTranslationOuputToFile;
if (validationResults.HasResults())
{
@@ -27,8 +27,6 @@ namespace ScriptCanvasEditor
using LoadedInterpretedDependencies = AZStd::vector<AZStd::pair<AZStd::string, ScriptCanvas::Translation::LuaAssetResult>>;
AZ_INLINE LoadedInterpretedDependencies LoadInterpretedDepencies(const ScriptCanvas::DependencySet& dependencySet);
AZ_INLINE LoadTestFunctionResult LoadTestFunction(AZStd::string_view path);
AZ_INLINE LoadTestGraphResult LoadTestGraph(AZStd::string_view path);
struct RunSpec
@@ -58,12 +58,12 @@ namespace ScriptCanvasEditor
originalPath.resize(originalPath.size() - AZStd::string_view(Grammar::k_internalRuntimeSuffix).size());
}
AZStd::string path = AZStd::string::format("%s/%s.scriptcanvas_fn", k_unitTestDirPathRelative, originalPath.data());
LoadTestFunctionResult loadResult = LoadTestFunction(path);
AZ_Assert(loadResult.m_runtimeAsset, "failed to load function asset");
AZStd::string path = AZStd::string::format("%s/%s.scriptcanvas", k_unitTestDirPathRelative, originalPath.data());
LoadTestGraphResult loadResult = LoadTestGraph(path);
AZ_Assert(loadResult.m_runtimeAsset, "failed to load dependent asset");
AZ::Outcome<ScriptCanvas::Translation::LuaAssetResult, AZStd::string> luaAssetOutcome = AZ::Failure(AZStd::string("lua asset creation for function failed"));
ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(luaAssetOutcome, &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateLuaFunctionAsset, loadResult.m_editorAsset, loadResult.m_graphPath);
ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(luaAssetOutcome, &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateLuaAsset, loadResult.m_editorAsset, loadResult.m_graphPath);
AZ_Assert(luaAssetOutcome.IsSuccess(), "failed to create Lua asset");
AZStd::string modulePath = namespacePath[0].data();
@@ -97,29 +97,6 @@ namespace ScriptCanvasEditor
return spec;
}
AZ_INLINE LoadTestFunctionResult LoadTestFunction(AZStd::string_view path)
{
AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasFunctionAsset> editorAsset;
ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(editorAsset, &ScriptCanvasEditor::EditorAssetConversionBusTraits::LoadFunctionAsset, path);
if (editorAsset.GetData())
{
AZ::Outcome< AZ::Data::Asset<ScriptCanvas::SubgraphInterfaceAsset>, AZStd::string> assetOutcome = AZ::Failure(AZStd::string("asset creation failed"));
ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(assetOutcome, &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateFunctionRuntimeAsset, editorAsset);
if (assetOutcome.IsSuccess())
{
LoadTestFunctionResult result;
result.m_graphPath = path;
result.m_editorAsset = editorAsset;
result.m_runtimeAsset = assetOutcome.GetValue();
result.m_entity = AZStd::make_unique<AZ::Entity>("Loaded Graph");
return result;
}
}
return {};
}
AZ_INLINE LoadTestGraphResult LoadTestGraph(AZStd::string_view graphPath)
{
AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasAsset> editorAsset;
@@ -230,7 +207,7 @@ namespace ScriptCanvasEditor
if (!reporter.IsProcessOnly())
{
dependencies = LoadInterpretedDepencies(luaAssetResult.m_dependencies.userSubgraphs);
dependencies = LoadInterpretedDepencies(luaAssetResult.m_dependencies.source.userSubgraphs);
if (!dependencies.empty())
{
@@ -260,7 +237,7 @@ namespace ScriptCanvasEditor
dependencyData.m_input = depencyAssetResult.m_runtimeInputs;
dependencyData.m_debugMap = depencyAssetResult.m_debugMap;
dependencyData.m_script = depencyAssetResult.m_scriptAsset;
Execution::Context::IntializeAssetData(dependencyData);
Execution::Context::InitializeActivationData(dependencyData);
Execution::InitializeInterpretedStatics(dependencyData);
}
}
@@ -270,7 +247,7 @@ namespace ScriptCanvasEditor
loadResult.m_runtimeAsset.Get()->GetData().m_input = luaAssetResult.m_runtimeInputs;
loadResult.m_runtimeAsset.Get()->GetData().m_debugMap = luaAssetResult.m_debugMap;
loadResult.m_runtimeComponent = loadResult.m_entity->CreateComponent<ScriptCanvas::RuntimeComponent>(loadResult.m_runtimeAsset);
Execution::Context::IntializeAssetData(loadResult.m_runtimeAsset->GetData());
Execution::Context::InitializeActivationData(loadResult.m_runtimeAsset->GetData());
Execution::InitializeInterpretedStatics(loadResult.m_runtimeAsset->GetData());
}
else
@@ -1,4 +1,4 @@
/*
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
@@ -1,4 +1,4 @@
/*
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
@@ -57,8 +57,8 @@ namespace ScriptCanvasEditor
if (requestInterface)
{
AZStd::vector< const ScriptCanvas::Slot* > scriptSlots;
ScriptCanvas::NodeRequestBus::EventResult(scriptSlots, GetScriptCanvasNodeId(), &ScriptCanvas::NodeRequests::GetAllSlots);
AZStd::vector<ScriptCanvas::Slot*> scriptSlots;
ScriptCanvas::NodeRequestBus::EventResult(scriptSlots, GetScriptCanvasNodeId(), &ScriptCanvas::NodeRequests::ModAllSlots);
for (int i = 0; i < scriptSlots.size(); ++i)
{
@@ -110,7 +110,7 @@ namespace ScriptCanvasEditor
////
protected:
void OnAddedToGraphCanvasGraph(const GraphCanvas::GraphId& graphId, const AZ::EntityId& scriptCanvasNodeId);
void OnAddedToGraphCanvasGraph(const GraphCanvas::GraphId& graphId, const AZ::EntityId& scriptCanvasNodeId) override;
private:
@@ -0,0 +1,102 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "FunctionDefinitionNodeDescriptorComponent.h"
#include <QInputDialog>
#include <QMainWindow>
#include <GraphCanvas/Components/Nodes/NodeTitleBus.h>
#include <ScriptCanvas/Bus/ScriptCanvasBus.h>
#include <ScriptCanvas/Core/NodelingBus.h>
#include <ScriptCanvas/Bus/RequestBus.h>
namespace ScriptCanvasEditor
{
FunctionDefinitionNodeDescriptorComponent::FunctionDefinitionNodeDescriptorComponent()
: NodelingDescriptorComponent(NodeDescriptorType::FunctionDefinitionNode)
{
}
void FunctionDefinitionNodeDescriptorComponent::Activate()
{
NodelingDescriptorComponent::Activate();
GraphCanvas::VisualNotificationBus::Handler::BusConnect(GetEntityId());
}
void FunctionDefinitionNodeDescriptorComponent::Deactivate()
{
NodelingDescriptorComponent::Deactivate();
GraphCanvas::VisualNotificationBus::Handler::BusDisconnect();
}
void FunctionDefinitionNodeDescriptorComponent::Reflect(AZ::ReflectContext* reflectContext)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflectContext))
{
serializeContext->Class<FunctionDefinitionNodeDescriptorComponent, NodelingDescriptorComponent>()
->Version(1)
;
}
}
bool FunctionDefinitionNodeDescriptorComponent::RenameDialog(FunctionDefinitionNodeDescriptorComponent* descriptor)
{
if (!descriptor)
{
return false;
}
AZStd::string inBoxText{};
AZStd::string defaultName{};
GraphCanvas::NodeId nodeId = descriptor->GetEntityId();
GraphCanvas::NodeTitleRequestBus::EventResult(defaultName, nodeId, &GraphCanvas::NodeTitleRequests::GetTitle);
QMainWindow* editorWindow = nullptr;
UIRequestBus::BroadcastResult(editorWindow, &UIRequests::GetMainWindow);
bool accepted = false;
QString name = QInputDialog::getText(qobject_cast<QWidget*>(editorWindow->parent()), "Name", inBoxText.c_str(), QLineEdit::Normal, defaultName.c_str(), &accepted);
const AZStd::string newName = name.toUtf8().data();
if (!name.isEmpty() && newName.compare(defaultName) != 0)
{
GraphCanvas::NodeTitleRequestBus::Event(nodeId, &GraphCanvas::NodeTitleRequests::SetTitle, newName);
AZ::EntityId graphCanvasGraphId;
GraphCanvas::SceneMemberRequestBus::EventResult(graphCanvasGraphId, descriptor->GetEntityId(), &GraphCanvas::SceneMemberRequests::GetScene);
ScriptCanvas::ScriptCanvasId scriptCanvasId;
GeneralRequestBus::BroadcastResult(scriptCanvasId, &GeneralRequests::GetScriptCanvasId, graphCanvasGraphId);
ScriptCanvas::GraphScopedNodeId scopedNodeId = ScriptCanvas::GraphScopedNodeId(scriptCanvasId, descriptor->FindScriptCanvasNodeId());
ScriptCanvas::NodelingRequestBus::Event(scopedNodeId, &ScriptCanvas::NodelingRequests::SetDisplayName, newName);
return true;
}
return false;
}
bool FunctionDefinitionNodeDescriptorComponent::OnMouseDoubleClick(const QGraphicsSceneMouseEvent*)
{
return RenameDialog(this);
}
}
@@ -0,0 +1,47 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include "NodelingDescriptorComponent.h"
#include <Editor/GraphCanvas/Components/NodeDescriptors/NodeDescriptorComponent.h>
#include <ScriptCanvas/Core/NodelingBus.h>
#include <ScriptCanvas/Core/GraphBus.h>
#include <GraphCanvas/Components/VisualBus.h>
namespace ScriptCanvasEditor
{
class FunctionDefinitionNodeDescriptorComponent
: public NodelingDescriptorComponent
, GraphCanvas::VisualNotificationBus::Handler
{
public:
AZ_COMPONENT(FunctionDefinitionNodeDescriptorComponent, "{F433EC33-D8A7-40E0-97E7-B29C3C68323E}", NodelingDescriptorComponent);
static void Reflect(AZ::ReflectContext* reflectContext);
FunctionDefinitionNodeDescriptorComponent();
~FunctionDefinitionNodeDescriptorComponent() override = default;
static bool RenameDialog(FunctionDefinitionNodeDescriptorComponent* descriptor);
protected:
void Activate() override;
void Deactivate() override;
// GraphCanvas::VisualNotificationBus::Handler...
bool OnMouseDoubleClick(const QGraphicsSceneMouseEvent*) override;
/////
};
}
@@ -26,7 +26,7 @@
#include <ScriptCanvas/Bus/RequestBus.h>
#include <ScriptCanvas/Libraries/Core/ScriptEventBase.h>
#include <ScriptCanvas/Libraries/Core/FunctionNode.h>
#include <ScriptCanvas/Libraries/Core/FunctionCallNode.h>
namespace ScriptCanvasEditor
{
@@ -51,7 +51,7 @@ namespace ScriptCanvasEditor
void OnVersionConversionEnd() override;
////
// GraphCanvas::NodeNotificationBus
// GraphCanvas::VisualNotificationBus
bool OnMouseDoubleClick(const QGraphicsSceneMouseEvent*) override;
//
@@ -44,6 +44,7 @@ namespace ScriptCanvasEditor
// NodeDescriptorBus::Handler
NodeDescriptorType GetType() const override { return m_nodeDescriptorType; }
NodeDescriptorComponent* GetDescriptorComponent() override { return this; }
////
// GraphCanvas::NodeNotificationBus
@@ -11,11 +11,13 @@
*/
#include "precompiled.h"
#include <GraphCanvas/Components/Nodes/NodeTitleBus.h>
#include "NodelingDescriptorComponent.h"
#include "ScriptCanvas/Bus/EditorScriptCanvasBus.h"
#include "ScriptCanvas/GraphCanvas/MappingBus.h"
#include <GraphCanvas/Components/Nodes/NodeTitleBus.h>
#include <ScriptCanvas/Bus/RequestBus.h>
#include <ScriptCanvas/Core/Slot.h>
#include <ScriptCanvas/Libraries/Core/Nodeling.h>
namespace ScriptCanvasEditor
{
@@ -35,11 +37,18 @@ namespace ScriptCanvasEditor
}
}
NodelingDescriptorComponent::NodelingDescriptorComponent()
: NodeDescriptorComponent(NodeDescriptorType::FunctionDefinitionNode)
NodelingDescriptorComponent::NodelingDescriptorComponent(NodeDescriptorType descriptorType)
: NodeDescriptorComponent(descriptorType)
{
}
void NodelingDescriptorComponent::Deactivate()
{
NodeDescriptorComponent::Deactivate();
ScriptCanvas::GraphNotificationBus::Handler::BusDisconnect();
}
void NodelingDescriptorComponent::OnNameChanged(const AZStd::string& displayName)
{
GraphCanvas::NodeTitleRequestBus::Event(GetEntityId(), &GraphCanvas::NodeTitleRequests::SetTitle, displayName);
@@ -56,7 +65,180 @@ namespace ScriptCanvasEditor
AZStd::string displayName;
ScriptCanvas::NodelingRequestBus::EventResult(displayName, scopedNodeId, &ScriptCanvas::NodelingRequests::GetDisplayName);
OnNameChanged(displayName);
ScriptCanvas::GraphNotificationBus::Handler::BusConnect(scriptCanvasId);
}
ScriptCanvas::Slot* NodelingDescriptorComponent::GetSlotFromNodeling(const AZ::EntityId& connectionId)
{
GraphCanvas::Endpoint sourceEndpoint;
GraphCanvas::ConnectionRequestBus::EventResult(sourceEndpoint, connectionId, &GraphCanvas::ConnectionRequests::GetSourceEndpoint);
GraphCanvas::Endpoint targetEndpoint;
GraphCanvas::ConnectionRequestBus::EventResult(targetEndpoint, connectionId, &GraphCanvas::ConnectionRequests::GetTargetEndpoint);
ScriptCanvas::ScriptCanvasId scriptCanvasId;
AZ::EntityId scriptCanvasNodeId = FindScriptCanvasNodeId();
ScriptCanvas::NodeRequestBus::EventResult(scriptCanvasId, scriptCanvasNodeId, &ScriptCanvas::NodeRequests::GetOwningScriptCanvasId);
AZStd::vector<GraphCanvas::Endpoint> endpoints = { sourceEndpoint, targetEndpoint };
for (auto& endpoint : endpoints)
{
ScriptCanvas::Endpoint scEndpoint;
EditorGraphRequestBus::EventResult(scEndpoint, scriptCanvasId, &EditorGraphRequests::ConvertToScriptCanvasEndpoint, endpoint);
ScriptCanvas::Slot* slot = nullptr;
ScriptCanvas::NodeRequestBus::EventResult(slot, scEndpoint.GetNodeId(), &ScriptCanvas::NodeRequests::GetSlot, scEndpoint.GetSlotId());
if (slot)
{
if (azrtti_istypeof<ScriptCanvas::Nodes::Core::Internal::Nodeling>(slot->GetNode()))
{
return slot;
}
}
}
return nullptr;
}
void NodelingDescriptorComponent::OnConnectionComplete(const AZ::EntityId& connectionId)
{
AZStd::vector< AZ::EntityId > graphCanvasSlotIds;
GraphCanvas::NodeRequestBus::EventResult(graphCanvasSlotIds, GetEntityId(), &GraphCanvas::NodeRequests::GetSlotIds);
ScriptCanvas::Slot* slot = GetSlotFromNodeling(connectionId);
if (slot)
{
const auto& descriptor = slot->GetDescriptor();
if (descriptor.IsExecution())
{
AZStd::vector<ScriptCanvas::Slot*> scriptSlots;
ScriptCanvas::NodeRequestBus::EventResult(scriptSlots, slot->GetNodeId(), &ScriptCanvas::NodeRequests::ModAllSlots);
if (descriptor.IsInput())
{
// Hide the output slot
for (ScriptCanvas::Slot* s : scriptSlots)
{
if (s->IsExecution() && s->IsOutput())
{
// Need the GC slot Id
AZ::EntityId graphCanvasGraphId;
ScriptCanvasEditor::SlotMappingRequestBus::EventResult(graphCanvasGraphId, s->GetNodeId(), &ScriptCanvasEditor::SlotMappingRequests::MapToGraphCanvasId, s->GetId());
if (graphCanvasGraphId.IsValid())
{
m_removedSlotId = graphCanvasGraphId;
//m_removedSlot = *s; // copy the slot?
GraphCanvas::NodeRequestBus::Event(GetEntityId(), &GraphCanvas::NodeRequests::RemoveSlot, graphCanvasGraphId);
}
s->SetVisible(false);
}
}
}
else
{
// Hide the input slot
for (ScriptCanvas::Slot* s : scriptSlots)
{
if (s->IsExecution() && s->IsInput())
{
AZ::EntityId graphCanvasGraphId;
ScriptCanvasEditor::SlotMappingRequestBus::EventResult(graphCanvasGraphId, s->GetNodeId(), &ScriptCanvasEditor::SlotMappingRequests::MapToGraphCanvasId, s->GetId());
if (graphCanvasGraphId.IsValid())
{
GraphCanvas::NodeRequestBus::Event(GetEntityId(), &GraphCanvas::NodeRequests::RemoveSlot, graphCanvasGraphId);
}
s->SetVisible(false);
}
}
}
}
}
}
void NodelingDescriptorComponent::OnDisonnectionComplete(const AZ::EntityId& connectionId)
{
ScriptCanvas::Slot* slot = GetSlotFromNodeling(connectionId);
if (slot)
{
const auto& descriptor = slot->GetDescriptor();
if (descriptor.IsExecution())
{
AZStd::vector<ScriptCanvas::Slot*> scriptSlots;
ScriptCanvas::NodeRequestBus::EventResult(scriptSlots, slot->GetNodeId(), &ScriptCanvas::NodeRequests::ModAllSlots);
if (descriptor.IsInput())
{
// Hide the output slot
for (ScriptCanvas::Slot* s : scriptSlots)
{
if (s->IsExecution() && s->IsOutput())
{
AZ::EntityId graphCanvasGraphId;
ScriptCanvasEditor::SlotMappingRequestBus::EventResult(graphCanvasGraphId, s->GetNodeId(), &ScriptCanvasEditor::SlotMappingRequests::MapToGraphCanvasId, s->GetId());
if (graphCanvasGraphId.IsValid())
{
GraphCanvas::NodeRequestBus::Event(GetEntityId(), &GraphCanvas::NodeRequests::AddSlot, m_removedSlotId);
}
s->SetVisible(true);
}
}
}
else
{
// Hide the input slot
for (ScriptCanvas::Slot* s : scriptSlots)
{
if (s->IsExecution() && s->IsInput())
{
AZ::EntityId graphCanvasGraphId;
ScriptCanvasEditor::SlotMappingRequestBus::EventResult(graphCanvasGraphId, s->GetNodeId(), &ScriptCanvasEditor::SlotMappingRequests::MapToGraphCanvasId, s->GetId());
if (graphCanvasGraphId.IsValid())
{
GraphCanvas::NodeRequestBus::Event(GetEntityId(), &GraphCanvas::NodeRequests::AddSlot, graphCanvasGraphId);
}
s->SetVisible(true);
}
}
}
}
}
}
void NodelingDescriptorComponent::OnPreConnectionRemoved(const AZ::EntityId& connectionId)
{
ScriptCanvas::Slot* slot = GetSlotFromNodeling(connectionId);
if (slot)
{
const auto& descriptor = slot->GetDescriptor();
if (descriptor.IsExecution())
{
AZStd::vector<ScriptCanvas::Slot*> scriptSlots;
ScriptCanvas::NodeRequestBus::EventResult(scriptSlots, slot->GetNodeId(), &ScriptCanvas::NodeRequests::ModAllSlots);
// Show all the slots
for (ScriptCanvas::Slot* s : scriptSlots)
{
s->SetVisible(true);
}
}
}
}
}
@@ -16,25 +16,41 @@
#include <Editor/GraphCanvas/Components/NodeDescriptors/NodeDescriptorComponent.h>
#include <ScriptCanvas/Core/NodelingBus.h>
#include <ScriptCanvas/Core/GraphBus.h>
namespace ScriptCanvasEditor
{
class NodelingDescriptorComponent
: public NodeDescriptorComponent
, public ScriptCanvas::NodelingNotificationBus::Handler
, private ScriptCanvas::GraphNotificationBus::Handler
{
public:
AZ_COMPONENT(NodelingDescriptorComponent, "{9EFA1DA5-2CCB-4A6D-AA84-BD121C75773A}", NodeDescriptorComponent);
static void Reflect(AZ::ReflectContext* reflectContext);
NodelingDescriptorComponent();
~NodelingDescriptorComponent() = default;
NodelingDescriptorComponent(NodeDescriptorType descriptorType = NodeDescriptorType::FunctionDefinitionNode);
~NodelingDescriptorComponent() override = default;
void Deactivate() override;
// NodelingNotificationBus
void OnNameChanged(const AZStd::string& newName) override;
////
// GraphCanvas::GraphNotificationBus
void OnConnectionComplete(const AZ::EntityId& connectionId) override;
void OnDisonnectionComplete(const AZ::EntityId& connectionId) override;
void OnPreConnectionRemoved(const AZ::EntityId& connectionId) override;
////
protected:
void OnAddedToGraphCanvasGraph(const GraphCanvas::GraphId& graphId, const AZ::EntityId& scriptCanvasNodeId) override;
ScriptCanvas::Slot* GetSlotFromNodeling(const AZ::EntityId& connectionId);
AZ::Entity* m_slotEntity;
ScriptCanvas::Slot* m_removedSlot;
AZ::EntityId m_removedSlotId;
};
}
@@ -193,17 +193,6 @@ namespace ScriptCanvasEditor
if (remapVariableOutcome)
{
SetVariableId(remapVariableOutcome.GetValue());
bool runtimeGraph = false;
EditorGraphRequestBus::EventResult(runtimeGraph, scriptCanvasId2, &EditorGraphRequests::IsRuntimeGraph);
ScriptCanvas::GraphVariable* variable = nullptr;
ScriptCanvas::GraphVariableManagerRequestBus::EventResult(variable, scriptCanvasId2, &ScriptCanvas::GraphVariableManagerRequests::FindVariableById, remapVariableOutcome.GetValue());
if (variable)
{
variable->RemoveScope(ScriptCanvas::VariableFlags::Scope::Output);
}
}
}
}
@@ -31,6 +31,8 @@ class QPushButton;
class QTableView;
class QToolButton;
namespace ScriptCanvas { class Slot; }
namespace GraphCanvas
{
struct Endpoint;
@@ -83,7 +85,6 @@ namespace ScriptCanvasEditor
virtual void OnChangeActiveGraphTab(AZ::Data::AssetId) {}
virtual void CreateNewFunctionAsset() = 0;
virtual void CreateNewRuntimeAsset() = 0;
virtual ScriptCanvas::ScriptCanvasId GetActiveScriptCanvasId() const
@@ -195,6 +196,14 @@ namespace ScriptCanvasEditor
virtual void RegisterVariableType(const ScriptCanvas::Data::Type& variabletype) = 0;
virtual bool IsValidVariableType(const ScriptCanvas::Data::Type& variableType) const = 0;
struct SlotSetup
{
AZStd::string m_name;
AZ::Uuid m_type = AZ::Uuid::CreateNull();
};
virtual bool ShowSlotTypeSelector(ScriptCanvas::Slot* slot, const QPoint& scenePosition, SlotSetup&) = 0;
};
using VariablePaletteRequestBus = AZ::EBus<VariablePaletteRequests>;
@@ -196,7 +196,7 @@ namespace ScriptCanvasEditor
GraphCanvas::CanHandleMimeEventOutcome CanHandleValueMimeEvent(const GraphCanvas::Endpoint& endpoint, const QMimeData* mimeData) override;
bool HandleValueMimeEvent(const GraphCanvas::Endpoint& endpoint, const QMimeData* mimeData) override;
GraphCanvas::SlotId RequestExtension(const GraphCanvas::NodeId& nodeId, const GraphCanvas::ExtenderId& extenderId) override;
GraphCanvas::SlotId RequestExtension(const GraphCanvas::NodeId& nodeId, const GraphCanvas::ExtenderId& extenderId, GraphModelRequests::ExtensionRequestReason ) override;
void ExtensionCancelled(const GraphCanvas::NodeId& nodeId, const GraphCanvas::ExtenderId& extenderId) override;
void FinalizeExtension(const GraphCanvas::NodeId& nodeId, const GraphCanvas::ExtenderId& extenderId) override;
@@ -357,6 +357,9 @@ namespace ScriptCanvasEditor
AZStd::unordered_map< GraphCanvas::ToastId, AZ::EntityId > m_toastNodeIds;
// Function Definition Node Extension
void HandleFunctionDefinitionExtension(ScriptCanvas::Node* node, GraphCanvas::SlotId graphCanvasSlotId, const GraphCanvas::NodeId& nodeId);
//// Version Update code
AZ::Outcome<ScriptCanvas::Node*> ReplaceNodeByConfig(ScriptCanvas::Node*, const ScriptCanvas::NodeConfiguration&, ScriptCanvas::ReplacementConnectionMap&);
bool SanityCheckNodeReplacement(ScriptCanvas::Node*, ScriptCanvas::Node*, AZStd::unordered_map<ScriptCanvas::SlotId, AZStd::vector<ScriptCanvas::SlotId>>&);
@@ -146,8 +146,6 @@ namespace ScriptCanvasEditor
void LoadVariables(const ScriptCanvasMemoryAsset::pointer memoryAsset);
void ClearVariables();
void GetScriptCanvasId();
private:
AZ::Data::AssetId m_removedCatalogId;
AZ::Data::AssetId m_previousAssetId;
@@ -53,7 +53,9 @@ namespace ScriptCanvasEditor
AzEventHandler,
Invalid
};
class NodeDescriptorComponent;
class NodeDescriptorRequests : public AZ::EBusTraits
{
public:
@@ -74,6 +76,8 @@ namespace ScriptCanvasEditor
return GetType() == descriptorType;
}
virtual NodeDescriptorComponent* GetDescriptorComponent() = 0;
};
using NodeDescriptorRequestBus = AZ::EBus<NodeDescriptorRequests>;
@@ -15,6 +15,7 @@
#include <Editor/Nodes/NodeCreateUtils.h>
#include <Editor/Nodes/NodeDisplayUtils.h>
#include <GraphCanvas/Components/Nodes/NodeBus.h>
#include <GraphCanvas/Components/Nodes/NodeTitleBus.h>
#include <ScriptCanvas/Bus/EditorScriptCanvasBus.h>
@@ -23,7 +24,7 @@
#include <ScriptCanvas/Libraries/Core/AzEventHandler.h>
#include <ScriptCanvas/Libraries/Core/EBusEventHandler.h>
#include <ScriptCanvas/Libraries/Core/FunctionDefinitionNode.h>
#include <ScriptCanvas/Libraries/Core/FunctionNode.h>
#include <ScriptCanvas/Libraries/Core/FunctionCallNode.h>
#include <ScriptCanvas/Libraries/Core/GetVariable.h>
#include <ScriptCanvas/Libraries/Core/Method.h>
#include <ScriptCanvas/Libraries/Core/MethodOverloaded.h>
@@ -34,12 +35,15 @@
namespace ScriptCanvasEditor::Nodes
{
NodeIdPair CreateExecutionNodeling(const ScriptCanvas::ScriptCanvasId& scriptCanvasId, AZStd::string_view rootName)
NodeIdPair CreateFunctionDefinitionNode(const ScriptCanvas::ScriptCanvasId& scriptCanvasId, bool isInput, AZStd::string rootName)
{
ScriptCanvasEditor::Nodes::StyleConfiguration styleConfiguration;
NodeIdPair createdPair = CreateNode(azrtti_typeid<ScriptCanvas::Nodes::Core::FunctionDefinitionNode>(), scriptCanvasId, styleConfiguration);
auto nodeAndPair = CreateAndGetNode(azrtti_typeid<ScriptCanvas::Nodes::Core::FunctionDefinitionNode>(), scriptCanvasId, styleConfiguration);
NodeIdPair createdPair = nodeAndPair.second;
if (createdPair.m_scriptCanvasId.IsValid())
auto functionDefinitionNode = azrtti_cast<ScriptCanvas::Nodes::Core::FunctionDefinitionNode*>(nodeAndPair.first);
if (functionDefinitionNode && createdPair.m_scriptCanvasId.IsValid())
{
AZStd::unordered_set<AZStd::string> nodelingNames;
@@ -71,12 +75,43 @@ namespace ScriptCanvasEditor::Nodes
nodelingId.m_scriptCanvasId = scriptCanvasId;
ScriptCanvas::NodelingRequestBus::Event(nodelingId, &ScriptCanvas::NodelingRequests::SetDisplayName, nodelingName);
if (!isInput)
{
functionDefinitionNode->MarkExecutionExit();
}
GraphCanvas::NodeTitleRequestBus::Event(createdPair.m_graphCanvasId, &GraphCanvas::NodeTitleRequests::SetSubTitle, "Function");
// Because of how the extender slots are registered, there isn't an easy way to only create one or the other based on
// the type of nodeling, so instead they both get created and we need to remove the inapplicable one
GraphCanvas::ConnectionType typeToRemove = (isInput) ? GraphCanvas::CT_Input : GraphCanvas::CT_Output;
AZStd::vector<GraphCanvas::SlotId> extenderSlotIds, executionSlotIds;
GraphCanvas::NodeRequestBus::EventResult(extenderSlotIds, createdPair.m_graphCanvasId, &GraphCanvas::NodeRequests::FindVisibleSlotIdsByType, typeToRemove, GraphCanvas::SlotTypes::ExtenderSlot);
if (!extenderSlotIds.empty())
{
GraphCanvas::NodeRequestBus::Event(createdPair.m_graphCanvasId, &GraphCanvas::NodeRequests::RemoveSlot, *extenderSlotIds.begin());
}
GraphCanvas::NodeRequestBus::EventResult(executionSlotIds, createdPair.m_graphCanvasId, &GraphCanvas::NodeRequests::FindVisibleSlotIdsByType, typeToRemove, GraphCanvas::SlotTypes::ExecutionSlot);
if (!executionSlotIds.empty())
{
GraphCanvas::NodeRequestBus::Event(createdPair.m_graphCanvasId, &GraphCanvas::NodeRequests::RemoveSlot, *executionSlotIds.begin());
}
}
return createdPair;
}
NodeIdPair CreateNode(const AZ::Uuid& classId, const ScriptCanvas::ScriptCanvasId& scriptCanvasId, const StyleConfiguration& styleConfiguration)
{
return CreateAndGetNode(classId, scriptCanvasId, styleConfiguration).second;
}
AZStd::pair<ScriptCanvas::Node*, NodeIdPair> CreateAndGetNode(const AZ::Uuid& classId, const ScriptCanvas::ScriptCanvasId& scriptCanvasId, const StyleConfiguration& styleConfiguration)
{
AZ_PROFILE_TIMER("ScriptCanvas", __FUNCTION__);
NodeIdPair nodeIdPair;
@@ -104,7 +139,7 @@ namespace ScriptCanvasEditor::Nodes
//nodeConfiguration.m_nodeSubStyle = styleConfiguration.m_nodeSubStyle;
}
return nodeIdPair;
return AZStd::make_pair(node, nodeIdPair);
}
NodeIdPair CreateEntityNode(const AZ::EntityId& sourceId, const ScriptCanvas::ScriptCanvasId& scriptCanvasId)
@@ -367,7 +402,7 @@ namespace ScriptCanvasEditor::Nodes
return nodeIds;
}
NodeIdPair CreateFunctionNode(const ScriptCanvas::ScriptCanvasId& scriptCanvasGraphId, const AZ::Data::AssetId& assetId)
NodeIdPair CreateFunctionNode(const ScriptCanvas::ScriptCanvasId& scriptCanvasGraphId, const AZ::Data::AssetId& assetId, const ScriptCanvas::Grammar::FunctionSourceId& sourceId)
{
AZ_Assert(assetId.IsValid(), "CreateFunctionNode source asset Id must be valid");
@@ -381,11 +416,9 @@ namespace ScriptCanvasEditor::Nodes
scriptCanvasEntity->Init();
ScriptCanvas::Node* node = nullptr;
ScriptCanvas::SystemRequestBus::BroadcastResult(node, &ScriptCanvas::SystemRequests::CreateNodeOnEntity, scriptCanvasEntity->GetId(), scriptCanvasGraphId, ScriptCanvas::Nodes::Core::FunctionNode::RTTI_Type());
auto* functionNode = azrtti_cast<ScriptCanvas::Nodes::Core::FunctionNode*>(node);
functionNode->Initialize(assetId);
functionNode->ConfigureNode(assetId);
ScriptCanvas::SystemRequestBus::BroadcastResult(node, &ScriptCanvas::SystemRequests::CreateNodeOnEntity, scriptCanvasEntity->GetId(), scriptCanvasGraphId, ScriptCanvas::Nodes::Core::FunctionCallNode::RTTI_Type());
auto functionNode = azrtti_cast<ScriptCanvas::Nodes::Core::FunctionCallNode*>(node);
functionNode->Initialize(assetId, sourceId);
functionNode->BuildNode();
nodeIdPair.m_scriptCanvasId = scriptCanvasEntity->GetId();
@@ -13,12 +13,16 @@
#pragma once
#include <AzCore/Component/EntityId.h>
#include <Editor/Nodes/NodeUtils.h>
#include <ScriptCanvas/Bus/NodeIdPair.h>
#include <ScriptCanvas/Core/SubgraphInterfaceUtility.h>
#include <ScriptCanvas/Variable/VariableCore.h>
namespace ScriptCanvas
{
class Node;
}
namespace ScriptEvents
{
class Method;
@@ -27,6 +31,7 @@ namespace ScriptEvents
namespace ScriptCanvasEditor::Nodes
{
// Specific create methods which will also handle displaying the node.
AZStd::pair<ScriptCanvas::Node*, NodeIdPair> CreateAndGetNode(const AZ::Uuid& classData, const ScriptCanvas::ScriptCanvasId& scriptCanvasId, const StyleConfiguration& styleConfiguration);
NodeIdPair CreateNode(const AZ::Uuid& classData, const ScriptCanvas::ScriptCanvasId& scriptCanvasId, const StyleConfiguration& styleConfiguration);
NodeIdPair CreateEntityNode(const AZ::EntityId& sourceId, const ScriptCanvas::ScriptCanvasId& scriptCanvasId);
NodeIdPair CreateObjectMethodNode(AZStd::string_view className, AZStd::string_view methodName, const ScriptCanvas::ScriptCanvasId& scriptCanvasId);
@@ -42,10 +47,8 @@ namespace ScriptCanvasEditor::Nodes
NodeIdPair CreateSetVariableNode(const ScriptCanvas::VariableId& variableId, ScriptCanvas::ScriptCanvasId scriptCanvasGraphId);
// Functions
NodeIdPair CreateFunctionNode(const ScriptCanvas::ScriptCanvasId& scriptCanvasGraphId, const AZ::Data::AssetId& assetId);
// Nodelings
NodeIdPair CreateExecutionNodeling(const ScriptCanvas::ScriptCanvasId& scriptCanvasId, AZStd::string_view rootName = "New Nodeling");
NodeIdPair CreateFunctionNode(const ScriptCanvas::ScriptCanvasId& scriptCanvasGraphId, const AZ::Data::AssetId& assetId, const ScriptCanvas::Grammar::FunctionSourceId& sourceId);
NodeIdPair CreateFunctionDefinitionNode(const ScriptCanvas::ScriptCanvasId& scriptCanvasId, bool isInput, AZStd::string rootName = "New Nodeling");
// AZ Event
NodeIdPair CreateAzEventHandlerNode(const AZ::BehaviorMethod& methodWithAzEventReturn, ScriptCanvas::ScriptCanvasId scriptCanvasId,
@@ -30,6 +30,8 @@
#include <GraphCanvas/Components/NodeDescriptors/ScriptEventReceiverNodeDescriptorComponent.h>
#include <GraphCanvas/Components/NodeDescriptors/ScriptEventSenderNodeDescriptorComponent.h>
#include <GraphCanvas/Components/NodeDescriptors/UserDefinedNodeDescriptorComponent.h>
#include <GraphCanvas/Components/NodeDescriptors/FunctionDefinitionNodeDescriptorComponent.h>
#include <GraphCanvas/Components/Nodes/NodeTitleBus.h>
#include <GraphCanvas/GraphCanvasBus.h>
#include <GraphCanvas/Components/Slots/Extender/ExtenderSlotBus.h>
@@ -39,7 +41,7 @@
#include <ScriptCanvas/Libraries/Core/AzEventHandler.h>
#include <ScriptCanvas/Libraries/Core/EBusEventHandler.h>
#include <ScriptCanvas/Libraries/Core/FunctionDefinitionNode.h>
#include <ScriptCanvas/Libraries/Core/FunctionNode.h>
#include <ScriptCanvas/Libraries/Core/FunctionCallNode.h>
#include <ScriptCanvas/Libraries/Core/GetVariable.h>
#include <ScriptCanvas/Libraries/Core/ReceiveScriptEvent.h>
#include <ScriptCanvas/Libraries/Core/Method.h>
@@ -47,6 +49,7 @@
#include <ScriptCanvas/Libraries/Core/SetVariable.h>
#include <ScriptCanvas/Libraries/Entity/EntityRef.h>
namespace ScriptCanvasEditor::Nodes::SlotDisplayHelper
{
AZ::EntityId DisplayPropertySlot(AZ::EntityId graphCanvasNodeId, const ScriptCanvas::VisualExtensionSlotConfiguration& propertyConfiguration);
@@ -819,12 +822,12 @@ namespace ScriptCanvasEditor::Nodes
}
// Function Nodes
AZ::EntityId DisplayFunctionNode(AZ::EntityId graphCanvasGraphId, const ScriptCanvas::Nodes::Core::FunctionNode* functionNode)
AZ::EntityId DisplayFunctionNode(AZ::EntityId graphCanvasGraphId, const ScriptCanvas::Nodes::Core::FunctionCallNode* functionNode)
{
return DisplayFunctionNode(graphCanvasGraphId, const_cast<ScriptCanvas::Nodes::Core::FunctionNode*>(functionNode));
return DisplayFunctionNode(graphCanvasGraphId, const_cast<ScriptCanvas::Nodes::Core::FunctionCallNode*>(functionNode));
}
AZ::EntityId DisplayFunctionNode(AZ::EntityId, ScriptCanvas::Nodes::Core::FunctionNode* functionNode)
AZ::EntityId DisplayFunctionNode(AZ::EntityId, ScriptCanvas::Nodes::Core::FunctionCallNode* functionNode)
{
AZ::EntityId graphCanvasNodeId;
@@ -892,6 +895,80 @@ namespace ScriptCanvasEditor::Nodes
return graphCanvasNodeId;
}
AZ::EntityId DisplayFunctionDefinitionNode(AZ::EntityId graphCanvasGraphId, const ScriptCanvas::Nodes::Core::FunctionDefinitionNode* nodeling)
{
NodeConfiguration nodeConfiguration;
nodeConfiguration.PopulateComponentDescriptors<IconComponent, FunctionDefinitionNodeDescriptorComponent>();
if (nodeling->RequiresDynamicSlotOrdering())
{
nodeConfiguration.PopulateComponentDescriptors<DynamicOrderingDynamicSlotComponent>();
}
else
{
nodeConfiguration.PopulateComponentDescriptors<DynamicSlotComponent>();
}
nodeConfiguration.m_nodeSubStyle = ".nodeling";
nodeConfiguration.m_titlePalette = "NodelingTitlePalette";
nodeConfiguration.m_scriptCanvasId = nodeling->GetEntityId();
AZ::SerializeContext* serializeContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
AZ_Assert(serializeContext, "Failed to acquire application serialize context.");
const AZ::SerializeContext::ClassData* classData = serializeContext->FindClassData(azrtti_typeid(nodeling));
if (classData)
{
AZStd::string nodeContext = GetContextName(*classData);
nodeConfiguration.m_translationContext = TranslationHelper::GetUserDefinedContext(nodeContext);
nodeConfiguration.m_titleFallback = (classData->m_editData && classData->m_editData->m_name) ? classData->m_editData->m_name : classData->m_name;
nodeConfiguration.m_tooltipFallback = (classData->m_editData && classData->m_editData->m_description) ? classData->m_editData->m_description : "";
GraphCanvas::TranslationKeyedString subtitleKeyedString(nodeContext, nodeConfiguration.m_translationContext);
subtitleKeyedString.m_key = TranslationHelper::GetUserDefinedNodeKey(nodeContext, nodeConfiguration.m_titleFallback, ScriptCanvasEditor::TranslationKeyId::Category);
nodeConfiguration.m_subtitleFallback = subtitleKeyedString.GetDisplayString();
nodeConfiguration.m_translationKeyName = nodeConfiguration.m_titleFallback;
nodeConfiguration.m_translationKeyContext = nodeContext;
nodeConfiguration.m_translationGroup = TranslationContextGroup::ClassMethod;
ScriptCanvas::GraphScopedNodeId nodelingId;
nodelingId.m_identifier = nodeConfiguration.m_scriptCanvasId;
nodelingId.m_scriptCanvasId = nodeling->GetOwningScriptCanvasId();
AZStd::string nodelingName;
ScriptCanvas::NodelingRequestBus::EventResult(nodelingName, nodelingId, &ScriptCanvas::NodelingRequests::GetDisplayName);
if (classData->m_editData)
{
const AZ::Edit::ElementData* elementData = classData->m_editData->FindElementData(AZ::Edit::ClassElements::EditorData);
if (elementData)
{
if (auto nodeTypeAttribute = elementData->FindAttribute(ScriptCanvas::Attributes::Node::NodeType))
{
if (auto nodeTypeAttributeData = azdynamic_cast<const AZ::Edit::AttributeData<NodeType>*>(nodeTypeAttribute))
{
nodeConfiguration.m_nodeType = nodeTypeAttributeData->Get(nullptr);
}
}
}
}
}
nodeConfiguration.m_subtitleFallback = "";
return DisplayGeneralScriptCanvasNode(graphCanvasGraphId, nodeling, nodeConfiguration);
}
AZ::EntityId DisplayNodeling(AZ::EntityId graphCanvasGraphId, const ScriptCanvas::Nodes::Core::Internal::Nodeling* nodeling)
{
NodeConfiguration nodeConfiguration;
@@ -1062,9 +1139,13 @@ namespace ScriptCanvasEditor::Nodes
{
graphCanvasNodeId = DisplayScriptEventSenderNode(graphCanvasGraphId, static_cast<const ScriptCanvas::Nodes::Core::SendScriptEvent*>(node));
}
else if (azrtti_istypeof<ScriptCanvas::Nodes::Core::FunctionNode>(node))
else if (azrtti_istypeof<ScriptCanvas::Nodes::Core::FunctionCallNode>(node))
{
graphCanvasNodeId = DisplayFunctionNode(graphCanvasGraphId, static_cast<const ScriptCanvas::Nodes::Core::FunctionNode*>(node));
graphCanvasNodeId = DisplayFunctionNode(graphCanvasGraphId, static_cast<const ScriptCanvas::Nodes::Core::FunctionCallNode*>(node));
}
else if (azrtti_istypeof<ScriptCanvas::Nodes::Core::FunctionDefinitionNode>(node))
{
graphCanvasNodeId = DisplayFunctionDefinitionNode(graphCanvasGraphId, static_cast<const ScriptCanvas::Nodes::Core::FunctionDefinitionNode*>(node));
}
else if (azrtti_istypeof<ScriptCanvas::Nodes::Core::Internal::Nodeling>(node))
{
@@ -1138,7 +1219,7 @@ namespace ScriptCanvasEditor::Nodes
if (slot.IsLatent())
{
executionConfiguration.m_textDecoration = "🕒";
executionConfiguration.m_textDecoration = u8"\U0001f552";
executionConfiguration.m_textDecorationToolTip = "This slot will not be executed immediately.";
}
@@ -1163,7 +1244,7 @@ namespace ScriptCanvasEditor::Nodes
if (slot.IsLatent())
{
dataSlotConfiguration.m_textDecoration = "🕒";
dataSlotConfiguration.m_textDecoration = u8"\U0001f552";
dataSlotConfiguration.m_textDecorationToolTip = "This slot will not be executed immediately.";
}
@@ -28,7 +28,7 @@ namespace ScriptCanvas::Nodes::Core
{
class AzEventHandler;
class EBusEventHandler;
class FunctionNode;
class FunctionCallNode;
class GetVariableNode;
class Method;
class ReceiveScriptEvent;
@@ -66,8 +66,8 @@ namespace ScriptCanvasEditor::Nodes
AZ::EntityId DisplayScriptEventWrapperNode(AZ::EntityId graphCanvasGraphId, const ScriptCanvas::Nodes::Core::ReceiveScriptEvent* busNode);
// Functions
AZ::EntityId DisplayFunctionNode(AZ::EntityId graphCanvasGraphId, const ScriptCanvas::Nodes::Core::FunctionNode* functionNode);
AZ::EntityId DisplayFunctionNode(AZ::EntityId graphCanvasGraphId, ScriptCanvas::Nodes::Core::FunctionNode* functionNode);
AZ::EntityId DisplayFunctionNode(AZ::EntityId graphCanvasGraphId, const ScriptCanvas::Nodes::Core::FunctionCallNode* functionNode);
AZ::EntityId DisplayFunctionNode(AZ::EntityId graphCanvasGraphId, ScriptCanvas::Nodes::Core::FunctionCallNode* functionNode);
// SlotGroup will control how elements are grouped.
@@ -66,6 +66,7 @@
#include <Editor/GraphCanvas/Components/NodeDescriptors/UserDefinedNodeDescriptorComponent.h>
#include <Editor/GraphCanvas/Components/NodeDescriptors/VariableNodeDescriptorComponent.h>
#include <Editor/GraphCanvas/Components/NodeDescriptors/FunctionNodeDescriptorComponent.h>
#include <Editor/GraphCanvas/Components/NodeDescriptors/FunctionDefinitionNodeDescriptorComponent.h>
#include <Editor/GraphCanvas/Components/MappingComponent.h>
#include <Editor/View/Widgets/VariablePanel/VariableDockWidget.h>
@@ -118,6 +119,7 @@ namespace ScriptCanvas
ScriptCanvasEditor::SetVariableNodeDescriptorComponent::CreateDescriptor(),
ScriptCanvasEditor::UserDefinedNodeDescriptorComponent::CreateDescriptor(),
ScriptCanvasEditor::FunctionNodeDescriptorComponent::CreateDescriptor(),
ScriptCanvasEditor::FunctionDefinitionNodeDescriptorComponent::CreateDescriptor(),
ScriptCanvasEditor::NodelingDescriptorComponent::CreateDescriptor()
});
+2 -2
View File
@@ -30,8 +30,8 @@ namespace SettingsCpp
{
if (auto userSettings = AZ::UserSettings::CreateFind<ScriptCanvasEditor::EditorSettings::ScriptCanvasEditorSettings>(AZ_CRC("ScriptCanvasPreviewSettings", 0x1c5a2965), AZ::UserSettings::CT_LOCAL))
{
ScriptCanvas::Grammar::s_saveRawTranslationOuputToFile = userSettings->m_saveRawTranslationOuputToFile;
ScriptCanvas::Grammar::s_printAbstractCodeModel = userSettings->m_printAbstractCodeModel;
ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = userSettings->m_saveRawTranslationOuputToFile;
ScriptCanvas::Grammar::g_printAbstractCodeModel = userSettings->m_printAbstractCodeModel;
}
}
}
@@ -15,22 +15,19 @@
#include <QPixmap>
#include <AzToolsFramework/AssetEditor/AssetEditorUtils.h>
#include <Editor/GraphCanvas/GraphCanvasEditorNotificationBusId.h>
#include <Editor/Nodes/NodeCreateUtils.h>
#include <ScriptCanvas/Bus/EditorScriptCanvasBus.h>
#include <ScriptCanvas/Bus/RequestBus.h>
#include <ScriptCanvas/GraphCanvas/NodeDescriptorBus.h>
#include <GraphCanvas/Components/SceneBus.h>
#include <GraphCanvas/Components/VisualBus.h>
#include <Editor/View/Widgets/NodePalette/FunctionNodePaletteTreeItemTypes.h>
#include <GraphCanvas/Components/GridBus.h>
#include <GraphCanvas/Components/Nodes/Wrapper/WrapperNodeBus.h>
#include <GraphCanvas/Components/SceneBus.h>
#include <GraphCanvas/Components/StyleBus.h>
#include <GraphCanvas/Components/VisualBus.h>
#include <GraphCanvas/Widgets/GraphCanvasGraphicsView/GraphCanvasGraphicsView.h>
#include <Editor/GraphCanvas/GraphCanvasEditorNotificationBusId.h>
#include <Editor/View/Widgets/NodePalette/FunctionNodePaletteTreeItemTypes.h>
#include <ScriptCanvas/Bus/EditorScriptCanvasBus.h>
#include <ScriptCanvas/Bus/RequestBus.h>
#include <ScriptCanvas/Core/SubgraphInterfaceUtility.h>
#include <ScriptCanvas/GraphCanvas/NodeDescriptorBus.h>
namespace ScriptCanvasEditor
{
@@ -51,50 +48,41 @@ namespace ScriptCanvasEditor
}
CreateFunctionMimeEvent::CreateFunctionMimeEvent(const AZ::Data::AssetId& assetId)
CreateFunctionMimeEvent::CreateFunctionMimeEvent(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType, const ScriptCanvas::Grammar::FunctionSourceId& sourceId)
: m_assetId(assetId)
, m_assetType(assetType)
, m_sourceId(sourceId)
{
}
bool CreateFunctionMimeEvent::CanGraphHandleEvent(const GraphCanvas::GraphId& graphId) const
bool CreateFunctionMimeEvent::CanGraphHandleEvent([[maybe_unused]] const GraphCanvas::GraphId& graphId) const
{
AZ::EntityId scGraphId;
GeneralRequestBus::BroadcastResult(scGraphId, &GeneralRequests::GetScriptCanvasId, graphId);
bool isFunctionGraph = false;
EditorGraphRequestBus::EventResult(isFunctionGraph, scGraphId, &EditorGraphRequests::IsFunctionGraph);
return !isFunctionGraph;
return true;
}
ScriptCanvasEditor::NodeIdPair CreateFunctionMimeEvent::CreateNode(const AZ::EntityId& scriptCanvasGraphId) const
{
return Nodes::CreateFunctionNode(scriptCanvasGraphId, m_assetId);
return Nodes::CreateFunctionNode(scriptCanvasGraphId, m_assetId, m_sourceId);
}
/////////////////////////////////////
// FunctionPaletteTreeItem
/////////////////////////////////////
FunctionPaletteTreeItem::FunctionPaletteTreeItem(const char* name, const AZ::Data::AssetId& sourceAssetId, const AZ::Data::AssetId& runtimeAssetId)
FunctionPaletteTreeItem::FunctionPaletteTreeItem(const char* name, const ScriptCanvas::Grammar::FunctionSourceId& sourceId, AZ::Data::Asset<AZ::Data::AssetData> asset)
: GraphCanvas::DraggableNodePaletteTreeItem(name, ScriptCanvasEditor::AssetEditorId)
, m_editIcon(":/ScriptCanvasEditorResources/Resources/edit_icon.png")
, m_sourceAssetId(sourceAssetId)
, m_runtimeAssetId(runtimeAssetId)
, m_sourceId(sourceId)
, m_asset(asset)
{
//TODO
// TODO
//SetToolTip(m_methodDefinition.GetTooltip().c_str());
SetTitlePalette("FunctionNodeTitlePalette");
}
void FunctionPaletteTreeItem::SetRuntimeAssetId(const AZ::Data::AssetId& assetId)
{
m_runtimeAssetId = assetId;
}
GraphCanvas::GraphCanvasMimeEvent* FunctionPaletteTreeItem::CreateMimeEvent() const
{
return aznew CreateFunctionMimeEvent(m_runtimeAssetId);
return aznew CreateFunctionMimeEvent(m_asset->GetId(), m_asset->GetType(), m_sourceId);
}
QVariant FunctionPaletteTreeItem::OnData(const QModelIndex& index, int role) const
@@ -117,14 +105,24 @@ namespace ScriptCanvasEditor
return GraphCanvas::DraggableNodePaletteTreeItem::OnData(index, role);
}
const AZ::Data::AssetId& FunctionPaletteTreeItem::GetSourceAssetId() const
ScriptCanvas::Grammar::FunctionSourceId FunctionPaletteTreeItem::GetFunctionSourceId() const
{
return m_sourceAssetId;
return m_sourceId;
}
const AZ::Data::AssetId& FunctionPaletteTreeItem::GetRuntimeAssetId() const
AZ::Data::AssetId FunctionPaletteTreeItem::GetSourceAssetId() const
{
return m_runtimeAssetId;
return AZ::Data::AssetId(GetAssetId().m_guid, 0);
}
AZ::Data::AssetId FunctionPaletteTreeItem::GetAssetId() const
{
return m_asset->GetId();
}
AZ::Data::AssetType FunctionPaletteTreeItem::GetAssetType() const
{
return m_asset->GetType();
}
void FunctionPaletteTreeItem::OnHoverStateChanged()
@@ -136,7 +134,7 @@ namespace ScriptCanvasEditor
{
if (row == NodePaletteTreeItem::Column::Customization)
{
GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAsset, m_sourceAssetId, -1);
GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAsset, GetSourceAssetId(), -1);
}
}
@@ -144,7 +142,7 @@ namespace ScriptCanvasEditor
{
if (row != NodePaletteTreeItem::Column::Customization)
{
GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAsset, m_sourceAssetId, -1);
GeneralRequestBus::Broadcast(&GeneralRequests::OpenScriptCanvasAsset, GetSourceAssetId(), -1);
return true;
}
@@ -44,15 +44,16 @@ namespace ScriptCanvasEditor
static void Reflect(AZ::ReflectContext* reflectContext);
CreateFunctionMimeEvent() = default;
CreateFunctionMimeEvent(const AZ::Data::AssetId& assetId);
CreateFunctionMimeEvent(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType, const ScriptCanvas::Grammar::FunctionSourceId& sourceId);
~CreateFunctionMimeEvent() = default;
bool CanGraphHandleEvent(const GraphCanvas::GraphId& graphId) const override;
ScriptCanvasEditor::NodeIdPair CreateNode(const AZ::EntityId& graphId) const override;
private:
ScriptCanvas::Grammar::FunctionSourceId m_sourceId;
AZ::Data::AssetId m_assetId;
AZ::Data::AssetType m_assetType;
};
class FunctionPaletteTreeItem
@@ -62,30 +63,26 @@ namespace ScriptCanvasEditor
AZ_RTTI(FunctionPaletteTreeItem, "{AF75BBAD-BC8A-46D2-81B6-54C0E6CB3E41}", GraphCanvas::DraggableNodePaletteTreeItem);
AZ_CLASS_ALLOCATOR(FunctionPaletteTreeItem, AZ::SystemAllocator, 0);
FunctionPaletteTreeItem(const char* name, const AZ::Data::AssetId& sourceAssetId, const AZ::Data::AssetId& runtimeAssetId = {});
FunctionPaletteTreeItem(const char* name, const ScriptCanvas::Grammar::FunctionSourceId& sourceId, AZ::Data::Asset<AZ::Data::AssetData> asset);
~FunctionPaletteTreeItem() = default;
void SetRuntimeAssetId(const AZ::Data::AssetId& assetId);
GraphCanvas::GraphCanvasMimeEvent* CreateMimeEvent() const;
QVariant OnData(const QModelIndex& index, int role) const;
const AZ::Data::AssetId& GetSourceAssetId() const;
const AZ::Data::AssetId& GetRuntimeAssetId() const;
ScriptCanvas::Grammar::FunctionSourceId GetFunctionSourceId() const;
AZ::Data::AssetId GetSourceAssetId() const;
AZ::Data::AssetId GetAssetId() const;
AZ::Data::AssetType GetAssetType() const;
protected:
void OnHoverStateChanged() override;
void OnClicked(int row) override;
bool OnDoubleClicked(int row) override;
private:
QIcon m_editIcon;
AZ::Data::AssetId m_sourceAssetId;
AZ::Data::AssetId m_runtimeAssetId;
ScriptCanvas::Grammar::FunctionSourceId m_sourceId;
AZ::Data::Asset<AZ::Data::AssetData> m_asset;
};
}
@@ -583,6 +583,13 @@ namespace
{
if (!IsExplicitOverload(*methodIter.second))
{
// Respect the exclusion flags
auto attributeData = azdynamic_cast<const AZ::Edit::AttributeData<AZ::Script::Attributes::ExcludeFlags>*>(AZ::FindAttribute(AZ::Script::Attributes::ExcludeFrom, methodIter.second->m_attributes));
if (ShouldExcludeFromNodeList(attributeData , {}))
{
return;
}
RegisterMethod(nodePaletteModel, behaviorContext, categoryPath, behaviorClass, methodIter.first, *methodIter.second, behaviorClass->IsMethodOverloaded(methodIter.first));
}
}
@@ -1290,7 +1297,7 @@ namespace ScriptCanvasEditor
AzFramework::StringFunc::Path::Join(rootPath.c_str(), assetInfo.m_relativePath.c_str(), absolutePath);
AZStd::string category = "Global Functions";
AZStd::string category = "User Functions";
AZStd::string relativePath;
if (AzFramework::StringFunc::Path::GetFolderPath(assetInfo.m_relativePath.c_str(), relativePath))
@@ -27,59 +27,48 @@
#include <AzCore/Component/ComponentApplication.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/std/containers/map.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/UserSettings/UserSettings.h>
#include <AzCore/std/containers/map.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/AssetEditor/AssetEditorUtils.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/AssetBrowser/Entries/ProductAssetBrowserEntry.h>
#include <AzToolsFramework/AssetBrowser/Entries/SourceAssetBrowserEntry.h>
#include <AzToolsFramework/AssetEditor/AssetEditorUtils.h>
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
#include <ScriptEvents/ScriptEventsAsset.h>
#include <GraphCanvas/Widgets/NodePalette/TreeItems/NodePaletteTreeItem.h>
#include <GraphCanvas/Widgets/NodePalette/NodePaletteWidget.h>
#include <GraphCanvas/Widgets/NodePalette/NodePaletteTreeView.h>
#include <Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.h>
#include <Editor/View/Widgets/ui_ScriptCanvasNodePaletteToolbar.h>
#include <Editor/GraphCanvas/GraphCanvasEditorNotificationBusId.h>
#include <Editor/Nodes/NodeUtils.h>
#include <Editor/GraphCanvas/GraphCanvasEditorNotificationBusId.h>
#include <Editor/View/Widgets/NodePalette/EBusNodePaletteTreeItemTypes.h>
#include <Editor/View/Widgets/NodePalette/FunctionNodePaletteTreeItemTypes.h>
#include <Editor/View/Widgets/NodePalette/ScriptEventsNodePaletteTreeItemTypes.h>
#include <Editor/View/Widgets/NodePalette/GeneralNodePaletteTreeItemTypes.h>
#include <Editor/View/Widgets/NodePalette/SpecializedNodePaletteTreeItemTypes.h>
#include <Editor/View/Widgets/NodePalette/VariableNodePaletteTreeItemTypes.h>
#include <Editor/View/Widgets/NodePalette/NodePaletteModel.h>
#include <Editor/Assets/ScriptCanvasAssetHelpers.h>
#include <Editor/Components/IconComponent.h>
#include <Editor/Include/ScriptCanvas/Bus/RequestBus.h>
#include <Editor/GraphCanvas/GraphCanvasEditorNotificationBusId.h>
#include <Editor/GraphCanvas/GraphCanvasEditorNotificationBusId.h>
#include <Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h>
#include <Editor/Include/ScriptCanvas/Bus/RequestBus.h>
#include <Editor/Nodes/NodeUtils.h>
#include <Editor/Settings.h>
#include <Editor/Translation/TranslationHelper.h>
#include <Editor/View/Widgets/NodePalette/EBusNodePaletteTreeItemTypes.h>
#include <Editor/View/Widgets/NodePalette/FunctionNodePaletteTreeItemTypes.h>
#include <Editor/View/Widgets/NodePalette/GeneralNodePaletteTreeItemTypes.h>
#include <Editor/View/Widgets/NodePalette/NodePaletteModel.h>
#include <Editor/View/Widgets/NodePalette/ScriptEventsNodePaletteTreeItemTypes.h>
#include <Editor/View/Widgets/NodePalette/SpecializedNodePaletteTreeItemTypes.h>
#include <Editor/View/Widgets/NodePalette/VariableNodePaletteTreeItemTypes.h>
#include <Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.h>
#include <Editor/View/Widgets/ui_ScriptCanvasNodePaletteToolbar.h>
#include <GraphCanvas/Widgets/NodePalette/NodePaletteTreeView.h>
#include <GraphCanvas/Widgets/NodePalette/NodePaletteWidget.h>
#include <GraphCanvas/Widgets/NodePalette/TreeItems/NodePaletteTreeItem.h>
#include <ScriptCanvas/Asset/RuntimeAsset.h>
#include <ScriptCanvas/Data/DataRegistry.h>
#include <ScriptCanvas/Utils/NodeUtils.h>
#include <ScriptCanvas/Core/Attributes.h>
#include <ScriptCanvas/Libraries/Entity/EntityRef.h>
#include <ScriptCanvas/Libraries/Libraries.h>
#include <ScriptCanvas/Core/SubgraphInterfaceUtility.h>
#include <ScriptCanvas/Data/DataRegistry.h>
#include <ScriptCanvas/Libraries/Core/GetVariable.h>
#include <ScriptCanvas/Libraries/Core/Method.h>
#include <ScriptCanvas/Libraries/Core/SetVariable.h>
#include <AzToolsFramework/AssetBrowser/Entries/ProductAssetBrowserEntry.h>
#include <AzToolsFramework/AssetBrowser/Entries/SourceAssetBrowserEntry.h>
#include <ScriptCanvas/Libraries/Entity/EntityRef.h>
#include <ScriptCanvas/Libraries/Libraries.h>
#include <ScriptCanvas/Utils/NodeUtils.h>
#include <ScriptEvents/ScriptEventsAsset.h>
namespace ScriptCanvasEditor
{
@@ -103,7 +92,7 @@ namespace ScriptCanvasEditor
GraphCanvas::NodePaletteTreeItem* customEventRoot = root->GetCategoryNode("Script Events");
customEventRoot->SetAllowPruneOnEmpty(false);
GraphCanvas::NodePaletteTreeItem* globalFunctionRoot = root->GetCategoryNode("Global Functions");
GraphCanvas::NodePaletteTreeItem* globalFunctionRoot = root->GetCategoryNode("User Functions");
globalFunctionRoot->SetAllowPruneOnEmpty(false);
}
@@ -167,7 +156,6 @@ namespace ScriptCanvasEditor
, m_nodePaletteModel(nodePaletteModel)
, m_assetModel(assetModel)
, m_categorizer(nodePaletteModel)
, m_isFunctionGraphActive(false)
{
UpgradeNotifications::Bus::Handler::BusConnect();
@@ -245,12 +233,9 @@ namespace ScriptCanvasEditor
{
ScriptCanvas::RuntimeRequestBus::EventResult(m_previousAssetId, scriptCanvasId, &ScriptCanvas::RuntimeRequests::GetAssetId);
m_isFunctionGraphActive = false;
EditorGraphRequestBus::EventResult(m_isFunctionGraphActive, scriptCanvasId, &EditorGraphRequests::IsFunctionGraph);
for (auto functionTreePair : m_globalFunctionTreeItems)
{
functionTreePair.second->SetEnabled(!m_isFunctionGraphActive);
functionTreePair.second->SetEnabled(true);
}
}
@@ -278,7 +263,6 @@ namespace ScriptCanvasEditor
if (entry->GetEntryType() == AzToolsFramework::AssetBrowser::AssetBrowserEntry::AssetEntryType::Product)
{
const AzToolsFramework::AssetBrowser::ProductAssetBrowserEntry* productEntry = azrtti_cast<const AzToolsFramework::AssetBrowser::ProductAssetBrowserEntry*>(entry);
const AZ::Data::AssetId& assetId = productEntry->GetAssetId();
auto scriptEventElementIter = m_scriptEventElementTreeItems.find(assetId);
@@ -290,22 +274,10 @@ namespace ScriptCanvasEditor
}
else
{
bool isRuntimeAsset = (m_runtimeAssets.erase(assetId) > 0);
auto globalFunctionElementIter = m_globalFunctionTreeItems.find(assetId.m_guid);
auto globalFunctionElementIter = m_globalFunctionTreeItems.find(assetId);
if (globalFunctionElementIter != m_globalFunctionTreeItems.end())
{
if (isRuntimeAsset)
{
globalFunctionElementIter->second->SetError("Function has errors and cannot be created until these errors are resolved.");
}
else
{
globalFunctionElementIter->second->DetachItem();
delete globalFunctionElementIter->second;
m_globalFunctionTreeItems.erase(globalFunctionElementIter);
}
globalFunctionElementIter->second->SetError("Graph has errors or has been deleted");
}
}
}
@@ -337,35 +309,35 @@ namespace ScriptCanvasEditor
if (entry->GetEntryType() == AzToolsFramework::AssetBrowser::AssetBrowserEntry::AssetEntryType::Product)
{
const AzToolsFramework::AssetBrowser::ProductAssetBrowserEntry* productEntry = static_cast<const AzToolsFramework::AssetBrowser::ProductAssetBrowserEntry*>(entry);
const AZ::Data::AssetId& assetId = productEntry->GetAssetId();
if (productEntry->GetAssetType() == azrtti_typeid<ScriptCanvasFunctionAsset>())
const auto entryType = productEntry->GetAssetType();
if (entryType == azrtti_typeid<ScriptCanvas::SubgraphInterfaceAsset>())
{
auto elementIter = m_globalFunctionTreeItems.find(assetId.m_guid);
const AZ::Data::AssetId& assetId = productEntry->GetAssetId();
auto elementIter = m_globalFunctionTreeItems.find(assetId);
if (elementIter == m_globalFunctionTreeItems.end())
{
RequestAssetLoad(assetId, azrtti_typeid<ScriptCanvasFunctionAsset>());
}
}
else if (productEntry->GetAssetType() == azrtti_typeid<ScriptCanvas::SubgraphInterfaceAsset>())
{
auto elementIter = m_globalFunctionTreeItems.find(assetId.m_guid);
if (elementIter == m_globalFunctionTreeItems.end())
{
RequestAssetLoad(assetId, azrtti_typeid<ScriptCanvas::SubgraphInterfaceAsset>());
RequestAssetLoad(assetId, productEntry->GetAssetType());
}
else
{
elementIter->second->SetRuntimeAssetId(assetId);
elementIter->second->ClearError();
if (elementIter->second->HasError())
{
m_pendingAssets.erase(assetId);
RequestAssetLoad(assetId, productEntry->GetAssetType());
}
}
}
else if (productEntry->GetAssetType() == azrtti_typeid<ScriptEvents::ScriptEventsAsset>())
else if (entryType == azrtti_typeid<ScriptEvents::ScriptEventsAsset>())
{
const AZ::Data::AssetId& assetId = productEntry->GetAssetId();
auto elementIter = m_scriptEventElementTreeItems.find(assetId.m_guid);
if (elementIter == m_scriptEventElementTreeItems.end())
{
RequestAssetLoad(assetId, azrtti_typeid<ScriptEvents::ScriptEventsAsset>());
RequestAssetLoad(assetId, productEntry->GetAssetType());
}
}
}
@@ -376,17 +348,15 @@ namespace ScriptCanvasEditor
{
AZ::SystemTickBus::Handler::BusDisconnect();
while (!m_queuedLoads.empty())
while (!m_requestQueue.empty())
{
auto entry = m_queuedLoads.front();
m_queuedLoads.erase(m_queuedLoads.begin());
const auto entry = m_requestQueue.front();
m_requestQueue.pop();
if (m_pendingAssets.find(entry) == m_pendingAssets.end())
if (m_pendingAssets.find(entry.first) == m_pendingAssets.end())
{
m_pendingAssets.insert(entry);
AZ::Data::AssetBus::MultiHandler::BusConnect(entry.first);
AZ::Data::AssetManager::Instance().GetAsset(entry.first, entry.second, AZ::Data::AssetLoadBehavior::Default);
m_pendingAssets[entry.first] = AZ::Data::AssetManager::Instance().GetAsset(entry.first, entry.second, AZ::Data::AssetLoadBehavior::Default);
}
}
}
@@ -394,28 +364,28 @@ namespace ScriptCanvasEditor
void ScriptCanvasRootPaletteTreeItem::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId)
{
auto scriptEventIter = m_scriptEventElementTreeItems.find(assetId.m_guid);
if (scriptEventIter != m_scriptEventElementTreeItems.end())
{
RequestAssetLoad(assetId, azrtti_typeid<ScriptEvents::ScriptEventsAsset>());
}
else
{
AZ::Data::AssetType assetType = azrtti_typeid<ScriptCanvasFunctionAsset>();
auto elementIter = m_globalFunctionTreeItems.find(assetId.m_guid);
if (m_runtimeAssets.count(assetId) > 0)
auto functionIter = m_globalFunctionTreeItems.find(assetId);
if (functionIter != m_globalFunctionTreeItems.end())
{
assetType = azrtti_typeid<ScriptCanvas::SubgraphInterfaceAsset>();
}
if (elementIter != m_globalFunctionTreeItems.end())
{
RequestAssetLoad(assetId, assetType);
RequestAssetLoad(assetId, azrtti_typeid<ScriptCanvas::SubgraphInterfaceAsset>());
}
}
}
void ScriptCanvasRootPaletteTreeItem::OnCatalogAssetAdded(const AZ::Data::AssetId&)
{
}
void ScriptCanvasRootPaletteTreeItem::OnCatalogAssetRemoved(const AZ::Data::AssetId&, const AZ::Data::AssetInfo&)
{
}
void ScriptCanvasRootPaletteTreeItem::OnUpgradeStart()
{
DisconnectLambdas();
@@ -450,15 +420,20 @@ namespace ScriptCanvasEditor
{
// Delay handling loads until the top of the next tick in case we are handling this on an asset callback thread to avoid potential deadlocks.
AZ::SystemTickBus::Handler::BusConnect();
m_queuedLoads.emplace_back(AZStd::make_pair(assetId, assetType));
m_requestQueue.emplace(AZStd::make_pair(assetId, assetType));
}
void ScriptCanvasRootPaletteTreeItem::OnAssetError(AZ::Data::Asset<AZ::Data::AssetData> asset)
{
// mark the function on error... if possible
AZ::Data::AssetId assetId = asset.GetId();
m_pendingAssets.erase(assetId);
}
void ScriptCanvasRootPaletteTreeItem::OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset)
{
AZ::Data::AssetId assetId = asset.GetId();
m_pendingAssets.erase(AZStd::make_pair(assetId, asset.GetType()));
AZ::Data::AssetBus::MultiHandler::BusDisconnect(assetId);
m_pendingAssets.erase(assetId);
if (asset.GetType() == azrtti_typeid<ScriptEvents::ScriptEventsAsset>())
{
@@ -480,125 +455,193 @@ namespace ScriptCanvasEditor
}
else if (asset.GetType() == azrtti_typeid<ScriptCanvas::SubgraphInterfaceAsset>())
{
ScriptCanvas::SubgraphInterfaceAsset* data = asset.GetAs<ScriptCanvas::SubgraphInterfaceAsset>();
AZStd::string rootPath, absolutePath;
AZ::Data::AssetInfo assetInfo = AssetHelpers::GetAssetInfo(assetId, rootPath);
AzFramework::StringFunc::Path::Join(rootPath.c_str(), assetInfo.m_relativePath.c_str(), absolutePath);
AZ::Data::AssetId sourceAssetId;
AZStd::string normPath = absolutePath;
AzFramework::StringFunc::Path::Normalize(normPath);
AZStd::string watchFolder;
bool sourceInfoFound{};
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, normPath.c_str(), assetInfo, watchFolder);
if (!sourceInfoFound)
{
// TODO-LS: report the problem
return;
}
sourceAssetId = assetInfo.m_assetId;
AZ::Data::AssetId runtimeAssetId = asset.GetId();
if (m_runtimeAssets.count(runtimeAssetId) == 0)
{
m_runtimeAssets.insert(runtimeAssetId);
auto treePaletteIter = m_globalFunctionTreeItems.find(sourceAssetId.m_guid);
if (treePaletteIter == m_globalFunctionTreeItems.end())
{
CreateFunctionPaletteItem(data->m_runtimeData.m_name, assetInfo, sourceAssetId, runtimeAssetId);
}
else
{
treePaletteIter->second->SetRuntimeAssetId(runtimeAssetId);
treePaletteIter->second->ClearError();
}
}
}
else if (asset.GetType() == azrtti_typeid<ScriptCanvasFunctionAsset>())
{
ScriptCanvasFunctionAsset* data = asset.GetAs<ScriptCanvasFunctionAsset>();
AZStd::string rootPath, absolutePath;
AZ::Data::AssetInfo assetInfo = AssetHelpers::GetAssetInfo(assetId, rootPath);
AzFramework::StringFunc::Path::Join(rootPath.c_str(), assetInfo.m_relativePath.c_str(), absolutePath);
AZ::Data::AssetId sourceAssetId;
AZStd::string normPath = absolutePath;
AzFramework::StringFunc::Path::Normalize(normPath);
AZStd::string watchFolder;
bool sourceInfoFound{};
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, normPath.c_str(), assetInfo, watchFolder);
if (!sourceInfoFound)
{
return;
}
sourceAssetId = assetInfo.m_assetId;
// We only need to add
auto treePaletteIter = m_globalFunctionTreeItems.find(sourceAssetId.m_guid);
// We only need to add
auto treePaletteIter = m_globalFunctionTreeItems.find(asset->GetId());
if (treePaletteIter == m_globalFunctionTreeItems.end())
{
CreateFunctionPaletteItem(data->GetFunctionData()->GetPrettyName(), assetInfo, sourceAssetId);
ScriptCanvas::SubgraphInterfaceAsset* data = asset.GetAs<ScriptCanvas::SubgraphInterfaceAsset>();
if (!data)
{
return;
}
treePaletteIter = m_globalFunctionTreeItems.find(sourceAssetId.m_guid);
if (!data->m_runtimeData.m_interface.HasAnyFunctionality())
{
// check for deleting the old entry
return;
}
AZStd::string rootPath, absolutePath;
AZ::Data::AssetInfo assetInfo = AssetHelpers::GetAssetInfo(assetId, rootPath);
AzFramework::StringFunc::Path::Join(rootPath.c_str(), assetInfo.m_relativePath.c_str(), absolutePath);
AZStd::string normPath = absolutePath;
AzFramework::StringFunc::Path::Normalize(normPath);
AZStd::string watchFolder;
bool sourceInfoFound{};
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, normPath.c_str(), assetInfo, watchFolder);
if (!sourceInfoFound)
{
return;
}
CreateFunctionPaletteItem(asset, assetInfo);
treePaletteIter = m_globalFunctionTreeItems.find(asset->GetId());
if (treePaletteIter != m_globalFunctionTreeItems.end())
{
treePaletteIter->second->SetError("Function has errors and cannot be created until these errors are resolved.");
treePaletteIter->second->ClearError();
}
m_monitoredAssets.emplace(asset->GetId(), asset);
}
else
{
RequestBuildChildrenFromSubgraphInterface(treePaletteIter->second, asset);
treePaletteIter->second->ClearError();
}
}
}
void ScriptCanvasRootPaletteTreeItem::OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset)
{
OnAssetReady(asset);
}
bool ScriptCanvasRootPaletteTreeItem::HasAssetTreeItem(AZ::Data::AssetId assetId) const
{
return m_scriptEventElementTreeItems.find(assetId) != m_scriptEventElementTreeItems.end()
|| m_globalFunctionTreeItems.find(assetId) != m_globalFunctionTreeItems.end();
}
void ScriptCanvasRootPaletteTreeItem::CreateFunctionPaletteItem(const AZStd::string& displayName, const AZ::Data::AssetInfo& assetInfo, const AZ::Data::AssetId& sourceId, const AZ::Data::AssetId& runtimeId)
void ScriptCanvasRootPaletteTreeItem::CreateFunctionPaletteItem(AZ::Data::Asset<AZ::Data::AssetData> asset, const AZ::Data::AssetInfo& assetInfo)
{
ScriptCanvas::SubgraphInterfaceAsset* data = asset.GetAs<ScriptCanvas::SubgraphInterfaceAsset>();
if (!data)
{
return;
}
const ScriptCanvas::Grammar::SubgraphInterface& graphInterface = data->m_runtimeData.m_interface;
if (!graphInterface.HasAnyFunctionality())
{
return;
}
AZStd::string name;
AzFramework::StringFunc::Path::GetFileName(assetInfo.m_relativePath.c_str(), name);
AZStd::string prettyName = displayName;
AZStd::string category = "User Functions";
AZStd::string category = "Global Functions";
AZStd::string relativePath;
if (AzFramework::StringFunc::Path::GetFolderPath(assetInfo.m_relativePath.c_str(), relativePath))
{
AZStd::to_lower(relativePath.begin(), relativePath.end());
const AZStd::string root = "scriptcanvas/functions/";
if (relativePath.starts_with(root))
auto stripPathStart = [&](const AZStd::string root)
{
relativePath = relativePath.substr(root.size(), relativePath.size() - root.size());
}
if (relativePath.starts_with(root))
{
relativePath = relativePath.substr(root.size(), relativePath.size() - root.size());
}
};
stripPathStart("scriptcanvas/functions");
stripPathStart("scriptcanvas");
stripPathStart("/");
category.append("/");
category.append(relativePath);
}
GraphCanvas::NodePaletteTreeItem* categoryRoot = GetCategoryNode(category.c_str());
FunctionPaletteTreeItem* treeItem = categoryRoot->CreateChildNode<FunctionPaletteTreeItem>(prettyName.empty() ? name.c_str() : prettyName.c_str(), sourceId, runtimeId);
NodePaletteTreeItem* categoryRoot = GetCategoryNode(category.c_str());
auto functionCategory = categoryRoot->CreateChildNode<NodePaletteTreeItem>(name.c_str(), ScriptCanvasEditor::AssetEditorId);
RequestBuildChildrenFromSubgraphInterface(functionCategory, asset);
m_globalFunctionTreeItems[asset->GetId()] = functionCategory;
categoryRoot->SetEnabled(true);
}
if (treeItem)
void ScriptCanvasRootPaletteTreeItem::RequestBuildChildrenFromSubgraphInterface(NodePaletteTreeItem* functionCategory, AZ::Data::Asset<AZ::Data::AssetData> asset)
{
functionCategory->ClearChildren();
ScriptCanvas::SubgraphInterfaceAsset* data = asset.GetAs<ScriptCanvas::SubgraphInterfaceAsset>();
if (!data)
{
m_globalFunctionTreeItems[sourceId.m_guid] = treeItem;
treeItem->SetEnabled(!m_isFunctionGraphActive);
return;
}
const ScriptCanvas::Grammar::SubgraphInterface& graphInterface = data->m_runtimeData.m_interface;
if (!graphInterface.HasAnyFunctionality())
{
return;
}
auto parent = functionCategory;
parent->SetEnabled(true);
if (graphInterface.IsUserNodeable())
{
auto name = functionCategory->GetName().toUtf8().constData();
parent = parent->CreateChildNode<FunctionPaletteTreeItem>(AZStd::string::format("%s Node", name).c_str(), ScriptCanvas::Grammar::MakeFunctionSourceIdNodeable(), asset);
parent->SetEnabled(true);
}
if (graphInterface.IsMarkedPure())
{
for (auto& in : graphInterface.GetIns())
{
auto childNode = parent->CreateChildNode<FunctionPaletteTreeItem>(in.displayName.c_str(), in.sourceID, asset);
childNode->SetEnabled(true);
}
}
else
{
auto& ins = graphInterface.GetIns();
AZStd::vector<const ScriptCanvas::Grammar::In*> onNodeIns;
AZStd::vector<const ScriptCanvas::Grammar::In*> pureIns;
auto onNodeParent = parent;
auto pureParent = functionCategory;
for (auto& in : ins)
{
if (in.isPure)
{
pureIns.push_back(&in);
}
else
{
onNodeIns.push_back(&in);
}
}
if (!onNodeIns.empty())
{
parent->SetEnabled(true);
for (auto in : onNodeIns)
{
auto childNode = parent->CreateChildNode<NodePaletteTreeItem>(in->displayName.c_str(), ScriptCanvasEditor::AssetEditorId);
childNode->SetEnabled(true);
}
}
if (!pureIns.empty())
{
parent = pureParent->CreateChildNode<NodePaletteTreeItem>("Pure Functions", ScriptCanvasEditor::AssetEditorId);
parent->SetEnabled(true);
for (auto in : pureIns)
{
auto childNode = parent->CreateChildNode<FunctionPaletteTreeItem>(in->displayName.c_str(), in->sourceID, asset);
childNode->SetEnabled(true);
}
}
}
}
@@ -643,9 +686,6 @@ namespace ScriptCanvasEditor
auto scriptEventAction = creationMenu->addAction("New Script Event");
QObject::connect(scriptEventAction, &QAction::triggered, this, &NodePaletteDockWidget::OnNewCustomEvent);
auto functionAction = creationMenu->addAction("New Function");
QObject::connect(functionAction, &QAction::triggered, this, &NodePaletteDockWidget::OnNewFunctionEvent);
m_newCustomEvent = new QToolButton(this);
m_newCustomEvent->setIcon(QIcon(":/ScriptCanvasEditorResources/Resources/add.png"));
m_newCustomEvent->setToolTip("Click to create a new Script Event or Function");
@@ -696,11 +736,6 @@ namespace ScriptCanvasEditor
AzToolsFramework::AssetEditor::AssetEditorRequestsBus::Broadcast(&AzToolsFramework::AssetEditor::AssetEditorRequests::CreateNewAsset, azrtti_typeid<ScriptEvents::ScriptEventsAsset>());
}
void NodePaletteDockWidget::OnNewFunctionEvent()
{
GeneralRequestBus::Broadcast(&GeneralRequests::CreateNewFunctionAsset);
}
void NodePaletteDockWidget::OnActiveGraphChanged(const GraphCanvas::GraphId& graphCanvasGraphId)
{
GraphCanvas::SceneNotificationBus::Handler::BusDisconnect();
@@ -89,7 +89,9 @@ namespace ScriptCanvasEditor
////
// AssetCatalogEventBus
void OnCatalogAssetChanged(const AZ::Data::AssetId& /*assetId*/) override;
void OnCatalogAssetChanged(const AZ::Data::AssetId&) override;
void OnCatalogAssetAdded(const AZ::Data::AssetId&) override;
void OnCatalogAssetRemoved(const AZ::Data::AssetId&, const AZ::Data::AssetInfo&) override;
////
// UpgradeNotifications::Bus
@@ -104,30 +106,35 @@ namespace ScriptCanvasEditor
// Requests an async load of a given asset of a type
void RequestAssetLoad(AZ::Data::AssetId assetId, AZ::Data::AssetType assetType);
// When the asset loading is ready, this allows to use the asset in some meaningful way
void OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
void OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
void OnAssetError(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
bool HasAssetTreeItem(AZ::Data::AssetId assetId) const;
void CreateFunctionPaletteItem(const AZStd::string& displayName, const AZ::Data::AssetInfo& assetInfo, const AZ::Data::AssetId& sourceId, const AZ::Data::AssetId& runtimeId = {});
void CreateFunctionPaletteItem(AZ::Data::Asset<AZ::Data::AssetData> asset, const AZ::Data::AssetInfo& assetInfo);
void RequestBuildChildrenFromSubgraphInterface(NodePaletteTreeItem* item, AZ::Data::Asset<AZ::Data::AssetData> asset);
const NodePaletteModel& m_nodePaletteModel;
AzToolsFramework::AssetBrowser::AssetBrowserFilterModel* m_assetModel;
GraphCanvas::GraphCanvasTreeCategorizer m_categorizer;
bool m_isFunctionGraphActive;
AZ::Data::AssetId m_previousAssetId;
AZStd::unordered_map< AZ::Data::AssetId, ScriptEventsPaletteTreeItem* > m_scriptEventElementTreeItems;
AZStd::unordered_set< AZ::Data::AssetId > m_runtimeAssets;
AZStd::unordered_map< AZ::Data::AssetId, FunctionPaletteTreeItem* > m_globalFunctionTreeItems;
AZStd::unordered_map< AZ::Data::AssetId, GraphCanvas::NodePaletteTreeItem*> m_globalFunctionTreeItems;
AZStd::vector< AZStd::pair<AZ::Data::AssetId, AZ::Data::AssetType>> m_queuedLoads;
AZStd::queue<AZStd::pair<AZ::Data::AssetId, AZ::Data::AssetType>> m_requestQueue;
// RequestAssetLoad uses this set to track assets being asynchronously loaded
AZStd::unordered_set<AZStd::pair<AZ::Data::AssetId, AZ::Data::AssetType>> m_pendingAssets;
AZStd::unordered_map<AZ::Data::AssetId, AZ::Data::Asset<AZ::Data::AssetData>> m_pendingAssets;
AZStd::unordered_map< AZ::Data::AssetId, AZ::Data::Asset<AZ::Data::AssetData>> m_monitoredAssets;
AZStd::vector< QMetaObject::Connection > m_lambdaConnections;
};
@@ -40,8 +40,20 @@
#include <ScriptCanvas/Bus/RequestBus.h>
#include <ScriptCanvas/Bus/EditorScriptCanvasBus.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
namespace ScriptCanvasEditor
{
const char* GraphVariablesModel::m_columnNames[static_cast<int>(ColumnIndex::Count)] =
{
"Name",
"Type",
"Default Value",
"Scope",
"Initial Value"
};
////////////////////////
// GraphVariablesModel
////////////////////////
@@ -137,6 +149,16 @@ namespace ScriptCanvasEditor
return ScriptCanvas::VariableFlags::GetScopeDisplayLabel(graphVariable->GetScope());
}
}
else if (index.column() == ColumnIndex::InitialValueSource)
{
ScriptCanvas::GraphVariable* graphVariable = nullptr;
ScriptCanvas::GraphVariableManagerRequestBus::EventResult(graphVariable, m_scriptCanvasId, &ScriptCanvas::GraphVariableManagerRequests::FindVariableById, varId.m_identifier);
if (graphVariable)
{
return graphVariable->GetInitialValueSourceName().data();
}
}
}
break;
@@ -232,6 +254,16 @@ namespace ScriptCanvasEditor
return ScriptCanvas::VariableFlags::GetScopeDisplayLabel(graphVariable->GetScope());
}
}
else if (index.column() == ColumnIndex::InitialValueSource)
{
ScriptCanvas::GraphVariable* graphVariable = nullptr;
ScriptCanvas::GraphVariableManagerRequestBus::EventResult(graphVariable, m_scriptCanvasId, &ScriptCanvas::GraphVariableManagerRequests::FindVariableById, varId.m_identifier);
if (graphVariable)
{
return graphVariable->GetInitialValueSourceName().data();
}
}
}
break;
@@ -281,6 +313,19 @@ namespace ScriptCanvasEditor
return QVariant(type.c_str());
}
}
else if (index.column() == ColumnIndex::InitialValueSource)
{
ScriptCanvas::GraphVariable* graphVariable = nullptr;
ScriptCanvas::GraphVariableManagerRequestBus::EventResult(graphVariable, m_scriptCanvasId, &ScriptCanvas::GraphVariableManagerRequests::FindVariableById, varId.m_identifier);
QString tooltipString = QString("The value of this variable can only be set within this graph");
if (graphVariable->GetInitialValueSource() == ScriptCanvas::VariableFlags::InitialValueSource::Component)
{
tooltipString = QString("The value of this variable can be set set on the component's properties");
}
return tooltipString;
}
else
{
AZStd::string variableName;
@@ -296,6 +341,7 @@ namespace ScriptCanvasEditor
return tooltipString;
}
}
break;
case Qt::DecorationRole:
@@ -381,22 +427,17 @@ namespace ScriptCanvasEditor
{
if (index.column() == ColumnIndex::Scope)
{
if (IsFunction())
{
return QStringList{
ScriptCanvas::VariableFlags::GetScopeDisplayLabel(ScriptCanvas::VariableFlags::Scope::Local),
ScriptCanvas::VariableFlags::GetScopeDisplayLabel(ScriptCanvas::VariableFlags::Scope::Input),
ScriptCanvas::VariableFlags::GetScopeDisplayLabel(ScriptCanvas::VariableFlags::Scope::Output),
ScriptCanvas::VariableFlags::GetScopeDisplayLabel(ScriptCanvas::VariableFlags::Scope::InOut)
};
}
else
{
return QStringList{
ScriptCanvas::VariableFlags::GetScopeDisplayLabel(ScriptCanvas::VariableFlags::Scope::Local),
ScriptCanvas::VariableFlags::GetScopeDisplayLabel(ScriptCanvas::VariableFlags::Scope::Input)
};
}
return QStringList{
ScriptCanvas::VariableFlags::GetScopeDisplayLabel(ScriptCanvas::VariableFlags::Scope::Graph),
ScriptCanvas::VariableFlags::GetScopeDisplayLabel(ScriptCanvas::VariableFlags::Scope::Function)
};
}
else if (index.column() == ColumnIndex::InitialValueSource)
{
return QStringList{
tr(ScriptCanvas::GraphVariable::s_InitialValueSourceNames[0]),
tr(ScriptCanvas::GraphVariable::s_InitialValueSourceNames[1])
};
}
}
break;
@@ -496,22 +537,25 @@ namespace ScriptCanvasEditor
}
}
else if (index.column() == ColumnIndex::Scope)
{
// Scope is not changed by users
}
else if (index.column() == ColumnIndex::InitialValueSource)
{
ScriptCanvas::GraphVariable* graphVariable = nullptr;
ScriptCanvas::GraphVariableManagerRequestBus::EventResult(graphVariable, m_scriptCanvasId, &ScriptCanvas::GraphVariableManagerRequests::FindVariableById, varId.m_identifier);
if (graphVariable)
{
QString exposureValue = value.toString();
QString comboBoxValue = value.toString();
if (!exposureValue.isEmpty())
if (!comboBoxValue.isEmpty())
{
ScriptCanvas::VariableFlags::Scope newScope = ScriptCanvas::VariableFlags::GetScopeFromLabel(exposureValue.toUtf8().data());
if (graphVariable->GetScope() != newScope)
if (graphVariable->GetInitialValueSourceName().compare(comboBoxValue.toUtf8().data()) != 0)
{
modifiedData = true;
graphVariable->SetScope(newScope);
graphVariable->SetInitialValueSourceFromName(comboBoxValue.toUtf8().data());
AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&AzToolsFramework::PropertyEditorGUIMessages::RequestRefresh, AzToolsFramework::Refresh_EntireTree);
}
}
}
@@ -563,8 +607,11 @@ namespace ScriptCanvasEditor
}
else if (index.column() == ColumnIndex::Scope)
{
// Disabling the editing column temporarily, since the combo box doesn't work.
//itemFlags |= Qt::ItemIsEditable;
itemFlags |= Qt::ItemIsEditable;
}
else if (index.column() == ColumnIndex::InitialValueSource)
{
itemFlags |= Qt::ItemIsEditable;
}
return itemFlags;
@@ -778,6 +825,19 @@ namespace ScriptCanvasEditor
}
}
void GraphVariablesModel::OnVariableInitialValueSourceChanged()
{
const ScriptCanvas::GraphScopedVariableId* variableId = ScriptCanvas::VariableNotificationBus::GetCurrentBusId();
int index = FindRowForVariableId((*variableId).m_identifier);
if (index >= 0)
{
QModelIndex modelIndex = createIndex(index, ColumnIndex::InitialValueSource, nullptr);
dataChanged(modelIndex, modelIndex);
}
}
void GraphVariablesModel::OnVariablePriorityChanged()
{
const ScriptCanvas::GraphScopedVariableId* variableId = ScriptCanvas::VariableNotificationBus::GetCurrentBusId();
@@ -793,6 +853,16 @@ namespace ScriptCanvasEditor
}
}
QVariant GraphVariablesModel::headerData(int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole*/) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
{
return tr(m_columnNames[section]);
}
return QAbstractItemModel::headerData(section, orientation, role);
}
ScriptCanvas::VariableId GraphVariablesModel::FindVariableIdForIndex(const QModelIndex& index) const
{
ScriptCanvas::VariableId variableId;
@@ -977,20 +1047,7 @@ namespace ScriptCanvasEditor
for (auto variableMapData : copiedVariableData.m_variableMapping)
{
AZ::Outcome<ScriptCanvas::VariableId, AZStd::string> variableOutcome = requests->CloneVariable(variableMapData.second);
if (isRuntimeGraph)
{
if (variableOutcome)
{
ScriptCanvas::GraphVariable* variable = requests->FindVariableById(variableOutcome.GetValue());
if (variable)
{
variable->RemoveScope(ScriptCanvas::VariableFlags::Scope::Output);
}
}
}
requests->CloneVariable(variableMapData.second);
}
GeneralRequestBus::Broadcast(&GeneralRequests::PopPreventUndoStateUpdate);
@@ -1015,12 +1072,15 @@ namespace ScriptCanvasEditor
ApplyPreferenceSort();
setItemDelegateForColumn(GraphVariablesModel::Name, aznew GraphCanvas::IconDecoratedNameDelegate(this));
setItemDelegateForColumn(GraphVariablesModel::Scope, aznew GraphCanvas::GenericComboBoxDelegate(this));
setItemDelegateForColumn(GraphVariablesModel::InitialValueSource, aznew GraphCanvas::GenericComboBoxDelegate(this));
horizontalHeader()->setStretchLastSection(false);
horizontalHeader()->setSectionResizeMode(GraphVariablesModel::Type, QHeaderView::ResizeMode::Fixed);
horizontalHeader()->setSectionResizeMode(GraphVariablesModel::Name, QHeaderView::ResizeMode::Stretch);
horizontalHeader()->setSectionResizeMode(GraphVariablesModel::DefaultValue, QHeaderView::ResizeMode::Fixed);
horizontalHeader()->setSectionResizeMode(GraphVariablesModel::Scope, QHeaderView::ResizeMode::Fixed);
horizontalHeader()->setSectionResizeMode(GraphVariablesModel::Name, QHeaderView::ResizeMode::ResizeToContents);
horizontalHeader()->setSectionResizeMode(GraphVariablesModel::DefaultValue, QHeaderView::ResizeMode::ResizeToContents);
horizontalHeader()->setSectionResizeMode(GraphVariablesModel::Type, QHeaderView::ResizeMode::Stretch);
horizontalHeader()->setSectionResizeMode(GraphVariablesModel::Scope, QHeaderView::ResizeMode::Stretch);
horizontalHeader()->setSectionResizeMode(GraphVariablesModel::InitialValueSource, QHeaderView::ResizeMode::Stretch);
horizontalHeader()->show();
{
QAction* deleteAction = new QAction(this);
@@ -1229,16 +1289,18 @@ namespace ScriptCanvasEditor
horizontalHeader()->resizeSection(GraphVariablesModel::Type, typeLength);
horizontalHeader()->resizeSection(GraphVariablesModel::DefaultValue, defaultValueLength);
int exposureLength = aznumeric_cast<int>(availableWidth * 0.2f);
int maxExposureLength = 60;
if (exposureLength >= 60)
horizontalHeader()->resizeSection(GraphVariablesModel::Scope, 100);
int remainingLength = aznumeric_cast<int>(availableWidth * 0.1f);
int maxExposureLength = 80;
if (remainingLength >= maxExposureLength)
{
exposureLength = 60;
remainingLength = maxExposureLength;
}
horizontalHeader()->resizeSection(GraphVariablesModel::Scope, exposureLength);
horizontalHeader()->resizeSection(GraphVariablesModel::InitialValueSource, 120);
}
void GraphVariablesTableView::OnCopySelected()
@@ -45,9 +45,12 @@ namespace ScriptCanvasEditor
Type,
DefaultValue,
Scope,
InitialValueSource,
Count
};
static const char* m_columnNames[static_cast<int>(ColumnIndex::Count)];
enum CustomRole
{
VarIdRole = Qt::UserRole
@@ -84,9 +87,13 @@ namespace ScriptCanvasEditor
// ScriptCanvas::VariableRuntimeNotificationBus
void OnVariableValueChanged() override;
void OnVariableScopeChanged() override;
void OnVariableInitialValueSourceChanged() override;
void OnVariablePriorityChanged() override;
////
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
ScriptCanvas::VariableId FindVariableIdForIndex(const QModelIndex& index) const;
ScriptCanvas::GraphScopedVariableId FindScopedVariableIdForIndex(const QModelIndex& index) const;
@@ -0,0 +1,233 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <precompiled.h>
#include <QAction>
#include <QCompleter>
#include <QEvent>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QAction>
#include <QMenu>
#include <QMessageBox>
#include <QScopedValueRollback>
#include <QLineEdit>
#include <QTimer>
#include <QPushButton>
#include <QHeaderView>
#include <AzCore/Component/ComponentApplication.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/UserSettings/UserSettings.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzToolsFramework/Entity/EditorEntityContextPickingBus.h>
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
#include <GraphCanvas/Components/VisualBus.h>
#include <GraphCanvas/Components/SceneBus.h>
#include <GraphCanvas/Components/StyleBus.h>
#include <Editor/View/Widgets/VariablePanel/SlotTypeSelectorWidget.h>
#include <Editor/View/Widgets/VariablePanel/ui_SlotTypeSelectorWidget.h>
#include <Data/Data.h>
#include <Editor/Assets/ScriptCanvasAssetTrackerBus.h>
#include <Editor/GraphCanvas/GraphCanvasEditorNotificationBusId.h>
#include <Editor/QtMetaTypes.h>
#include <Editor/Settings.h>
#include <Editor/Translation/TranslationHelper.h>
#include <Editor/View/Widgets/DataTypePalette/DataTypePaletteModel.h>
#include <Editor/View/Widgets/NodePalette/VariableNodePaletteTreeItemTypes.h>
#include <Editor/View/Widgets/PropertyGridBus.h>
#include <Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h>
#include <Editor/Include/ScriptCanvas/GraphCanvas/NodeDescriptorBus.h>
#include <ScriptCanvas/Core/NodeBus.h>
#include <ScriptCanvas/Data/DataRegistry.h>
#include <ScriptCanvas/Execution/RuntimeBus.h>
#include <ScriptCanvas/GraphCanvas/NodeDescriptorBus.h>
#include <ScriptCanvas/Asset/RuntimeAsset.h>
namespace ScriptCanvasEditor
{
///////////////////////
// SlotTypeSelectorWidget
///////////////////////
SlotTypeSelectorWidget::SlotTypeSelectorWidget(const ScriptCanvas::ScriptCanvasId& scriptCanvasId, QWidget* parent /*= nullptr*/)
: AzQtComponents::StyledDialog(parent)
, m_manipulatingSelection(false)
, ui(new Ui::SlotTypeSelectorWidget())
, m_scriptCanvasId(scriptCanvasId)
{
ui->setupUi(this);
ui->searchFilter->setClearButtonEnabled(true);
QObject::connect(ui->searchFilter, &QLineEdit::textChanged, this, &SlotTypeSelectorWidget::OnQuickFilterChanged);
QObject::connect(ui->slotName, &QLineEdit::returnPressed, this, &SlotTypeSelectorWidget::OnReturnPressed);
QObject::connect(ui->slotName, &QLineEdit::textChanged, this, &SlotTypeSelectorWidget::OnNameChanged);
QObject::connect(ui->variablePalette, &QTableView::clicked, this, [this]() { ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); });
// Tell the widget to auto create our context menu, for now
setContextMenuPolicy(Qt::ActionsContextMenu);
ui->searchFilter->setEnabled(true);
QObject::connect(ui->variablePalette, &VariablePaletteTableView::CreateVariable, this, &SlotTypeSelectorWidget::OnCreateVariable);
m_filterTimer.setInterval(250);
m_filterTimer.setSingleShot(true);
m_filterTimer.stop();
QObject::connect(&m_filterTimer, &QTimer::timeout, this, &SlotTypeSelectorWidget::UpdateFilter);
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
}
SlotTypeSelectorWidget::~SlotTypeSelectorWidget()
{
}
void SlotTypeSelectorWidget::PopulateVariablePalette(const AZStd::unordered_set< AZ::Uuid >& objectTypes)
{
ui->variablePalette->PopulateVariablePalette(objectTypes);
}
void SlotTypeSelectorWidget::OnEscape()
{
reject();
}
void SlotTypeSelectorWidget::focusOutEvent(QFocusEvent* )
{
reject();
}
const ScriptCanvas::ScriptCanvasId& SlotTypeSelectorWidget::GetActiveScriptCanvasId() const
{
return m_scriptCanvasId;
}
void SlotTypeSelectorWidget::ShowVariablePalette()
{
ClearFilter();
ui->searchFilter->setPlaceholderText("Variable Type...");
FocusOnSearchFilter();
ui->searchFilter->setCompleter(ui->variablePalette->GetVariableCompleter());
AzToolsFramework::EditorEvents::Bus::Handler::BusConnect();
}
void SlotTypeSelectorWidget::FocusOnSearchFilter()
{
ui->searchFilter->setFocus(Qt::FocusReason::MouseFocusReason);
}
void SlotTypeSelectorWidget::ClearFilter()
{
{
QSignalBlocker blocker(ui->searchFilter);
ui->searchFilter->setText("");
}
UpdateFilter();
}
void SlotTypeSelectorWidget::UpdateFilter()
{
ui->variablePalette->SetFilter(ui->searchFilter->userInputText());
}
void SlotTypeSelectorWidget::OnReturnPressed()
{
// Set the type to the slot
if (!m_selectedType.IsNull())
{
m_slotName = ui->slotName->text().toUtf8().data();
accept();
}
}
AZ::Uuid SlotTypeSelectorWidget::GetSelectedType() const
{
return m_selectedType;
}
AZStd::string SlotTypeSelectorWidget::GetSlotName() const
{
return m_slotName;
}
void SlotTypeSelectorWidget::SetSlotName(AZStd::string name)
{
m_slotName = name;
ui->slotName->setText(QString(name.c_str()));
}
void SlotTypeSelectorWidget::OnQuickFilterChanged(const QString& text)
{
if (text.isEmpty())
{
//If field was cleared, update immediately
UpdateFilter();
return;
}
m_filterTimer.stop();
m_filterTimer.start();
}
void SlotTypeSelectorWidget::OnNameChanged(const QString& text)
{
bool nameInUse = false;
const AZStd::unordered_map<ScriptCanvas::VariableId, ScriptCanvas::GraphVariable>* properties = nullptr;
ScriptCanvas::GraphVariableManagerRequestBus::EventResult(properties, m_scriptCanvasId, &ScriptCanvas::GraphVariableManagerRequests::GetVariables);
if (properties)
{
for (const auto& variablePair : (*properties))
{
AZStd::string testName = text.toUtf8().data();
if (testName.compare(variablePair.second.GetVariableName()) == 0)
{
nameInUse = true;
break;
}
}
}
m_slotName = text.toUtf8().data();
if (nameInUse)
{
m_slotName.append(" (duplicate)");
ui->slotName->setText(m_slotName.c_str());
}
}
void SlotTypeSelectorWidget::OnContextMenuRequested(const QPoint&)
{
}
void SlotTypeSelectorWidget::OnCreateVariable(ScriptCanvas::Data::Type varType)
{
m_selectedType = varType.GetAZType();
}
#include <Editor/View/Widgets/VariablePanel/moc_SlotTypeSelectorWidget.cpp>
}
@@ -0,0 +1,131 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzCore/PlatformDef.h>
#include <QAbstractListModel>
#include <QAbstractItemView>
#include <QListView>
#include <QVBoxLayout>
#include <QHeaderView>
#include <QTimer>
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include <QFocusEvent>
#include <QMenu>
#include <AzCore/Component/EntityId.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/Casting/numeric_cast.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzQtComponents/Components/StyledDialog.h>
#include <GraphCanvas/Editor/AssetEditorBus.h>
#include <GraphCanvas/Components/GraphCanvasPropertyBus.h>
#include <GraphCanvas/Components/SceneBus.h>
#include <GraphCanvas/Components/Nodes/NodeBus.h>
#include <GraphCanvas/Components/Nodes/NodeTitleBus.h>
#include <GraphCanvas/Widgets/GraphCanvasTreeItem.h>
#include <GraphCanvas/Widgets/GraphCanvasTreeModel.h>
#include <ScriptCanvas/Bus/RequestBus.h>
#include <ScriptCanvas/Variable/VariableBus.h>
#include <ScriptCanvas/Variable/GraphVariable.h>
#include <Editor/View/Widgets/VariablePanel/VariablePaletteTableView.h>
#include <Editor/View/Widgets/VariablePanel/GraphVariablesTableView.h>
#endif
class QAction;
class QLineEdit;
class QPushButton;
namespace Ui
{
class SlotTypeSelectorWidget;
}
namespace ScriptCanvasEditor
{
class SlotTypeSelectorWidget
: public AzQtComponents::StyledDialog
, public AzToolsFramework::EditorEvents::Bus::Handler
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(SlotTypeSelectorWidget, AZ::SystemAllocator, 0);
SlotTypeSelectorWidget(const ScriptCanvas::ScriptCanvasId& scriptCanvasId, QWidget* parent = nullptr);
~SlotTypeSelectorWidget();
void PopulateVariablePalette(const AZStd::unordered_set< AZ::Uuid >& objectTypes);
// AzToolsFramework::EditorEvents::Bus
void OnEscape() override;
////
// QWidget
void focusOutEvent(QFocusEvent* focusEvent) override;
////
AZ::Uuid GetSelectedType() const;
AZStd::string GetSlotName() const;
void SetSlotName(AZStd::string);
const ScriptCanvas::ScriptCanvasId& GetActiveScriptCanvasId() const;
public Q_SLOTS:
void OnCreateVariable(ScriptCanvas::Data::Type varType);
Q_SIGNALS:
void OnVariableSelectionChanged(const AZStd::vector<AZ::EntityId>& variableIds);
private:
void ShowVariablePalette();
void FocusOnSearchFilter();
void ClearFilter();
void UpdateFilter();
void OnReturnPressed();
void OnQuickFilterChanged(const QString& text);
void OnNameChanged(const QString& text);
void OnContextMenuRequested(const QPoint& pos);
//bool event(QEvent* ev) override;
bool m_manipulatingSelection;
AZStd::vector< AZStd::unique_ptr<AZ::Entity> > m_propertyHelpers;
ScriptCanvas::ScriptCanvasId m_scriptCanvasId;
AZ::EntityId m_graphCanvasGraphId;
AZ::Uuid m_selectedType;
AZStd::string m_slotName;
AZStd::unique_ptr<Ui::SlotTypeSelectorWidget> ui;
QTimer m_filterTimer;
};
}
@@ -0,0 +1,161 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SlotTypeSelectorWidget</class>
<widget class="QWidget" name="SlotTypeSelectorWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>278</width>
<height>316</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Pick slot name/type</string>
</property>
<property name="floating" stdset="0">
<bool>false</bool>
</property>
<widget class="QWidget" name="widgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>278</width>
<height>278</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<number>30</number>
</property>
<item>
<widget class="AzQtComponents::SearchLineEdit" name="searchFilter">
<property name="inputMask">
<string/>
</property>
<property name="placeholderText">
<string>Search...</string>
</property>
</widget>
</item>
<item>
<widget class="ScriptCanvasEditor::VariablePaletteTableView" name="variablePalette">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLineEdit" name="slotName">
<property name="placeholderText">
<string>Type the name for your slot here...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>AzQtComponents::SearchLineEdit</class>
<extends>QLineEdit</extends>
<header location="global">AzQtComponents/Components/SearchLineEdit.h</header>
</customwidget>
<customwidget>
<class>ScriptCanvasEditor::VariablePaletteTableView</class>
<extends>QTableView</extends>
<header location="global">Editor/View/Widgets/VariablePanel/VariablePaletteTableView.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SlotTypeSelectorWidget</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>77</x>
<y>294</y>
</hint>
<hint type="destinationlabel">
<x>7</x>
<y>296</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SlotTypeSelectorWidget</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
@@ -117,7 +117,7 @@ namespace ScriptCanvasEditor
{
if (variable)
{
ScriptCanvas::VariableNotificationBus::Handler::BusDisconnect();
ScriptCanvas::VariableNotificationBus::Handler::BusDisconnect();
m_variable = variable;
m_componentTitle.clear();
@@ -180,6 +180,7 @@ namespace ScriptCanvasEditor
{
GeneralRequestBus::Broadcast(&GeneralRequests::PostUndoPoint, m_scriptCanvasGraphId);
PropertyGridRequestBus::Broadcast(&PropertyGridRequests::RefreshPropertyGrid);
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues);
}
void VariablePropertiesComponent::OnVariableRenamed(AZStd::string_view variableName)
@@ -292,6 +293,8 @@ namespace ScriptCanvasEditor
dockWidget->OnDeleteVariables(variableIds);
});
addAction(getAction);
addAction(setAction);
addSeparator();
@@ -299,56 +302,6 @@ namespace ScriptCanvasEditor
addAction(pasteAction);
addAction(duplicateAction);
addAction(deleteAction);
addSeparator();
// Setup exposure options
ScriptCanvas::GraphScopedVariableId variableId;
variableId.m_scriptCanvasId = scriptCanvasId;
variableId.m_identifier = varId;
ScriptCanvas::GraphVariable* variable = nullptr;
ScriptCanvas::VariableRequestBus::EventResult(variable, variableId, &ScriptCanvas::VariableRequests::GetVariable);
AZ_Assert(variable, "The variable must exist at this point");
AZ::Data::AssetType assetType;
AssetTrackerRequestBus::BroadcastResult(assetType, &AssetTrackerRequests::GetAssetType, scriptCanvasId);
// Exposing variables is only available for Function assets
QMenu* scopeSubMenu = new QMenu(QObject::tr("Scope"), this);
QActionGroup* actionGroup = new QActionGroup(scopeSubMenu);
actionGroup->setExclusive(true);
AZStd::vector<ScriptCanvas::VariableFlags::Scope> scopes = { ScriptCanvas::VariableFlags::Scope::Local, ScriptCanvas::VariableFlags::Scope::Input };
if (assetType == azrtti_typeid<ScriptCanvasEditor::ScriptCanvasFunctionAsset >())
{
scopes.emplace_back(ScriptCanvas::VariableFlags::Scope::Output);
scopes.emplace_back(ScriptCanvas::VariableFlags::Scope::InOut);
}
for (auto scopeType : scopes)
{
QAction* exposureAction = new QAction(QObject::tr(ScriptCanvas::VariableFlags::GetScopeDisplayLabel(scopeType)), this);
exposureAction->setCheckable(true);
exposureAction->setChecked(variable->GetScope() == scopeType);
exposureAction->setActionGroup(actionGroup);
exposureAction->setToolTip(QObject::tr(ScriptCanvas::VariableFlags::GetScopeToolTip(scopeType)));
QObject::connect(exposureAction, &QAction::triggered, this, [variableId, scopeType](bool)
{
ScriptCanvas::GraphVariable* variable = nullptr;
ScriptCanvas::VariableRequestBus::EventResult(variable, variableId, &ScriptCanvas::VariableRequests::GetVariable);
if (variable)
{
variable->SetScope(scopeType);
}
});
scopeSubMenu->addAction(exposureAction);
}
addMenu(scopeSubMenu);
}
///////////////////////
@@ -79,7 +79,7 @@
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
@@ -142,6 +142,8 @@
#include <Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.h>
#include <Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.h>
#include <Editor/View/Widgets/VariablePanel/SlotTypeSelectorWidget.h>
// Save Format Conversion
#include <AzCore/Component/EntityUtils.h>
#include <Editor/Include/ScriptCanvas/Components/EditorGraph.h>
@@ -160,6 +162,7 @@
#include <Editor/QtMetaTypes.h>
#include <GraphCanvas/Components/SceneBus.h>
namespace ScriptCanvasEditor
{
using namespace AzToolsFramework;
@@ -470,8 +473,6 @@ namespace ScriptCanvasEditor
scriptEventAssetFilter->SetAssetGroup(ScriptEvents::ScriptEventsAsset::GetGroup());
scriptEventAssetFilter->SetFilterPropagation(AzToolsFramework::AssetBrowser::AssetBrowserEntryFilter::PropagateDirection::Down);
// Filter doesn't actually work for whatever reason
//m_scriptEventsAssetModel->SetFilter(AzToolsFramework::AssetBrowser::FilterConstType(scriptEventAssetFilter));
m_scriptEventsAssetModel->setSourceModel(assetBrowserModel);
}
@@ -482,8 +483,6 @@ namespace ScriptCanvasEditor
scriptCanvasAssetFilter->SetAssetGroup(ScriptCanvasAsset::Description::GetGroup(azrtti_typeid<ScriptCanvasAsset>()));
scriptCanvasAssetFilter->SetFilterPropagation(AzToolsFramework::AssetBrowser::AssetBrowserEntryFilter::PropagateDirection::Down);
// Filter doesn't actually work for whatever reason
//m_scriptCanvasAssetModel->SetFilter(AzToolsFramework::AssetBrowser::FilterConstType(scriptCanvasAssetFilter));
m_scriptCanvasAssetModel->setSourceModel(assetBrowserModel);
}
@@ -537,14 +536,6 @@ namespace ScriptCanvasEditor
m_editorToolbar->AddCreationAction(m_createScriptCanvas);
RegisterObject(AutomationIds::CreateScriptCanvasButton, m_createScriptCanvas);
m_createFunction = new QToolButton();
m_createFunction->setIcon(QIcon(ScriptCanvas::AssetDescription::GetIconPath<ScriptCanvasFunctionAsset>()));
m_createFunction->setToolTip("Creates a new Script Canvas Function Graph");
QObject::connect(m_createFunction, &QToolButton::clicked, this, &MainWindow::OnFileNewFunction);
m_editorToolbar->AddCreationAction(m_createFunction);
RegisterObject(AutomationIds::CreateScriptCanvasFunctionButton, m_createFunction);
}
{
@@ -836,11 +827,6 @@ namespace ScriptCanvasEditor
connect(ui->action_New_Script, &QAction::triggered, this, &MainWindow::OnFileNew);
ui->action_New_Script->setShortcut(QKeySequence(QKeySequence::New));
connect(ui->actionFunction, &QAction::triggered, this, &MainWindow::OnFileNewFunction);
//ui->action_New_Function->setShortcut(QKeySequence(QKeySequence::New));
connect(ui->actionEditor_Graph, &QAction::triggered, this, &MainWindow::OnFileNewFunction);
connect(ui->action_Open, &QAction::triggered, this, &MainWindow::OnFileOpen);
ui->action_Open->setShortcut(QKeySequence(QKeySequence::Open));
@@ -969,7 +955,8 @@ namespace ScriptCanvasEditor
}
}
UpdateMenuState(enabled);
UpdateMenuState(enabled);
}
void MainWindow::UpdateRecentMenu()
@@ -1159,6 +1146,44 @@ namespace ScriptCanvasEditor
return m_variableDockWidget->IsValidVariableType(dataType);
}
bool MainWindow::ShowSlotTypeSelector(ScriptCanvas::Slot* slot, const QPoint& scenePosition, VariablePaletteRequests::SlotSetup& outSetup)
{
AZ_Assert(slot, "A valid slot must be provided");
if (slot)
{
m_slotTypeSelector = new SlotTypeSelectorWidget(GetActiveScriptCanvasId(), this); // Recreate the widget every time because of https://bugreports.qt.io/browse/QTBUG-76509
m_slotTypeSelector->PopulateVariablePalette(m_variablePaletteTypes);
// Only set the slot name if the user has already configured this slot, so if they are creating
// for the first time they will see the placeholder text instead
bool isValidVariableType = false;
VariablePaletteRequestBus::BroadcastResult(isValidVariableType, &VariablePaletteRequests::IsValidVariableType, slot->GetDataType());
if (isValidVariableType)
{
m_slotTypeSelector->SetSlotName(slot->GetName());
}
m_slotTypeSelector->move(scenePosition);
m_slotTypeSelector->setEnabled(true);
m_slotTypeSelector->update();
if (m_slotTypeSelector->exec() != QDialog::Rejected)
{
outSetup.m_name = m_slotTypeSelector->GetSlotName();
outSetup.m_type = m_slotTypeSelector->GetSelectedType();
}
else
{
return false;
}
delete m_slotTypeSelector;
}
return true;
}
void MainWindow::OpenValidationPanel()
{
if (!m_validationDockWidget->isVisible())
@@ -1736,11 +1761,6 @@ namespace ScriptCanvasEditor
MakeNewFile<ScriptCanvasAsset, ScriptCanvasAssetHandler>();
}
void MainWindow::OnFileNewFunction()
{
MakeNewFile<ScriptCanvasFunctionAsset, ScriptCanvasFunctionAssetHandler>();
}
int MainWindow::InsertTabForAsset(AZStd::string_view assetPath, AZ::Data::AssetId assetId, int tabIndex)
{
int outTabIndex = -1;
@@ -3598,14 +3618,12 @@ namespace ScriptCanvasEditor
ui->action_EnableSelection->setEnabled(enabled);
ui->action_DisableSelection->setEnabled(enabled);
m_createFunctionOutput->setEnabled(enabled);
m_createFunctionInput->setEnabled(enabled);
// File Menu
ui->action_Close->setEnabled(enabled);
bool isFunctionGraph = false;
EditorGraphRequestBus::EventResult(isFunctionGraph, GetActiveScriptCanvasId(), &EditorGraphRequests::IsFunctionGraph);
m_createFunctionInput->setEnabled(isFunctionGraph && enabled);
m_createFunctionOutput->setEnabled(isFunctionGraph && enabled);
RefreshGraphPreferencesAction();
UpdateAssignToSelectionState();
@@ -3715,7 +3733,7 @@ namespace ScriptCanvasEditor
void MainWindow::CreateFunctionInput()
{
PushPreventUndoStateUpdate();
CreateExecutionNodeling(-1);
CreateFunctionDefinitionNode(-1);
PopPreventUndoStateUpdate();
PostUndoPoint(GetActiveScriptCanvasId());
@@ -3724,13 +3742,13 @@ namespace ScriptCanvasEditor
void MainWindow::CreateFunctionOutput()
{
PushPreventUndoStateUpdate();
CreateExecutionNodeling(1);
CreateFunctionDefinitionNode(1);
PopPreventUndoStateUpdate();
PostUndoPoint(GetActiveScriptCanvasId());
}
void MainWindow::CreateExecutionNodeling(int positionOffset)
void MainWindow::CreateFunctionDefinitionNode(int positionOffset)
{
ScriptCanvas::ScriptCanvasId scriptCanvasId = GetActiveScriptCanvasId();
@@ -3742,14 +3760,9 @@ namespace ScriptCanvasEditor
QRectF viewBounds;
GraphCanvas::ViewRequestBus::EventResult(viewBounds, viewId, &GraphCanvas::ViewRequests::GetCompleteArea);
AZStd::string rootName = "New Output";
if (positionOffset < 0)
{
rootName = "New Input";
}
NodeIdPair nodeIdPair = Nodes::CreateExecutionNodeling(scriptCanvasId, rootName);
const bool isInput = positionOffset < 0;
const AZStd::string rootName = isInput ? "New Input" : "New Output";
NodeIdPair nodeIdPair = Nodes::CreateFunctionDefinitionNode(scriptCanvasId, isInput, rootName);
GraphCanvas::SceneRequests* sceneRequests = GraphCanvas::SceneRequestBus::FindFirstHandler(graphCanvasGraphId);
@@ -4151,6 +4164,13 @@ namespace ScriptCanvasEditor
contextMenu.AddMenuAction(aznew ConvertVariableNodeToReferenceAction(&contextMenu));
}
if (descriptorType == NodeDescriptorType::FunctionDefinitionNode)
{
NodeDescriptorComponent* descriptor = nullptr;
NodeDescriptorRequestBus::EventResult(descriptor, nodeId, &NodeDescriptorRequests::GetDescriptorComponent);
contextMenu.AddMenuAction(aznew RenameFunctionDefinitionNodeAction(descriptor, &contextMenu));
}
return HandleContextMenu(contextMenu, nodeId, screenPoint, scenePoint);
}
@@ -4276,6 +4296,7 @@ namespace ScriptCanvasEditor
contextMenu.AddMenuAction(aznew ConvertReferenceToVariableNodeAction(&contextMenu));
contextMenu.AddMenuAction(aznew ExposeSlotMenuAction(&contextMenu));
contextMenu.AddMenuAction(aznew CreateAzEventHandlerSlotMenuAction(&contextMenu));
contextMenu.AddMenuAction(aznew SetDataSlotTypeMenuAction(&contextMenu));
return HandleContextMenu(contextMenu, slotId, screenPoint, scenePoint);
}
@@ -4870,12 +4891,13 @@ namespace ScriptCanvasEditor
m_variableDockWidget->setEnabled(false);
m_propertyGrid->DisableGrid();
m_editorToolbar->OnViewDisabled();
m_createFunction->setEnabled(false);
m_createFunctionInput->setEnabled(false);
m_createFunctionOutput->setEnabled(false);
m_createScriptCanvas->setEnabled(false);
UpdateMenuState(false);
ui->action_New_Function->setEnabled(false);
ui->action_New_Script->setEnabled(false);
m_autoSaveTimer.stop();
@@ -4894,10 +4916,8 @@ namespace ScriptCanvasEditor
m_propertyGrid->EnableGrid();
m_editorToolbar->OnViewEnabled();
m_createFunction->setEnabled(true);
m_createScriptCanvas->setEnabled(true);
ui->action_New_Function->setEnabled(true);
ui->action_New_Script->setEnabled(true);
UpdateMenuState(true);
@@ -224,10 +224,12 @@ namespace ScriptCanvasEditor
class GraphValidationDockWidget;
class MainWindowStatusWidget;
class StatisticsDialog;
class SlotTypeSelectorWidget;
// Custom Context Menus
class SceneContextMenu;
class ConnectionContextMenu;
class RenameFunctionDefinitionNodeAction;
class MainWindow
: public QMainWindow
@@ -289,8 +291,8 @@ namespace ScriptCanvasEditor
// VariablePaletteRequestBus
void RegisterVariableType(const ScriptCanvas::Data::Type& variableType) override;
bool IsValidVariableType(const ScriptCanvas::Data::Type& dataType) const override;
bool ShowSlotTypeSelector(ScriptCanvas::Slot* slot, const QPoint& scenePosition, VariablePaletteRequests::SlotSetup&) override;
////
// GraphCanvas::AssetEditorRequestBus
@@ -334,7 +336,6 @@ namespace ScriptCanvasEditor
// File menu
void OnFileNew();
void OnFileNewFunction();
bool OnFileSave(const Callbacks::OnSave& saveCB);
bool OnFileSaveAs(const Callbacks::OnSave& saveCB);
@@ -451,7 +452,6 @@ namespace ScriptCanvasEditor
void RemoveScriptCanvasAsset(const AZ::Data::AssetId& assetId);
void OnChangeActiveGraphTab(AZ::Data::AssetId) override;
void CreateNewFunctionAsset() override { OnFileNewFunction(); }
void CreateNewRuntimeAsset() override { OnFileNew(); }
GraphCanvas::GraphId GetActiveGraphCanvasGraphId() const override;
@@ -614,7 +614,7 @@ namespace ScriptCanvasEditor
void CreateFunctionInput();
void CreateFunctionOutput();
void CreateExecutionNodeling(int positionOffset);
void CreateFunctionDefinitionNode(int positionOffset);
int CreateAssetTab(const AZ::Data::AssetId& assetId, int tabIndex = -1);
@@ -713,7 +713,6 @@ namespace ScriptCanvasEditor
QToolButton* m_createFunctionOutput = nullptr;
QToolButton* m_createScriptCanvas = nullptr;
QToolButton* m_createFunction = nullptr;
QMenu* m_selectedEntityMenu = nullptr;
@@ -728,6 +727,8 @@ namespace ScriptCanvasEditor
GraphCanvas::BookmarkDockWidget* m_bookmarkDockWidget = nullptr;
GraphCanvas::MiniMapDockWidget* m_minimap = nullptr;
LoggingWindow* m_loggingWindow = nullptr;
SlotTypeSelectorWidget* m_slotTypeSelector = nullptr;
AzQtComponents::WindowDecorationWrapper* m_presetWrapper = nullptr;
GraphCanvas::ConstructPresetDialog* m_presetEditor = nullptr;
@@ -15,12 +15,14 @@
#include <QApplication>
#include <QClipboard>
#include <QMimeData>
#include <QInputDialog>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <Editor/Nodes/NodeUtils.h>
#include <Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.h>
#include <Editor/View/Widgets/VariablePanel/GraphVariablesTableView.h>
#include <Editor/View/Widgets/VariablePanel/SlotTypeSelectorWidget.h>
#include <ScriptCanvas/Bus/EditorScriptCanvasBus.h>
#include <ScriptCanvas/Bus/RequestBus.h>
@@ -54,6 +56,8 @@
#include <ScriptCanvas/Core/Node.h>
#include <ScriptCanvas/GraphCanvas/MappingBus.h>
#include <GraphCanvas/Components/Nodes/NodeTitleBus.h>
#include <GraphCanvas/Components/NodeDescriptors/FunctionDefinitionNodeDescriptorComponent.h>
namespace ScriptCanvasEditor
{
//////////////////////////////
@@ -173,7 +177,7 @@ namespace ScriptCanvasEditor
}
ScriptCanvas::Slot* SlotManipulationMenuAction::GetScriptCanvasSlot(const GraphCanvas::Endpoint& endpoint) const
ScriptCanvas::Slot* SlotManipulationMenuAction::GetScriptCanvasSlot(const GraphCanvas::Endpoint& endpoint)
{
GraphCanvas::GraphId graphId;
GraphCanvas::SceneMemberRequestBus::EventResult(graphId, endpoint.GetNodeId(), &GraphCanvas::SceneMemberRequests::GetScene);
@@ -467,7 +471,12 @@ namespace ScriptCanvasEditor
GraphCanvas::NodeId nodeId;
GraphCanvas::SlotRequestBus::EventResult(nodeId, slotId, &GraphCanvas::SlotRequests::GetNode);
NodeIdPair nodePair = ScriptCanvasEditor::Nodes::CreateExecutionNodeling(scriptCanvasGraphId);
// Set the connection type for the node opposite of what it actually is because we're interested in the connection type of the node we're
// exposing, not the type of the slot we just created
ScriptCanvas::ConnectionType scriptCanvasConnectionType = (connectionType == GraphCanvas::CT_Input) ? ScriptCanvas::ConnectionType::Input : ScriptCanvas::ConnectionType::Output;
bool isInput = (scriptCanvasConnectionType == ScriptCanvas::ConnectionType::Output);
NodeIdPair nodePair = ScriptCanvasEditor::Nodes::CreateFunctionDefinitionNode(scriptCanvasGraphId, isInput);
GraphCanvas::SceneRequestBus::Event(graphId, &GraphCanvas::SceneRequests::AddNode, nodePair.m_graphCanvasId, scenePos, false);
@@ -490,13 +499,8 @@ namespace ScriptCanvasEditor
// Set the node title, subtitle, tooltip
GraphCanvas::NodeTitleRequestBus::Event(nodePair.m_graphCanvasId, &GraphCanvas::NodeTitleRequests::SetTitle, fullTitle);
GraphCanvas::NodeTitleRequestBus::Event(nodePair.m_graphCanvasId, &GraphCanvas::NodeTitleRequests::SetSubTitle, "Function");
GraphCanvas::NodeRequestBus::Event(nodePair.m_graphCanvasId, &GraphCanvas::NodeRequests::SetTooltip, name);
// Set the connection type for the node opposite of what it actually is because we're interested in the connection type of the node we're
// exposing, not the type of the slot we just created
ScriptCanvas::ConnectionType scriptCanvasConnectionType = (connectionType == GraphCanvas::CT_Input) ? ScriptCanvas::ConnectionType::Input : ScriptCanvas::ConnectionType::Output;
ScriptCanvas::SlotDescriptor descriptor;
descriptor.m_slotType = ScriptCanvas::SlotTypeDescriptor::Execution;
descriptor.m_connectionType = scriptCanvasConnectionType;
@@ -584,20 +588,7 @@ namespace ScriptCanvasEditor
if (variable)
{
if (connectionType == GraphCanvas::CT_Input)
{
if (!variable->IsInScope(ScriptCanvas::VariableFlags::Scope::Input))
{
variable->SetScope(ScriptCanvas::VariableFlags::Scope::Input);
}
}
else if (connectionType == GraphCanvas::CT_Output)
{
if (!variable->IsInScope(ScriptCanvas::VariableFlags::Scope::Output))
{
variable->SetScope(ScriptCanvas::VariableFlags::Scope::Output);
}
}
variable->SetScope(ScriptCanvas::VariableFlags::Scope::Function);
}
}
}
@@ -607,6 +598,100 @@ namespace ScriptCanvasEditor
return GraphCanvas::ContextMenuAction::SceneReaction::PostUndo;
}
//////////////////////////////////
// SetDataSlotTypeMenuAction
//////////////////////////////////
SetDataSlotTypeMenuAction::SetDataSlotTypeMenuAction(QObject* parent)
: GraphCanvas::SlotContextMenuAction("Set Slot Type", parent)
{
}
void SetDataSlotTypeMenuAction::RefreshAction(const GraphCanvas::GraphId& graphId, const AZ::EntityId& targetId)
{
ScriptCanvas::Slot* slot = GetSlot(graphId, targetId);
bool isEnabled = slot && slot->IsUserAdded() && slot->GetDescriptor().IsData();
setEnabled(isEnabled);
}
GraphCanvas::ContextMenuAction::SceneReaction SetDataSlotTypeMenuAction::TriggerAction(const GraphCanvas::GraphId& graphId, const AZ::Vector2& scenePos)
{
ScriptCanvas::Slot* slot = GetSlot(graphId, GetTargetId());
if (!slot)
{
return GraphCanvas::ContextMenuAction::SceneReaction::Nothing;
}
// Show the selection dialog
bool createSlot = false;
VariablePaletteRequests::SlotSetup selectedSlotSetup;
QPoint scenePoint(scenePos.GetX(), scenePos.GetY());
VariablePaletteRequestBus::BroadcastResult(createSlot, &VariablePaletteRequests::ShowSlotTypeSelector, slot, scenePoint, selectedSlotSetup);
bool changed = false;
if (createSlot && !selectedSlotSetup.m_type.IsNull())
{
if (slot)
{
auto displayType = ScriptCanvas::Data::FromAZType(selectedSlotSetup.m_type);
if (displayType.IsValid())
{
slot->SetDisplayType(displayType);
changed = true;
}
if (!selectedSlotSetup.m_name.empty())
{
slot->Rename(selectedSlotSetup.m_name);
changed = true;
}
}
}
return changed ? GraphCanvas::ContextMenuAction::SceneReaction::PostUndo : GraphCanvas::ContextMenuAction::SceneReaction::Nothing;
}
bool SetDataSlotTypeMenuAction::IsSupportedSlotType(const AZ::EntityId& slotId)
{
GraphCanvas::Endpoint endpoint;
GraphCanvas::SlotRequestBus::EventResult(endpoint, slotId, &GraphCanvas::SlotRequests::GetEndpoint);
const ScriptCanvas::Slot* slot = SlotManipulationMenuAction::GetScriptCanvasSlot(endpoint);
if (slot)
{
if (slot->GetDescriptor().IsData())
{
return true;
}
}
return false;
}
ScriptCanvas::Slot* SetDataSlotTypeMenuAction::GetSlot(const GraphCanvas::GraphId& graphId, const AZ::EntityId& targetId)
{
ScriptCanvas::ScriptCanvasId scriptCanvasGraphId;
GeneralRequestBus::BroadcastResult(scriptCanvasGraphId, &GeneralRequests::GetScriptCanvasId, graphId);
GraphCanvas::Endpoint endpoint;
GraphCanvas::SlotRequestBus::EventResult(endpoint, targetId, &GraphCanvas::SlotRequests::GetEndpoint);
ScriptCanvas::Endpoint scEndpoint;
EditorGraphRequestBus::EventResult(scEndpoint, scriptCanvasGraphId, &EditorGraphRequests::ConvertToScriptCanvasEndpoint, endpoint);
ScriptCanvas::Slot* slot = nullptr;
ScriptCanvas::NodeRequestBus::EventResult(slot, scEndpoint.GetNodeId(), &ScriptCanvas::NodeRequests::GetSlot, scEndpoint.GetSlotId());
return slot;
}
//////////////////////////////////
// CreateAzEventHandlerSlotMenuAction
//////////////////////////////////
CreateAzEventHandlerSlotMenuAction::CreateAzEventHandlerSlotMenuAction(QObject* parent)
: SlotContextMenuAction("Create event handler", parent)
{
@@ -853,6 +938,34 @@ namespace ScriptCanvasEditor
// TODO: Filter nodes.
}
//////////////////////////
// RenameFunctionDefinitionNodeAction
//////////////////////////
RenameFunctionDefinitionNodeAction::RenameFunctionDefinitionNodeAction(NodeDescriptorComponent* descriptor, QObject* parent)
: NodeContextMenuAction("Rename Function", parent)
, m_descriptor(descriptor)
{}
void RenameFunctionDefinitionNodeAction::RefreshAction(const GraphCanvas::GraphId& graphId, const AZ::EntityId& /*targetId*/)
{
AZStd::vector<AZ::EntityId> selectedNodes;
GraphCanvas::SceneRequestBus::EventResult(selectedNodes, graphId, &GraphCanvas::SceneRequests::GetSelectedNodes);
setEnabled(selectedNodes.size() == 1);
}
GraphCanvas::ContextMenuAction::SceneReaction RenameFunctionDefinitionNodeAction::TriggerAction(const GraphCanvas::GraphId&, const AZ::Vector2&)
{
if (FunctionDefinitionNodeDescriptorComponent::RenameDialog(azrtti_cast<FunctionDefinitionNodeDescriptorComponent*>(m_descriptor)))
{
return GraphCanvas::ContextMenuAction::SceneReaction::PostUndo;
}
return GraphCanvas::ContextMenuAction::SceneReaction::Nothing;
}
#include "Editor/View/Windows/moc_ScriptCanvasContextMenus.cpp"
}
@@ -23,8 +23,10 @@
#include <GraphCanvas/Widgets/EditorContextMenu/ContextMenus/SceneContextMenu.h>
#include <GraphCanvas/Widgets/EditorContextMenu/ContextMenus/ConnectionContextMenu.h>
#include <GraphCanvas/Widgets/EditorContextMenu/ContextMenus/SlotContextMenu.h>
#include <GraphCanvas/Widgets/EditorContextMenu/ContextMenus/NodeContextMenu.h>
#include <GraphCanvas/Widgets/EditorContextMenu/ContextMenuActions/SceneMenuActions/SceneContextMenuAction.h>
#include <GraphCanvas/Widgets/EditorContextMenu/ContextMenuActions/SlotMenuActions/SlotContextMenuAction.h>
#include <GraphCanvas/Widgets/EditorContextMenu/ContextMenuActions/NodeMenuActions/NodeContextMenuAction.h>
#endif
namespace ScriptCanvasEditor
@@ -112,8 +114,8 @@ namespace ScriptCanvasEditor
SlotManipulationMenuAction(AZStd::string_view actionName, QObject* parent);
protected:
ScriptCanvas::Slot* GetScriptCanvasSlot(const GraphCanvas::Endpoint& endpoint) const;
static ScriptCanvas::Slot* GetScriptCanvasSlot(const GraphCanvas::Endpoint& endpoint) ;
};
class ConvertReferenceToVariableNodeAction
@@ -153,6 +155,25 @@ namespace ScriptCanvasEditor
void CreateNodeling(const GraphCanvas::GraphId& graphId, AZ::EntityId scriptCanvasGraphId, GraphCanvas::GraphId slotId, const AZ::Vector2& scenePos, GraphCanvas::ConnectionType connectionType);
};
class SetDataSlotTypeMenuAction
: public GraphCanvas::SlotContextMenuAction
{
public:
AZ_CLASS_ALLOCATOR(SetDataSlotTypeMenuAction, AZ::SystemAllocator, 0);
explicit SetDataSlotTypeMenuAction(QObject* parent);
virtual ~SetDataSlotTypeMenuAction() = default;
static bool IsSupportedSlotType(const AZ::EntityId& slotId);
void RefreshAction(const GraphCanvas::GraphId& graphId, const AZ::EntityId& targetId) override;
GraphCanvas::ContextMenuAction::SceneReaction TriggerAction(const GraphCanvas::GraphId& graphId, const AZ::Vector2& scenePos) override;
private:
ScriptCanvas::Slot* GetSlot(const GraphCanvas::GraphId& graphId, const AZ::EntityId& targetId);
};
//! Context Menu Action for Creating an AzEventHandler node from a data slot of a Behavior Method node
//! which returns an AZ::Event<Params...> type
class CreateAzEventHandlerSlotMenuAction
@@ -172,6 +193,7 @@ namespace ScriptCanvasEditor
const AZ::BehaviorMethod* m_methodWithAzEventReturn{};
GraphCanvas::Endpoint m_methodNodeAzEventEndpoint;
};
/////////////////
@@ -222,4 +244,27 @@ namespace ScriptCanvasEditor
AZ::EntityId m_connectionId;
};
//////////////////////////
// RenameFunctionDefinitionNode
//////////////////////////
class NodeDescriptorComponent;
//! Context menu to rename a node
class RenameFunctionDefinitionNodeAction
: public GraphCanvas::NodeContextMenuAction
{
public:
AZ_CLASS_ALLOCATOR(RenameFunctionDefinitionNodeAction, AZ::SystemAllocator, 0);
RenameFunctionDefinitionNodeAction(NodeDescriptorComponent* descriptor, QObject* parent);
virtual ~RenameFunctionDefinitionNodeAction() = default;
void RefreshAction(const GraphCanvas::GraphId& graphId, const AZ::EntityId& targetId) override;
GraphCanvas::ContextMenuAction::SceneReaction TriggerAction(const GraphCanvas::GraphId& graphId, const AZ::Vector2& scenePos) override;
NodeDescriptorComponent* m_descriptor;
};
}
@@ -57,7 +57,6 @@
<string>&amp;File</string>
</property>
<addaction name="action_New_Script"/>
<addaction name="actionFunction"/>
<addaction name="action_Open"/>
<addaction name="action_Save"/>
<addaction name="action_Save_As"/>
@@ -180,11 +179,6 @@
<string>&amp;New Script</string>
</property>
</action>
<action name="action_New_Function">
<property name="text">
<string>&amp;Function</string>
</property>
</action>
<action name="action_New_Editor_Graph">
<property name="text">
<string>&amp;Editor Graph</string>
@@ -781,11 +775,6 @@
<string>Editor Graph</string>
</property>
</action>
<action name="actionFunction">
<property name="text">
<string>New Function</string>
</property>
</action>
<addaction name="action_ViewNodePalette"/>
<addaction name="action_ViewOutline"/>
<addaction name="action_ViewDynamicEBusAssets"/>
@@ -71,6 +71,30 @@ namespace ScriptCanvas
->Field("requiredScriptEvents", &RuntimeData::m_requiredScriptEvents)
;
}
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(reflectContext))
{
behaviorContext->Class<RuntimeData>()
->Method("GetRequiredAssets", [](const RuntimeData& data) { return data.m_requiredAssets; })
;
}
}
bool RuntimeData::RequiresDependencyConstructionParameters() const
{
return AZStd::any_of(m_requiredAssets.begin(), m_requiredAssets.end(), [](const AZ::Data::Asset<RuntimeAsset>& asset)
{
return RequiresDependencyConstructionParametersRecurse(asset.Get()->m_runtimeData);
});
}
bool RuntimeData::RequiresDependencyConstructionParametersRecurse(const RuntimeData& data)
{
return data.m_input.GetConstructorParameterCount() != 0
|| AZStd::any_of(data.m_requiredAssets.begin(), data.m_requiredAssets.end(), [](const AZ::Data::Asset<RuntimeAsset>& asset)
{
return RequiresDependencyConstructionParametersRecurse(asset.Get()->m_runtimeData);
});
}
bool RuntimeData::RequiresStaticInitialization() const
@@ -78,6 +102,7 @@ namespace ScriptCanvas
return !m_cloneSources.empty();
}
////////////////////////
// SubgraphInterfaceData
////////////////////////
@@ -88,8 +113,7 @@ namespace ScriptCanvas
{
serializeContext->Class<SubgraphInterfaceData>()
->Version(static_cast<int>(ScriptCanvasRuntimeAssetCpp::FunctionRuntimeDataVersion::Current))
->Field("m_name", &SubgraphInterfaceData::m_name)
->Field("m_version", &SubgraphInterfaceData::m_version)
->Field("name", &SubgraphInterfaceData::m_name)
->Field("interface", &SubgraphInterfaceData::m_interface)
;
}
@@ -105,7 +129,6 @@ namespace ScriptCanvas
if (this != &other)
{
m_name = AZStd::move(other.m_name);
m_version = AZStd::move(other.m_version);
m_interface = AZStd::move(other.m_interface);
}
@@ -79,6 +79,12 @@ namespace ScriptCanvas
Execution::ActivationInputRange m_activationInputRange;
bool RequiresStaticInitialization() const;
bool RequiresDependencyConstructionParameters() const;
private:
bool static RequiresDependencyConstructionParametersRecurse(const RuntimeData& data);
};
class RuntimeAssetBase
@@ -129,7 +135,6 @@ namespace ScriptCanvas
};
class RuntimeAsset : public RuntimeAssetTyped<RuntimeData>
{
public:
@@ -146,24 +151,24 @@ namespace ScriptCanvas
class SubgraphInterfaceAsset;
class RuntimeFunctionAssetDescription : public AssetDescription
class SubgraphInterfaceAssetDescription : public AssetDescription
{
public:
AZ_TYPE_INFO(RuntimeFunctionAssetDescription, "{7F7BE1A5-9447-41C2-9190-18580075094C}");
AZ_TYPE_INFO(SubgraphInterfaceAssetDescription, "{7F7BE1A5-9447-41C2-9190-18580075094C}");
RuntimeFunctionAssetDescription()
SubgraphInterfaceAssetDescription()
: AssetDescription(
azrtti_typeid<SubgraphInterfaceAsset>(),
"Script Canvas Runtime Function",
"Script Canvas Runtime Function Graph",
"Script Canvas Function Interface",
"Script Canvas Function Interface",
"@devassets@/scriptcanvas",
".scriptcanvas_fn_compiled",
"Script Canvas Runtime Function",
"Script Canvas Function Interface",
"Untitled-Function-%i",
"Script Canvas Compiled Function Files (*.scriptcanvas_fn_compiled)",
"Script Canvas Runtime Function",
"Script Canvas Runtime Function",
"Script Canvas Compiled Function Interfaces (*.scriptcanvas_fn_compiled)",
"Script Canvas Function Interface",
"Script Canvas Function Interface",
"Editor/Icons/ScriptCanvas/Viewport/ScriptCanvas_Function.png",
AZ::Color(1.0f,0.0f,0.0f,1.0f),
false
@@ -184,7 +189,6 @@ namespace ScriptCanvas
static void Reflect(AZ::ReflectContext* reflectContext);
size_t m_version;
AZStd::string m_name;
Grammar::SubgraphInterface m_interface;
};
@@ -97,7 +97,7 @@ namespace ScriptCanvas
{
RuntimeAsset* runtimeAsset = asset.GetAs<RuntimeAsset>();
AZ_Assert(runtimeAsset, "RuntimeAssetHandler::InitAsset This should be a Script Canvas runtime asset, as this is the only type this handler processes!");
Execution::Context::IntializeAssetData(runtimeAsset->GetData());
Execution::Context::InitializeActivationData(runtimeAsset->GetData());
Execution::InitializeInterpretedStatics(runtimeAsset->GetData());
}
}
@@ -8,43 +8,84 @@ or, if provided, by the license below or the license accompanying this file. Do
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#}
{% import 'ScriptCanvas_Macros.jinja' as macros %}
#pragma once
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// This code was produced with AzAutoGen, any modifications made will not be preserved.
// If you need to modify this code see:
//
// Gems\ScriptCanvas\Code\Include\ScriptCanvas\AutoGen\ScriptCanvasNode_Header.jinja
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <ScriptCanvas/Core/Datum.h>
#include <ScriptCanvas/Core/Node.h>
{% for xml in dataFiles %}
{% for Class in xml.iter('Class') %}
{# Any user-provided includes #}
{% for Include in Class.iter('Include') %}
#include <{{ Include.attrib['File'] }}>
{% endfor %}
{# Class Attributes #}
{# ----------------------------------------------------------------------------------------- #}
{% set attribute_Namespace = undefined %}
{%- if Class.attrib['Namespace'] is defined %}
{% if Class.attrib['Namespace'] != "None" %}
{% set attribute_Namespace = Class.attrib['Namespace'] %}
{% endif %}
{% endif %}
{% if attribute_Namespace is defined %}
namespace {{attribute_Namespace}}
{
{% endif %}
{% set className = Class.attrib['Name'] %}
{% set baseClass = Class.attrib['Base'] %}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
////
//// {{ Class.attrib['Name'] }}
//// {{ className }}
////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
{% set classUuid = Class.attrib['Uuid'] %}
{% if classUuid is not defined %}
{% set classUuid = className|createHashGuid %}
{% endif %}
{% set deprecationUuid = Class.attrib['DeprecationUUID'] %}
// The following will be injected directly into the source header file for which AzCodeGenerator is being run.
// You must #include the generated header into the source header
#define SCRIPTCANVAS_NODE_{{ Class.attrib['Name'] }} \
#define SCRIPTCANVAS_NODE_{{ className }} \
public: \
AZ_COMPONENT({{ Class.attrib['Name'] }}, "{{ Class.attrib['Uuid'] }}"{% if Class.attrib['Base'] is defined %}, {{ Class.attrib['Base'] }}{% endif %}); \
AZ_COMPONENT({{ className }}, "{{ classUuid }}"{% if baseClass is defined %}, {{ baseClass }}{% endif %}); \
static void Reflect(AZ::ReflectContext* reflection); \
void ConfigureSlots() override; \
bool RequiresDynamicSlotOrdering() const override; \
bool IsDeprecated() const override; \
{% if deprecationUuid is defined %}NodeConfiguration GetReplacementNodeConfiguration() const override; \ {% endif %}
using Node::FindDatum; \
{% if Class.attrib['GraphEntryPoint'] is defined %} bool IsEntryPoint() const override { return true; } \
{% if Class.attrib['GraphEntryPoint'] is defined %} bool IsEntryPoint() const override { return {%if Class.attrib['GraphEntryPoint'] == True %}true{%else%}false{%endif%}; } \
{% endif %}
public: \
friend struct ::{{ Class.attrib['Name'] | replace(' ','') }}Property;
friend struct ::{{ className | replace(' ','') }}Property;
// Helpers for easily accessing properties and slots
struct {{ Class.attrib['Name'] | replace(' ','') }}Property
struct {{ className | replace(' ','') }}Property
{
{% for Property in Class.iter('Out') %}
{% for Property in Class.iter('Out') %}
{% if Property.attrib['Description'] is defined %} // {{ Property.attrib['Description'] }}{% endif %}
static ScriptCanvas::SlotId Get{{ Property.attrib['Name'] | replace(' ','') }}SlotId(const ScriptCanvas::Node* owner)
@@ -118,5 +159,12 @@ struct {{ Class.attrib['Name'] | replace(' ','') }}Property
{% endfor %}
};
{% if attribute_Namespace is defined %}
}
{% endif %}
{{ macros.ReportErrors() }}
{% endfor %}
{% endfor %}
@@ -174,6 +174,18 @@ bool {{ Class.attrib['QualifiedName'] }}::IsDeprecated() const
return {% if Class.attrib['Deprecated'] is defined %}true{% else %}false{% endif %};
}
{% set deprecationUuid = Class.attrib['DeprecationUUID'] %}
{% if deprecationUuid is defined %}
NodeConfiguration {{ Class.attrib['QualifiedName'] }}::GetReplacementNodeConfiguration() const
{
ScriptCanvas::NodeConfiguration nodeConfig{};
nodeConfig.m_type = AZ::Uuid({{ deprecationUuid }});
{% if Class.attrib['ReplacementMethodName'] is defined %}
nodeConfig.m_methodName = "{{Class.attrib['ReplacementMethodName']}}";
{% endif %}
return nodeConfig;
}
{% endif %}
void {{ Class.attrib['QualifiedName'] }}::Reflect(AZ::ReflectContext* context)
{
@@ -63,7 +63,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
{# ----------------------------------------------------------------------------------------- #}
{# Groups al tags that do not provide a DisplayGroup #}
{# Groups all tags that do not provide a DisplayGroup #}
{% set global_standaloneTagMap = dict() %}
{# Display Group Support #}
@@ -225,6 +225,12 @@ namespace ScriptCanvas
void MergeWith(const DependencyReport& other);
};
struct OrderedDependencies
{
DependencyReport source;
AZStd::vector<AZ::Data::AssetId> orderedAssetIds;
};
//! Globally accessible Script Canvas settings, we use these to pass user provided settings
//! into the Script Canvas code
class ScriptCanvasSettingsRequests : public AZ::EBusTraits
@@ -177,20 +177,6 @@ namespace ScriptCanvas
return true;
}
for (auto& nodeEntity : m_graphData.m_nodes)
{
if (nodeEntity)
{
if (auto node = AZ::EntityUtils::FindFirstDerivedComponent<Node>(nodeEntity))
{
if (azrtti_istypeof<Nodes::Core::FunctionDefinitionNode*>(node))
{
return true;
}
}
}
}
return false;
}
@@ -324,8 +310,8 @@ namespace ScriptCanvas
request.graph = this;
request.name = "editorValidation";
request.rawSaveDebugOutput = Grammar::s_saveRawTranslationOuputToFile;
request.printModelToConsole = Grammar::s_printAbstractCodeModel;
request.rawSaveDebugOutput = Grammar::g_saveRawTranslationOuputToFile;
request.printModelToConsole = Grammar::g_printAbstractCodeModel;
const Translation::Result result = Translation::ToLua(request);
@@ -348,7 +334,10 @@ namespace ScriptCanvas
{
validationResults.ClearResults();
// Parse(validationResults);
if (!Grammar::g_disableParseOnGraphValidation)
{
Parse(validationResults);
}
for (auto& connectionEntity : m_graphData.m_connections)
{
@@ -131,6 +131,15 @@ namespace ScriptCanvas
//! Notification when a connections is removed
virtual void OnConnectionRemoved(const AZ::EntityId&) {}
//! Notification when a connections is about to be removed
virtual void OnPreConnectionRemoved(const AZ::EntityId&) {}
//! Notification when a connection is completed
virtual void OnConnectionComplete(const AZ::EntityId&) {}
//! Notification when a connection is completed
virtual void OnDisonnectionComplete(const AZ::EntityId&) {}
//! Notification when a batch add for a graph begins
virtual void OnBatchAddBegin() {}
@@ -560,7 +560,27 @@ namespace ScriptCanvas
return "";
}
SlotsOutcome Node::GetSlots(const AZStd::vector<SlotId>& slotIds) const
SlotsOutcome Node::GetSlots(const AZStd::vector<SlotId>& slotIds)
{
AZStd::vector<Slot*> slots;
slots.reserve(slotIds.size());
for (const auto& slotId : slotIds)
{
if (const auto slot = GetSlot(slotId))
{
slots.push_back(slot);
}
else
{
return AZ::Failure(AZStd::string::format("No slot found for slotId %s", slotId.ToString().data()));
}
}
return AZ::Success(slots);
}
ConstSlotsOutcome Node::GetSlots(const AZStd::vector<SlotId>& slotIds) const
{
AZStd::vector<const Slot*> slots;
slots.reserve(slotIds.size());
@@ -2043,6 +2063,23 @@ namespace ScriptCanvas
return retVal;
}
AZStd::vector<Slot*> Node::ModAllSlots()
{
AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::ScriptCanvas, "ScriptCanvas::Node::ModAllSlots");
SlotList& slots = GetSlots();
AZStd::vector<Slot*> retVal;
retVal.reserve(slots.size());
for (auto& slot : slots)
{
retVal.push_back(&slot);
}
return retVal;
}
bool Node::SlotExists(AZStd::string_view name, const SlotDescriptor& slotDescriptor) const
{
return FindSlotIdForDescriptor(name, slotDescriptor).IsValid();
@@ -2673,7 +2710,7 @@ namespace ScriptCanvas
Slot* slot = GetSlot(currentSlotId);
if (slot && slot->IsDynamicSlot())
if (slot && slot->IsDynamicSlot() && !slot->IsUserAdded())
{
AZ::Crc32 dynamicGroup = slot->GetDynamicGroup();
@@ -2890,9 +2927,9 @@ namespace ScriptCanvas
{
AZStd::string assetName = m_runtimeBus->GetAssetName();
AZ::EntityId assetNodeId = m_runtimeBus->FindAssetNodeIdByRuntimeNodeId(endpoint.GetNodeId());
AZ_Error("Script Canvas", false, "Unable to find node with id (id: %s) in the graph '%s'. Most likely the node was serialized with a type that is no longer reflected",
AZ_Warning("Script Canvas", false, "Unable to find node with id (id: %s) in the graph '%s'. Most likely the node was serialized with a type that is no longer reflected",
assetNodeId.ToString().data(), assetName.data());
continue;
}
else if (!node->IsNodeEnabled())
@@ -2900,7 +2937,18 @@ namespace ScriptCanvas
continue;
}
connectedNodes.emplace_back(node, node->GetSlot(endpoint.GetSlotId()));
auto endpointSlot = node->GetSlot(endpoint.GetSlotId());
if (!endpointSlot)
{
AZStd::string assetName = m_runtimeBus->GetAssetName();
AZ::EntityId assetNodeId = m_runtimeBus->FindAssetNodeIdByRuntimeNodeId(endpoint.GetNodeId());
AZ_Warning("Script Canvas", false, "Endpoint was missing slot. id (id: %s) in the graph '%s'.",
assetNodeId.ToString().data(), assetName.data());
continue;
}
connectedNodes.emplace_back(node, endpointSlot);
}
return connectedNodes;
@@ -3127,7 +3175,7 @@ namespace ScriptCanvas
return {};
}
bool Node::HandlerStartsConnected() const
bool Node::IsAutoConnected() const
{
return {};
}
@@ -3167,7 +3215,7 @@ namespace ScriptCanvas
return AZ::Failure();
}
SlotsOutcome Node::GetSlotsInExecutionThreadByTypeImpl(const Slot& executionSlot, CombinedSlotType targetSlotType, const Slot* executionChildSlot) const
ConstSlotsOutcome Node::GetSlotsInExecutionThreadByTypeImpl(const Slot& executionSlot, CombinedSlotType targetSlotType, const Slot* executionChildSlot) const
{
if (auto map = GetSlotExecutionMap())
{
@@ -3201,7 +3249,7 @@ namespace ScriptCanvas
return AZ::Failure(AZStd::string("override Node::GetSlotsInExecutionThreadByTypeImpl to do things subvert the normal slot map assumptions"));
}
SlotsOutcome Node::GetSlotsFromMap(const SlotExecution::Map& map, const Slot& executionSlot, CombinedSlotType targetSlotType, const Slot* /*executionChildSlot*/) const
ConstSlotsOutcome Node::GetSlotsFromMap(const SlotExecution::Map& map, const Slot& executionSlot, CombinedSlotType targetSlotType, const Slot* /*executionChildSlot*/) const
{
// so far ACM, needs to map:
// In -> Out, Data In, Data Out
@@ -3244,7 +3292,7 @@ namespace ScriptCanvas
return AZ::Failure(AZStd::string("no such mapping supported, yet"));
}
SlotsOutcome Node::GetDataInSlotsByExecutionIn(const SlotExecution::Map& map, const Slot& executionInSlot) const
ConstSlotsOutcome Node::GetDataInSlotsByExecutionIn(const SlotExecution::Map& map, const Slot& executionInSlot) const
{
const auto in = map.GetIn(executionInSlot.GetId());
@@ -3256,7 +3304,7 @@ namespace ScriptCanvas
return GetSlots(SlotExecution::ToInputSlotIds(in->inputs));
}
SlotsOutcome Node::GetDataOutSlotsByExecutionIn(const SlotExecution::Map& map, const Slot& executionInSlot) const
ConstSlotsOutcome Node::GetDataOutSlotsByExecutionIn(const SlotExecution::Map& map, const Slot& executionInSlot) const
{
const auto outs = map.GetOuts(executionInSlot.GetId());
@@ -3285,7 +3333,7 @@ namespace ScriptCanvas
return AZ::Success(outputSlots);
}
SlotsOutcome Node::GetDataOutSlotsByExecutionOut(const SlotExecution::Map& map, const Slot& executionOutSlot) const
ConstSlotsOutcome Node::GetDataOutSlotsByExecutionOut(const SlotExecution::Map& map, const Slot& executionOutSlot) const
{
if (executionOutSlot.IsLatent())
{
@@ -3311,7 +3359,7 @@ namespace ScriptCanvas
}
}
SlotsOutcome Node::GetExecutionOutSlotsByExecutionIn(const SlotExecution::Map& map, const Slot& executionInSlot) const
ConstSlotsOutcome Node::GetExecutionOutSlotsByExecutionIn(const SlotExecution::Map& map, const Slot& executionInSlot) const
{
const auto outs = map.GetOuts(executionInSlot.GetId());
if (!outs)
@@ -3336,7 +3384,7 @@ namespace ScriptCanvas
return AZ::Success(outSlots);
}
SlotsOutcome Node::GetDataInSlotsByExecutionOut(const SlotExecution::Map& map, const Slot& executionOutSlot) const
ConstSlotsOutcome Node::GetDataInSlotsByExecutionOut(const SlotExecution::Map& map, const Slot& executionOutSlot) const
{
if (auto returns = map.GetReturnValuesByOut(executionOutSlot.GetId()))
{
@@ -3464,7 +3512,7 @@ namespace ScriptCanvas
return AZ::Success(signature);
}
SlotsOutcome Node::GetSlotsInExecutionThreadByType(const Slot& executionSlot, CombinedSlotType targetSlotType, const Slot* executionChildSlot) const
ConstSlotsOutcome Node::GetSlotsInExecutionThreadByType(const Slot& executionSlot, CombinedSlotType targetSlotType, const Slot* executionChildSlot) const
{
auto targetSlotsOutcome = GetSlotsInExecutionThreadByTypeImpl(executionSlot, targetSlotType, executionChildSlot);
if (targetSlotsOutcome.IsSuccess())
@@ -260,7 +260,8 @@ namespace ScriptCanvas
DataType* m_dataType;
};
using SlotsOutcome = AZ::Outcome<AZStd::vector<const Slot*>, AZStd::string>;
using ConstSlotsOutcome = AZ::Outcome<AZStd::vector<const Slot*>, AZStd::string>;
using SlotsOutcome = AZ::Outcome<AZStd::vector<Slot*>, AZStd::string>;
using EndpointResolved = AZStd::pair<const Node*, const Slot*>;
using EndpointsResolved = AZStd::vector<EndpointResolved>;
@@ -531,8 +532,10 @@ namespace ScriptCanvas
AZStd::string GetSlotName(const SlotId& slotId) const;
//! returns a list of all slots, regardless of type
SlotList& GetSlots() { return m_slots; }
const SlotList& GetSlots() const { return m_slots; }
SlotsOutcome GetSlots(const AZStd::vector<SlotId>& slotIds) const;
ConstSlotsOutcome GetSlots(const AZStd::vector<SlotId>& slotIds) const;
SlotsOutcome GetSlots(const AZStd::vector<SlotId>& slotIds);
AZStd::vector< Slot* > GetSlotsWithDisplayGroup(AZStd::string_view displayGroup) const;
AZStd::vector< Slot* > GetSlotsWithDynamicGroup(const AZ::Crc32& dynamicGroup) const;
@@ -557,6 +560,7 @@ namespace ScriptCanvas
Slot* GetSlot(const SlotId& slotId) const override;
size_t GetSlotIndex(const SlotId& slotId) const override;
AZStd::vector<const Slot*> GetAllSlots() const override;
AZStd::vector<Slot*> ModAllSlots() override;
SlotId GetSlotId(AZStd::string_view slotName) const override;
SlotId FindSlotIdForDescriptor(AZStd::string_view slotName, const SlotDescriptor& descriptor) const override;
@@ -675,8 +679,6 @@ namespace ScriptCanvas
//////////////////////////////////////////////////////////////////////////
// Translation
virtual bool IsSupportedByNewBackend() const { return false; }
// \todo a hack that will disappear after conversions are properly done
virtual bool ConvertsInputToStrings() const;
@@ -696,7 +698,7 @@ namespace ScriptCanvas
virtual AZ::Outcome<Grammar::LexicalScope, void> GetFunctionCallLexicalScope(const Slot* /*slot*/) const;
// override if necessary, usually only when the node's execution topology dramatically alters at edit-time in a way that is not generally parseable
SlotsOutcome GetSlotsInExecutionThreadByType(const Slot& executionSlot, CombinedSlotType targetSlotType, const Slot* executionChildSlot = nullptr) const;
ConstSlotsOutcome GetSlotsInExecutionThreadByType(const Slot& executionSlot, CombinedSlotType targetSlotType, const Slot* executionChildSlot = nullptr) const;
// override if necessary, only used by NodeableNodes which can hide branched outs and rename them later
virtual AZ::Outcome<AZStd::string> GetInternalOutKey(const Slot& slot) const;
@@ -757,7 +759,7 @@ namespace ScriptCanvas
virtual AZStd::vector<const Slot*> GetOnVariableHandlingExecutionSlots() const;
virtual bool HandlerStartsConnected() const;
virtual bool IsAutoConnected() const;
virtual bool IsEBusAddressed() const;
@@ -784,19 +786,19 @@ namespace ScriptCanvas
virtual ExecutionNameMap GetExecutionNameMap() const { return ExecutionNameMap(); }
// override if necessary, usually only when the node's execution topology dramatically alters at edit-time in a way that is not generally parseable
virtual SlotsOutcome GetSlotsInExecutionThreadByTypeImpl(const Slot& executionSlot, CombinedSlotType targetSlotType, const Slot* executionChildSlot) const;
virtual ConstSlotsOutcome GetSlotsInExecutionThreadByTypeImpl(const Slot& executionSlot, CombinedSlotType targetSlotType, const Slot* executionChildSlot) const;
SlotsOutcome GetSlotsFromMap(const SlotExecution::Map& map, const Slot& executionSlot, CombinedSlotType targetSlotType, const Slot* executionChildSlot) const;
ConstSlotsOutcome GetSlotsFromMap(const SlotExecution::Map& map, const Slot& executionSlot, CombinedSlotType targetSlotType, const Slot* executionChildSlot) const;
SlotsOutcome GetDataInSlotsByExecutionIn(const SlotExecution::Map& map, const Slot& executionInSlot) const;
ConstSlotsOutcome GetDataInSlotsByExecutionIn(const SlotExecution::Map& map, const Slot& executionInSlot) const;
SlotsOutcome GetDataInSlotsByExecutionOut(const SlotExecution::Map& map, const Slot& executionOutSlot) const;
ConstSlotsOutcome GetDataInSlotsByExecutionOut(const SlotExecution::Map& map, const Slot& executionOutSlot) const;
SlotsOutcome GetDataOutSlotsByExecutionIn(const SlotExecution::Map& map, const Slot& executionInSlot) const;
ConstSlotsOutcome GetDataOutSlotsByExecutionIn(const SlotExecution::Map& map, const Slot& executionInSlot) const;
SlotsOutcome GetDataOutSlotsByExecutionOut(const SlotExecution::Map& map, const Slot& executionOutSlot) const;
ConstSlotsOutcome GetDataOutSlotsByExecutionOut(const SlotExecution::Map& map, const Slot& executionOutSlot) const;
SlotsOutcome GetExecutionOutSlotsByExecutionIn(const SlotExecution::Map& map, const Slot& executionInSlot) const;
ConstSlotsOutcome GetExecutionOutSlotsByExecutionIn(const SlotExecution::Map& map, const Slot& executionInSlot) const;
AZ::Outcome<AZStd::string> GetInternalOutKey(const SlotExecution::Map& map, const Slot& slot) const;
@@ -52,7 +52,9 @@ namespace ScriptCanvas
//! Name is funky to avoid a mismatch with typing with another function
//! that returns a better version of this information that cannot be used with
//! EBuses because of references.
virtual AZStd::vector<const Slot*> GetAllSlots() const = 0;
virtual AZStd::vector<const Slot*> GetAllSlots() const { return {}; }
virtual AZStd::vector<Slot*> ModAllSlots() { return {}; }
//! Retrieves a slot id that matches the supplied name
//! There can be multiple slots with the same name on a node
@@ -253,7 +253,7 @@ namespace ScriptCanvas
return AZ::Success(scope);
}
bool IsSupportedByNewBackend() const override { return true; }
protected:
@@ -123,7 +123,7 @@ namespace ScriptCanvas
return AZ::Success(behaviorClass);
}
SlotsOutcome NodeableNode::GetBehaviorContextOutName(const Slot& inSlot) const
ConstSlotsOutcome NodeableNode::GetBehaviorContextOutName(const Slot& inSlot) const
{
auto behaviorClassOutcome = GetBehaviorContextClass();
if (!behaviorClassOutcome)
@@ -236,11 +236,6 @@ namespace ScriptCanvas
return &m_slotExecutionMap;
}
bool NodeableNode::HandlerStartsConnected() const
{
return true;
}
bool NodeableNode::IsNodeableNode() const
{
return true;
@@ -60,11 +60,7 @@ namespace ScriptCanvas
const SlotExecution::Map* GetSlotExecutionMap() const override;
bool HandlerStartsConnected() const override;
bool IsNodeableNode() const override;
bool IsSupportedByNewBackend() const override { return true; }
bool IsNodeableNode() const override;
Nodeable* ReleaseNodeable();
@@ -81,7 +77,7 @@ namespace ScriptCanvas
AZ::Outcome<const AZ::BehaviorClass*, AZStd::string> GetBehaviorContextClass() const;
SlotsOutcome GetBehaviorContextOutName(const Slot& inSlot) const;
ConstSlotsOutcome GetBehaviorContextOutName(const Slot& inSlot) const;
virtual void RegisterExecutionMap(const AZ::BehaviorContext&) {}
@@ -29,6 +29,7 @@ namespace ScriptCanvas
virtual GraphScopedNodeId GetGraphScopedNodeId() const = 0;
virtual const AZStd::string& GetDisplayName() const = 0;
virtual void Setup() = 0;
virtual void SetDisplayName(const AZStd::string& displayName) = 0;
};
@@ -1,4 +1,4 @@
/*
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
@@ -212,6 +212,7 @@ namespace ScriptCanvas
->Field("DataType", &Slot::m_dataType)
->Field("IsReference", &Slot::m_isVariableReference)
->Field("VariableReference", &Slot::m_variableReference)
->Field("IsUserAdded", &Slot::m_isUserAdded)
;
}
@@ -221,6 +222,7 @@ namespace ScriptCanvas
: m_name(slotConfiguration.m_name)
, m_toolTip(slotConfiguration.m_toolTip)
, m_isLatentSlot(slotConfiguration.m_isLatent)
, m_isUserAdded(slotConfiguration.m_isUserAdded)
, m_descriptor(slotConfiguration.GetSlotDescriptor())
, m_dynamicDataType(DynamicDataType::None)
, m_id(slotConfiguration.m_slotId)
@@ -264,6 +266,7 @@ namespace ScriptCanvas
, m_displayGroup(other.m_displayGroup)
, m_dynamicGroup(other.m_dynamicGroup)
, m_isLatentSlot(other.m_isLatentSlot)
, m_isUserAdded(other.m_isUserAdded)
, m_descriptor(other.m_descriptor)
, m_isVariableReference(other.m_isVariableReference)
, m_dataType(other.m_dataType)
@@ -286,6 +289,7 @@ namespace ScriptCanvas
, m_displayGroup(AZStd::move(slot.m_displayGroup))
, m_dynamicGroup(AZStd::move(slot.m_dynamicGroup))
, m_isLatentSlot(AZStd::move(slot.m_isLatentSlot))
, m_isUserAdded(AZStd::move(slot.m_isUserAdded))
, m_descriptor(AZStd::move(slot.m_descriptor))
, m_isVariableReference(AZStd::move(slot.m_isVariableReference))
, m_dataType(AZStd::move(slot.m_dataType))
@@ -311,6 +315,7 @@ namespace ScriptCanvas
m_displayGroup = slot.m_displayGroup;
m_dynamicGroup = slot.m_dynamicGroup;
m_isLatentSlot = slot.m_isLatentSlot;
m_isUserAdded = slot.m_isUserAdded;
m_descriptor = slot.m_descriptor;
m_isVariableReference = slot.m_isVariableReference;
m_dataType = slot.m_dataType;
@@ -438,7 +443,7 @@ namespace ScriptCanvas
bool Slot::CanConvertToValue() const
{
return CanConvertTypes() && m_isVariableReference;
return !m_isUserAdded && CanConvertTypes() && m_isVariableReference;
}
bool Slot::ConvertToValue()
@@ -467,7 +472,7 @@ namespace ScriptCanvas
bool Slot::CanConvertToReference() const
{
return CanConvertTypes() && !m_isVariableReference && !m_node->HasConnectedNodes((*this));
return !m_isUserAdded && CanConvertTypes() && !m_isVariableReference && !m_node->HasConnectedNodes((*this));
}
bool Slot::ConvertToReference()
@@ -559,6 +564,11 @@ namespace ScriptCanvas
{
return m_isVisible;
}
bool Slot::IsUserAdded() const
{
return m_isUserAdded;
}
bool Slot::IsInput() const
{
@@ -603,7 +613,8 @@ namespace ScriptCanvas
void Slot::SetDisplayType(ScriptCanvas::Data::Type displayType)
{
if ((m_displayDataType.IsValid() && !displayType.IsValid())
|| (!m_displayDataType.IsValid() && displayType.IsValid()))
|| (!m_displayDataType.IsValid() && displayType.IsValid())
|| IsDynamicSlot())
{
// Confirm that the type we are display as conforms to what our underlying type says we
// should be.
@@ -925,4 +936,10 @@ namespace ScriptCanvas
{
m_dynamicGroup = dynamicGroup;
}
void Slot::SetVisible(bool isVisible)
{
m_isVisible = isVisible;
}
}
@@ -160,6 +160,9 @@ namespace ScriptCanvas
bool IsExecution() const;
bool IsVisible() const;
bool IsUserAdded() const;
void SetVisible(bool isVisible);
bool IsInput() const;
bool IsOutput() const;
@@ -216,6 +219,8 @@ namespace ScriptCanvas
protected:
bool m_isOverload = false;
bool m_isVisible = true;
bool m_isUserAdded = false;
void SetDynamicGroup(const AZ::Crc32& dynamicGroup);
AZStd::string m_name;
@@ -220,6 +220,7 @@ namespace ScriptCanvas
bool m_isVisible = true;
bool m_isLatent = false;
bool m_isUserAdded = false;
AZStd::vector<ContractDescriptor> m_contractDescs;
bool m_addUniqueSlotByNameAndType = true; // Only adds a new slot if a slot with the supplied name and CombinedSlotType does not exist on the node
@@ -64,7 +64,7 @@ namespace ScriptCanvas
Input() = default;
// not explicit on purpose
Input(const SlotId& slotId);
Input(const SlotId & slotId, const VariableId & interfaceSourceId);
Input(const SlotId& slotId, const VariableId & interfaceSourceId);
};
using Inputs = AZStd::vector<Input>;
using InputSlotIds = AZStd::vector<SlotId>;
@@ -30,9 +30,46 @@ namespace SubgraphInterfaceCpp
AddActivityParsing,
AddChildStarts,
AddExecutionCharacteristics,
Functions_2_0,
AddConstructionParameterRequirement,
AddConstructionParameterRequirementForDependencies,
// add your entry above
Current
};
const size_t k_maxTabs = 20;
AZ_INLINE const char* GetTabs(size_t tabs)
{
AZ_Assert(tabs >= 0 && tabs <= k_maxTabs, "invalid argument to GetTabs");
static const char* const k_tabs[] =
{
"", // 0
"\t",
"\t\t",
"\t\t\t",
"\t\t\t\t",
"\t\t\t\t\t", // 5
"\t\t\t\t\t\t",
"\t\t\t\t\t\t\t",
"\t\t\t\t\t\t\t\t",
"\t\t\t\t\t\t\t\t\t",
"\t\t\t\t\t\t\t\t\t\t", // 10
"\t\t\t\t\t\t\t\t\t\t\t",
"\t\t\t\t\t\t\t\t\t\t\t\t",
"\t\t\t\t\t\t\t\t\t\t\t\t\t",
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t", // 15
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t", // 20
};
return k_tabs[tabs];
}
}
namespace ScriptCanvas
@@ -43,6 +80,11 @@ namespace ScriptCanvas
{
// written out explicitly to aid breakpoint placement
if (isPure != rhs.isPure)
{
return false;
}
if (!AZ::StringFunc::Equal(displayName.c_str(), rhs.displayName.c_str()))
{
return false;
@@ -177,6 +219,18 @@ namespace ScriptCanvas
}
}
const In* SubgraphInterface::FindIn(const FunctionSourceId& sourceID) const
{
auto iter = AZStd::find_if(m_ins.begin(), m_ins.end(), [&sourceID](const In& in) { return in.sourceID == sourceID; });
return iter != m_ins.end() ? iter : nullptr;
}
const Out* SubgraphInterface::FindLatent(const FunctionSourceId& sourceID) const
{
auto iter = AZStd::find_if(m_latents.begin(), m_latents.end(), [&sourceID](const Out& latent) { return latent.sourceID == sourceID; });
return iter != m_latents.end() ? iter : nullptr;
}
ExecutionCharacteristics SubgraphInterface::GetExecutionCharacteristics() const
{
return m_executionCharacteristics;
@@ -202,6 +256,16 @@ namespace ScriptCanvas
return m_ins.size();
}
size_t SubgraphInterface::GetInCountNotPure() const
{
return AZStd::count_if(m_ins.begin(), m_ins.end(), [](const auto& in) { return !in.isPure; });
}
size_t SubgraphInterface::GetInCountPure() const
{
return AZStd::count_if(m_ins.begin(), m_ins.end(), [](const auto& in) { return in.isPure; });
}
const Inputs* SubgraphInterface::GetInput(const AZStd::string& inName) const
{
if (auto in = FindIn(inName))
@@ -230,7 +294,7 @@ namespace ScriptCanvas
{
return &(latent->outputs);
}
return nullptr;
}
@@ -241,7 +305,12 @@ namespace ScriptCanvas
LexicalScope SubgraphInterface::GetLexicalScope() const
{
if (IsMarkedPure())
return GetLexicalScope(IsMarkedPure());
}
LexicalScope SubgraphInterface::GetLexicalScope(bool isSourcePure) const
{
if (isSourcePure)
{
return LexicalScope{ LexicalScopeType::Namespace , m_namespacePath };
}
@@ -251,6 +320,11 @@ namespace ScriptCanvas
}
}
LexicalScope SubgraphInterface::GetLexicalScope(const In& in) const
{
return GetLexicalScope(in.isPure);
}
AZStd::string SubgraphInterface::GetName() const
{
AZ_Error("ScriptCanvas", !m_namespacePath.empty(), "Interface must have at least one name");
@@ -283,7 +357,7 @@ namespace ScriptCanvas
{
return &out->outputs;
}
return nullptr;
}
@@ -293,7 +367,7 @@ namespace ScriptCanvas
{
return &in->outs;
}
return nullptr;
}
@@ -315,7 +389,7 @@ namespace ScriptCanvas
{
Parse();
}
const Out* SubgraphInterface::FindImmediateOut(const AZStd::string& inName, const AZStd::string& outName) const
{
if (auto in = FindIn(inName))
@@ -343,7 +417,7 @@ namespace ScriptCanvas
const Out* SubgraphInterface::FindLatentOut(const AZStd::string& latentName) const
{
auto iter = AZStd::find_if(m_latents.begin(), m_latents.end(), [&latentName](const Out& latent) { return latent.displayName == latentName; });
if (iter != m_latents.end())
{
return iter;
@@ -360,9 +434,29 @@ namespace ScriptCanvas
return m_isActiveDefaultObject;
}
bool SubgraphInterface::IsAllInputOutputShared() const
bool SubgraphInterface::IsUserNodeable() const
{
return m_isAllInputOutputShared;
if (IsMarkedPure())
{
return false;
}
if (IsUserVariable())
{
return false;
}
if (GetInCountNotPure() == 0 && GetLatentOutCount() == 0)
{
return false;
}
return true;
}
bool SubgraphInterface::IsUserVariable() const
{
return m_isUserVariable;
}
AZ::Outcome<bool> SubgraphInterface::IsBranch(const AZStd::string& inName) const
@@ -374,7 +468,7 @@ namespace ScriptCanvas
else
{
return AZ::Failure();
}
}
}
bool SubgraphInterface::IsLatent() const
@@ -389,7 +483,32 @@ namespace ScriptCanvas
bool SubgraphInterface::IsParsedPure() const
{
return (!IsLatent()) && (!HasBranches()) && m_areAllChildrenPure;
if (IsLatent())
{
return false;
}
if (HasBranches())
{
return false;
}
if (!m_areAllChildrenPure)
{
return false;
}
if (m_requiresConstructionParameters && (!m_hasOnGraphStart && GetInCount() != 0))
{
return false;
}
return true;
}
bool SubgraphInterface::HasAnyFunctionality() const
{
return IsActiveDefaultObject() || HasPublicFunctionality();
}
bool SubgraphInterface::HasBranches() const
@@ -407,7 +526,8 @@ namespace ScriptCanvas
bool SubgraphInterface::HasIn(const FunctionSourceId& sourceID) const
{
return AZStd::find_if(m_ins.begin(), m_ins.end(), [&sourceID](const In& in) { return in.sourceID == sourceID; }) != m_ins.end();
return ((!IsUserVariable()) && (IsFunctionSourceIdNodeable(sourceID) || IsFunctionSourceIdObject(sourceID)))
|| FindIn(sourceID) != nullptr;
}
bool SubgraphInterface::HasInput(const VariableId& sourceID) const
@@ -488,9 +608,19 @@ namespace ScriptCanvas
m_isActiveDefaultObject = true;
}
void SubgraphInterface::MarkAllInputOutputShared()
void SubgraphInterface::MarkRequiresConstructionParameters()
{
m_isAllInputOutputShared = true;
m_requiresConstructionParameters = true;
}
void SubgraphInterface::MarkRequiresConstructionParametersForDependencies()
{
m_requiresConstructionParametersForDependencies = true;
}
void SubgraphInterface::MarkUserVariable()
{
m_isUserVariable = true;
}
void SubgraphInterface::MarkExecutionCharacteristics(ExecutionCharacteristics characteristics)
@@ -509,11 +639,20 @@ namespace ScriptCanvas
m_hasOnGraphStart = m_hasOnGraphStart || dependency.HasOnGraphStart();
m_isActiveDefaultObject = m_isActiveDefaultObject || dependency.IsActiveDefaultObject();
m_areAllChildrenPure = m_areAllChildrenPure && dependency.IsMarkedPure();
m_requiresConstructionParametersForDependencies = m_requiresConstructionParametersForDependencies || dependency.RequiresConstructionParameters();
}
In* SubgraphInterface::ModIn(const FunctionSourceId& sourceID)
{
return const_cast<In*>(FindIn(sourceID));
}
bool SubgraphInterface::operator==(const SubgraphInterface& rhs) const
{
// written out explicitly to aid debugging placement
if (m_isUserVariable != rhs.m_isUserVariable)
{
return false;
}
if (m_areAllChildrenPure != rhs.m_areAllChildrenPure)
{
@@ -524,13 +663,23 @@ namespace ScriptCanvas
{
return false;
}
if (m_isAllInputOutputShared != rhs.m_isAllInputOutputShared)
if (m_hasOnGraphStart != rhs.m_hasOnGraphStart)
{
return false;
}
if (m_hasOnGraphStart != rhs.m_hasOnGraphStart)
if (m_requiresConstructionParameters != rhs.m_requiresConstructionParameters)
{
return false;
}
if (m_requiresConstructionParametersForDependencies != rhs.m_requiresConstructionParametersForDependencies)
{
return false;
}
if (m_executionCharacteristics != rhs.m_executionCharacteristics)
{
return false;
}
@@ -555,11 +704,6 @@ namespace ScriptCanvas
return false;
}
if (m_executionCharacteristics != rhs.m_executionCharacteristics)
{
return false;
}
return true;
}
@@ -615,13 +759,13 @@ namespace ScriptCanvas
->Field("parsedName", &In::parsedName)
->Field("inputs", &In::inputs)
->Field("outs", &In::outs)
->Field("isPure", &In::isPure)
->Field("sourceID", &In::sourceID)
;
serializeContext->Class<SubgraphInterface>()
->Version(SubgraphInterfaceCpp::Version::Current)
->Field("areAllChildrenPure", &SubgraphInterface::m_areAllChildrenPure)
->Field("isAllInputOutputShared", &SubgraphInterface::m_isAllInputOutputShared)
->Field("hasOnGraphStart", &SubgraphInterface::m_hasOnGraphStart)
->Field("isActiveDefaultObject", &SubgraphInterface::m_isActiveDefaultObject)
->Field("ins", &SubgraphInterface::m_ins)
@@ -629,10 +773,22 @@ namespace ScriptCanvas
->Field("outKeys", &SubgraphInterface::m_outKeys)
->Field("namespacePath", &SubgraphInterface::m_namespacePath)
->Field("executionCharacteristics", &SubgraphInterface::m_executionCharacteristics)
->Field("requiresConstructionParameters", &SubgraphInterface::m_requiresConstructionParameters)
->Field("requiresConstructionParametersForDependencies", &SubgraphInterface::m_requiresConstructionParametersForDependencies)
;
}
}
bool SubgraphInterface::RequiresConstructionParameters() const
{
return m_requiresConstructionParameters || m_requiresConstructionParametersForDependencies;
}
bool SubgraphInterface::RequiresConstructionParametersForDependencies() const
{
return m_requiresConstructionParametersForDependencies;
}
void SubgraphInterface::SetNamespacePath(const NamespacePath& namespacePath)
{
m_namespacePath = namespacePath;
@@ -673,6 +829,132 @@ namespace ScriptCanvas
return result;
}
template<typename T>
AZStd::string EntryPerLine(const T& values, size_t tabs)
{
AZStd::string result;
for (const auto& value : values)
{
result += "\n";
result += ToString(value, tabs);
}
return result;
}
const char* YorN(bool value)
{
return value ? "Y" : "N";
}
AZStd::string ToString(const In& in, size_t tabs)
{
AZStd::string result = AZStd::string::format("In: %s, Pure: %s", in.displayName.c_str(), YorN(in.isPure));
if (!in.inputs.empty())
{
result += AZStd::string::format("%sInputs:", SubgraphInterfaceCpp::GetTabs(tabs + 1));
result += ToString(in.inputs, tabs + 2);
}
if (!in.outs.empty())
{
result += AZStd::string::format("%sOuts:", SubgraphInterfaceCpp::GetTabs(tabs + 1));
result += ToString(in.outs, false, tabs + 2);
}
return result;
}
AZStd::string ToString(const Ins& ins, size_t tabs)
{
return EntryPerLine(ins, tabs);
}
AZStd::string ToString(const Input& input, size_t tabs)
{
return AZStd::string::format("%sInput: %s, Type: %s", SubgraphInterfaceCpp::GetTabs(tabs), input.displayName.c_str(), Data::GetName(input.datum.GetType()).c_str());
}
AZStd::string ToString(const Inputs& inputs, size_t tabs)
{
return EntryPerLine(inputs, tabs);
}
AZStd::string ToString(const Out& out, bool isLatent, size_t tabs)
{
AZStd::string result = AZStd::string::format("%s%s: %s", SubgraphInterfaceCpp::GetTabs(tabs), isLatent ? "Latent" : "Out", out.displayName.c_str());
if (!out.outputs.empty())
{
result += AZStd::string::format("%sOutputs:", SubgraphInterfaceCpp::GetTabs(tabs + 1));
result += ToString(out.outputs, tabs + 2);
}
if (!out.returnValues.empty())
{
result += AZStd::string::format("%sReturn Values:", SubgraphInterfaceCpp::GetTabs(tabs + 1));
result += ToString(out.returnValues, tabs + 2);
}
return result;
}
AZStd::string ToString(const Outs& outs, bool isLatent, size_t tabs)
{
AZStd::string result;
for (const auto& value : outs)
{
result += "\n";
result += ToString(value, isLatent, tabs);
}
return result;
}
AZStd::string ToString(const Output& output, size_t tabs)
{
return AZStd::string::format("%sOutput: %s, Type: %s", SubgraphInterfaceCpp::GetTabs(tabs), output.displayName.c_str(), Data::GetName(output.type).c_str());
}
AZStd::string ToString(const Outputs& outputs, size_t tabs)
{
return EntryPerLine(outputs, tabs);
}
AZStd::string ToString(const SubgraphInterface& subgraphInterface)
{
AZStd::string result("\n");
result += subgraphInterface.GetName();
result += "\n";
result += AZStd::string::format("Is Active By Default: %s\n", YorN(subgraphInterface.IsActiveDefaultObject()));
result += AZStd::string::format("Is Latent: %s\n", YorN(subgraphInterface.IsLatent()));
result += AZStd::string::format("Is Pure: %s\n", YorN(subgraphInterface.GetExecutionCharacteristics() == ExecutionCharacteristics::Pure));
result += AZStd::string::format("Is User Nodeable: %s\n", YorN(subgraphInterface.IsUserNodeable()));
result += AZStd::string::format("Has Any Functionality: %s\n", YorN(subgraphInterface.HasAnyFunctionality()));
result += AZStd::string::format("Has On Graph Start: %s\n", YorN(subgraphInterface.HasOnGraphStart()));
const auto& ins = subgraphInterface.GetIns();
if (!ins.empty())
{
result += "Ins:";
result += ToString(ins, 1);
}
const auto& latents = subgraphInterface.GetLatentOuts();
if (!latents.empty())
{
result += "Latents:";
result += ToString(latents, 1);
}
result += "\n";
return result;
}
SubgraphInterfacePtrConst SubgraphInterfaceSystem::GetMap(const FunctionSourceId& nodeTypeId) const
{
auto iter = m_mapsByNodeType.find(nodeTypeId);
@@ -695,5 +977,5 @@ namespace ScriptCanvas
m_mapsByNodeType.insert({ nodeTypeId, executionMap });
return true;
}
}
}
}
@@ -99,15 +99,16 @@ namespace ScriptCanvas
AZ_TYPE_INFO(In, "{DFDA32F7-41D2-45BB-8ADF-876679053836}");
AZ_CLASS_ALLOCATOR(In, AZ::SystemAllocator, 0);
bool isPure = false;
AZStd::string displayName;
AZStd::string parsedName;
Inputs inputs;
Outs outs;
FunctionSourceId sourceID;
bool operator==(const In& rhs) const;
AZ_INLINE bool IsBranch() const { return outs.size() > 1; }
// #functions2 In-sensitive parsing. convert pure branches to mini-nodeables and provide a creation function
inline bool IsBranch() const { return outs.size() > 1; }
};
using Ins = AZStd::vector<In>;
@@ -131,6 +132,10 @@ namespace ScriptCanvas
void AddLatent(Out&& out);
const In* FindIn(const FunctionSourceId& sourceID) const;
const Out* FindLatent(const FunctionSourceId& sourceID) const;
ExecutionCharacteristics GetExecutionCharacteristics() const;
const In* GetIn(const AZStd::string& in) const;
@@ -141,6 +146,10 @@ namespace ScriptCanvas
size_t GetInCount() const;
size_t GetInCountPure() const;
size_t GetInCountNotPure() const;
const Inputs* GetInput(const AZStd::string& in) const;
const Out& GetLatentOut(size_t index) const;
@@ -151,9 +160,10 @@ namespace ScriptCanvas
const Outs& GetLatentOuts() const;
// \todo for max optimization this would be In sensitive
LexicalScope GetLexicalScope() const;
LexicalScope GetLexicalScope(const In& in) const;
AZStd::string GetName() const;
const NamespacePath& GetNamespacePath() const;
@@ -169,8 +179,6 @@ namespace ScriptCanvas
bool IsActiveDefaultObject() const;
bool IsAllInputOutputShared() const;
AZ::Outcome<bool> IsBranch(const AZStd::string& in) const;
// returns true iff there is at least one latent out
@@ -180,6 +188,12 @@ namespace ScriptCanvas
bool IsParsedPure() const;
bool IsUserNodeable() const;
bool IsUserVariable() const;
bool HasAnyFunctionality() const;
bool HasBranches() const;
bool HasIn(const FunctionSourceId& sourceID) const;
@@ -195,24 +209,35 @@ namespace ScriptCanvas
bool HasOutput(const VariableId& sourceID) const;
// returns true iff there is no public access to Ins or Latents
// \note The subgraph could still DO something, and be useful
// \note The subgraph could still DO something, and be useful, it could respond to tick bus or on graph start
bool HasPublicFunctionality() const;
void MarkActiveDefaultObject();
void MarkAllInputOutputShared();
void MarkActiveDefaultObject();
void MarkExecutionCharacteristics(ExecutionCharacteristics characteristics);
void MarkOnGraphStart();
void MergeExecutionCharacteristics(const SubgraphInterface& dependency);
void MarkRequiresConstructionParameters();
void MarkRequiresConstructionParametersForDependencies();
// #sc_user_data_type expose this to users directly, so they can say "I don't just want to make a component with this, I want to drop it right into another graph"
void MarkUserVariable();
void MergeExecutionCharacteristics(const SubgraphInterface & dependency);
In* ModIn(const FunctionSourceId & sourceID);
bool operator==(const SubgraphInterface& rhs) const;
// Populates the list of out keys
void Parse();
bool RequiresConstructionParameters() const;
bool RequiresConstructionParametersForDependencies() const;
void SetNamespacePath(const NamespacePath& namespacePath);
void TakeNamespacePath(NamespacePath&& namespacePath);
@@ -220,17 +245,20 @@ namespace ScriptCanvas
AZStd::string ToExecutionString() const;
private:
bool m_isUserVariable = false;
bool m_areAllChildrenPure = true;
// Does this graph have any (automatic) connection to buses or other latent activity,
// regardless of public exposure to out?
// Does this graph have any (automatic) connection to buses or other latent activity, or even on graph start
// regardless of public exposure to in/out?
bool m_isActiveDefaultObject = false;
// all input/output are used in every in/out/latent slot?
bool m_isAllInputOutputShared = false;
bool m_hasOnGraphStart = false;
bool m_requiresConstructionParameters = false;
bool m_requiresConstructionParametersForDependencies = false;
ExecutionCharacteristics m_executionCharacteristics = ExecutionCharacteristics::Pure;
Ins m_ins;
@@ -242,8 +270,37 @@ namespace ScriptCanvas
const Out* FindImmediateOut(const AZStd::string& in, const AZStd::string& out) const;
const In* FindIn(const AZStd::string& inSlotId) const;
const Out* FindLatentOut(const AZStd::string& latent) const;
LexicalScope GetLexicalScope(bool isSourcePure) const;
#if defined(FUNCTION_LEGACY_SUPPORT_ENABLED)
public:
bool IsAllInputOutputShared() const;
// all input/output are used in every in/out/latent slot?
bool m_isAllInputOutputShared = false;
void MarkAllInputOutputShared();
#endif
};
AZStd::string ToString(const In& in, size_t tabs = 0);
AZStd::string ToString(const Ins& ins, size_t tabs = 0);
AZStd::string ToString(const Input& input, size_t tabs = 1);
AZStd::string ToString(const Inputs& inputs, size_t tabs = 1);
AZStd::string ToString(const Out& out, bool isLatent, size_t tabs = 0);
AZStd::string ToString(const Outs& out, bool isLatent, size_t tabs = 0);
AZStd::string ToString(const Output& output, size_t tabs = 1);
AZStd::string ToString(const Outputs& outputs, size_t tabs = 1);
AZStd::string ToString(const SubgraphInterface& subgraphInterface);
using SubgraphInterfacePtrConst = AZStd::shared_ptr<const SubgraphInterface>;
using InterfacesByNodeType = AZStd::unordered_map<FunctionSourceId, SubgraphInterfacePtrConst>;
@@ -268,7 +325,5 @@ namespace ScriptCanvas
private:
InterfacesByNodeType m_mapsByNodeType;
};
}
}
}
@@ -17,9 +17,29 @@
namespace SubgraphInterfaceUtilityCpp
{
const constexpr size_t k_defaultOutIndex = 1;
const constexpr size_t k_uniqueOutIndex = 0;
const constexpr size_t k_signatureIndex = 1;
const constexpr AZ::u64 k_defaultOutIdSignature = 0x3ACF20E73ACF20E7ull;
const constexpr AZ::u64 k_functionSourceIdObjectSignature = 0xADC636A91EA5433Aull;
const constexpr AZ::u64 k_functionSourceIdNodeableSignature = 0xAD71FC30CA2E468Cull;
using namespace ScriptCanvas;
using namespace ScriptCanvas::Grammar;
bool IsSignatureId(size_t index, AZ::u64 signature, const FunctionSourceId& id)
{
const AZ::u64* idData = reinterpret_cast<const AZ::u64*>(id.data);
return idData[index] == signature;
}
FunctionSourceId MakeSignatureId(size_t index, AZ::u64 signature, const FunctionSourceId& id)
{
FunctionSourceId signatureId = id;
AZ::u64* idData = reinterpret_cast<AZ::u64*>(signatureId.data);
idData[index] = signature;
return signatureId;
}
}
namespace ScriptCanvas
@@ -30,17 +50,37 @@ namespace ScriptCanvas
bool IsDefaultOutId(const FunctionSourceId& id)
{
const AZ::u64* idData = reinterpret_cast<const AZ::u64*>(id.data);
return idData[k_defaultOutIndex] == k_defaultOutIdSignature;
return IsSignatureId(k_signatureIndex, k_defaultOutIdSignature, id);
}
bool IsFunctionSourceIdObject(const FunctionSourceId& id)
{
return IsSignatureId(k_signatureIndex, k_functionSourceIdObjectSignature, id);
}
bool IsFunctionSourceIdNodeable(const FunctionSourceId& id)
{
return IsSignatureId(k_signatureIndex, k_functionSourceIdNodeableSignature, id);
}
bool IsReservedId(const FunctionSourceId& id)
{
return IsDefaultOutId(id) || IsFunctionSourceIdNodeable(id) || IsFunctionSourceIdObject(id);
}
FunctionSourceId MakeDefaultOutId(const FunctionSourceId& id)
{
FunctionSourceId defaultOut = id;
AZ::u64* idData = reinterpret_cast<AZ::u64*>(defaultOut.data);
idData[k_defaultOutIndex] = k_defaultOutIdSignature;
AZ_Assert(idData[k_uniqueOutIndex] != k_defaultOutIdSignature, "the default out must also be unique");
return defaultOut;
return MakeSignatureId(k_signatureIndex, k_defaultOutIdSignature, id);
}
FunctionSourceId MakeFunctionSourceIdObject()
{
return MakeSignatureId(k_signatureIndex, k_functionSourceIdObjectSignature, FunctionSourceId());
}
FunctionSourceId MakeFunctionSourceIdNodeable()
{
return MakeSignatureId(k_signatureIndex, k_functionSourceIdNodeableSignature, FunctionSourceId());
}
bool OutIdIsEqual(const FunctionSourceId& lhs, const FunctionSourceId& rhs)
@@ -26,8 +26,18 @@ namespace ScriptCanvas
{
bool IsDefaultOutId(const FunctionSourceId& id);
bool IsFunctionSourceIdObject(const FunctionSourceId& id);
bool IsFunctionSourceIdNodeable(const FunctionSourceId& id);
bool IsReservedId(const FunctionSourceId& id);
FunctionSourceId MakeDefaultOutId(const FunctionSourceId& inID);
FunctionSourceId MakeFunctionSourceIdObject();
FunctionSourceId MakeFunctionSourceIdNodeable();
bool OutIdIsEqual(const FunctionSourceId& lhs, const FunctionSourceId& rhs);
Ins CreateInsFromBehaviorContextMethods(const AZStd::string& className, const AZ::BehaviorContext& behaviorContext, const AZStd::unordered_set<AZStd::string>& branchingMethods);
@@ -59,13 +59,11 @@ namespace ScriptCanvas
ActivationInputRange Context::CreateActivateInputRange(ActivationData& activationData)
{
const RuntimeData& runtimeData = activationData.runtimeData;
ActivationInputRange rangeOut;
ActivationInputRange rangeOut = runtimeData.m_activationInputRange;
rangeOut.inputs = activationData.storage.begin();
rangeOut.nodeableCount = runtimeData.m_activationInputRange.nodeableCount;
rangeOut.variableCount = runtimeData.m_activationInputRange.variableCount;
rangeOut.entityIdCount = runtimeData.m_activationInputRange.entityIdCount;
rangeOut.totalCount = rangeOut.nodeableCount + rangeOut.variableCount + rangeOut.entityIdCount;
AZ_Assert(rangeOut.totalCount <= activationData.storage.size(), "Too many initial arguments for activation. "
"Consider increasing size, source of ActivationInputArray, or breaking up the source graph");
// nodeables
{
@@ -97,6 +95,7 @@ namespace ScriptCanvas
}
// (must always be re-mapped) EntityId
if (!runtimeData.m_input.m_entityIds.empty())
{
AZ::SliceComponent::EntityIdToEntityIdMap loadedEntityIdMap;
AzFramework::EntityContextId owningContextId = AzFramework::EntityContextId::CreateNull();
@@ -110,7 +109,7 @@ namespace ScriptCanvas
+ runtimeData.m_activationInputRange.nodeableCount
+ runtimeData.m_activationInputRange.variableCount;
const auto entityIdTypeId = azrtti_typeid< Data::EntityIDType>();
const auto entityIdTypeId = azrtti_typeid<Data::EntityIDType>();
for (auto& idEntityPair : runtimeData.m_input.m_entityIds)
{
destVariableIter->m_typeId = entityIdTypeId;
@@ -141,22 +140,20 @@ namespace ScriptCanvas
return rangeOut;
}
void Context::IntializeActivationInputs(RuntimeData& runtimeData)
void Context::IntializeActivationInputs(RuntimeData& runtimeData, AZ::BehaviorContext& behaviorContext)
{
AZ::BehaviorContext* behaviorContext(nullptr);
AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationRequests::GetBehaviorContext);
AZ_Assert(behaviorContext, "missing behavior context");
AZStd::vector<AZ::BehaviorValueParameter>& parameters = runtimeData.m_activationInputStorage;
parameters.reserve(runtimeData.m_input.GetParameterSize());
auto& range = runtimeData.m_activationInputRange;
range.requiresDependencyConstructionParameters = runtimeData.RequiresDependencyConstructionParameters();
parameters.reserve(runtimeData.m_input.GetConstructorParameterCount());
for (const Nodeable* nodeable : runtimeData.m_input.m_nodeables)
{
AZ::BehaviorValueParameter bvp;
bvp.m_typeId = azrtti_typeid(nodeable);
const auto classIter(behaviorContext->m_typeToClassMap.find(bvp.m_typeId));
AZ_Assert(classIter != behaviorContext->m_typeToClassMap.end(), "No class by typeID of %s in the behavior context!", bvp.m_typeId.ToString<AZStd::string>().c_str());
const auto classIter(behaviorContext.m_typeToClassMap.find(bvp.m_typeId));
AZ_Assert(classIter != behaviorContext.m_typeToClassMap.end(), "No class by typeID of %s in the behavior context!", bvp.m_typeId.ToString<AZStd::string>().c_str());
bvp.m_azRtti = classIter->second->m_azRtti;
bvp.m_value = const_cast<Nodeable*>(nodeable);
parameters.push_back(bvp);
@@ -167,8 +164,8 @@ namespace ScriptCanvas
const Datum* datum = &idDatumPair.second;
AZ::BehaviorValueParameter bvp;
bvp.m_typeId = datum->GetType().GetAZType();
const auto classIter(behaviorContext->m_typeToClassMap.find(bvp.m_typeId));
bvp.m_azRtti = classIter != behaviorContext->m_typeToClassMap.end() ? classIter->second->m_azRtti : nullptr;
const auto classIter(behaviorContext.m_typeToClassMap.find(bvp.m_typeId));
bvp.m_azRtti = classIter != behaviorContext.m_typeToClassMap.end() ? classIter->second->m_azRtti : nullptr;
bvp.m_value = const_cast<void*>(datum->GetAsDanger());
parameters.push_back(bvp);
}
@@ -180,20 +177,14 @@ namespace ScriptCanvas
parameters.push_back(bvp);
}
runtimeData.m_activationInputRange.inputs = parameters.begin();
runtimeData.m_activationInputRange.nodeableCount = runtimeData.m_input.m_nodeables.size();
runtimeData.m_activationInputRange.variableCount = runtimeData.m_input.m_variables.size();
runtimeData.m_activationInputRange.entityIdCount = runtimeData.m_input.m_entityIds.size();
range.inputs = parameters.begin();
range.nodeableCount = runtimeData.m_input.m_nodeables.size();
range.variableCount = runtimeData.m_input.m_variables.size();
range.entityIdCount = runtimeData.m_input.m_entityIds.size();
range.totalCount = range.nodeableCount + range.variableCount + range.entityIdCount;
}
void Context::IntializeAssetData(RuntimeData& runtimeData)
{
// \todo, the stack push functions could be retrieved here
IntializeActivationInputs(runtimeData);
IntializeStaticCloners(runtimeData);
}
void Context::IntializeStaticCloners(RuntimeData& runtimeData)
void Context::InitializeActivationData(RuntimeData& runtimeData)
{
AZ::BehaviorContext* behaviorContext(nullptr);
AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationRequests::GetBehaviorContext);
@@ -203,12 +194,20 @@ namespace ScriptCanvas
return;
}
// \todo, the stack push functions could be retrieved here
IntializeActivationInputs(runtimeData, *behaviorContext);
IntializeStaticCloners(runtimeData, *behaviorContext);
}
// This does not have to recursively initialize dependent assets, as this is called by asset handler
void Context::IntializeStaticCloners(RuntimeData& runtimeData, AZ::BehaviorContext& behaviorContext)
{
runtimeData.m_cloneSources.reserve(runtimeData.m_input.m_staticVariables.size());
for (AZStd::pair<VariableId, AZStd::any>& staticSource : runtimeData.m_input.m_staticVariables)
{
AZStd::any& anySource = staticSource.second;
auto bcClass = AZ::BehaviorContextHelper::GetClass(behaviorContext, anySource.type());
auto bcClass = AZ::BehaviorContextHelper::GetClass(&behaviorContext, anySource.type());
AZ_Assert(bcClass, "BehaviorContext class for type %s was deleted", anySource.type().ToString<AZStd::string>().c_str());
runtimeData.m_cloneSources.emplace_back(*bcClass, AZStd::any_cast<void>(&anySource));
}
@@ -23,7 +23,7 @@ namespace ScriptCanvas
namespace Execution
{
using ActivationInputArray = AZStd::array<AZ::BehaviorValueParameter, 256>;
using ActivationInputArray = AZStd::array<AZ::BehaviorValueParameter, 128>;
struct ActivationData
{
@@ -39,6 +39,7 @@ namespace ScriptCanvas
struct ActivationInputRange
{
AZ::BehaviorValueParameter* inputs = nullptr;
bool requiresDependencyConstructionParameters = false;
size_t nodeableCount = 0;
size_t variableCount = 0;
size_t entityIdCount = 0;
@@ -52,12 +53,12 @@ namespace ScriptCanvas
AZ_CLASS_ALLOCATOR(Context, AZ::SystemAllocator, 0);
static ActivationInputRange CreateActivateInputRange(ActivationData& activationData);
static void IntializeAssetData(RuntimeData& runtimeData);
static void InitializeActivationData(RuntimeData& runtimeData);
static void UnloadData(RuntimeData& runtimeData);
private:
static void IntializeActivationInputs(RuntimeData& runtimeData);
static void IntializeStaticCloners(RuntimeData& runtimeData);
static void IntializeActivationInputs(RuntimeData& runtimeData, AZ::BehaviorContext& behaviorContext);
static void IntializeStaticCloners(RuntimeData& runtimeData, AZ::BehaviorContext& behaviorContext);
};
}
@@ -35,35 +35,26 @@ namespace ScriptCanvas
ExecutionStatePtr ExecutionState::Create(const ExecutionStateConfig& config)
{
switch (config.runtimeData.m_input.m_execution)
{
case ExecutionMode::Interpreted:
{
if (config.runtimeData.m_script.GetId().IsValid())
{
switch (config.runtimeData.m_input.m_executionCharacteristics)
{
case Grammar::ExecutionCharacteristics::PerEntity:
return AZStd::make_shared<ExecutionStateInterpretedPerActivation>(config);
Grammar::ExecutionStateSelection selection = config.runtimeData.m_input.m_executionSelection;
case Grammar::ExecutionCharacteristics::Pure:
return AZStd::make_shared<ExecutionStateInterpretedPure>(config);
switch (selection)
{
case Grammar::InterpretedPure:
return AZStd::make_shared<ExecutionStateInterpretedPure>(config);
case Grammar::InterpretedPureOnGraphStart:
return AZStd::make_shared<ExecutionStateInterpretedPureOnGraphStart>(config);
default:
break;
}
}
}
break;
case Grammar::InterpretedObject:
return AZStd::make_shared<ExecutionStateInterpretedPerActivation>(config);
case ExecutionMode::Native:
default:
AZ_Assert(false, "not done yet!");
return nullptr;
;
} // switch (config.executionMode)
return nullptr;
case Grammar::InterpretedObjectOnGraphStart:
return AZStd::make_shared<ExecutionStateInterpretedPerActivationOnGraphStart>(config);
default:
AZ_Assert(false, "Unsupported ScriptCanvas execution selection");
return nullptr;
}
}
AZ::Data::AssetId ExecutionState::GetAssetId() const
@@ -96,6 +87,11 @@ namespace ScriptCanvas
return m_component->GetScriptCanvasId();
}
const VariableData& ExecutionState::GetVariableOverrides() const
{
return m_component->GetVariableOverrides();
}
void ExecutionState::Reflect(AZ::ReflectContext* reflectContext)
{
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(reflectContext))
@@ -110,7 +106,9 @@ namespace ScriptCanvas
ExecutionStateInterpreted::Reflect(reflectContext);
ExecutionStateInterpretedPerActivation::Reflect(reflectContext);
ExecutionStateInterpretedPerActivationOnGraphStart::Reflect(reflectContext);
ExecutionStateInterpretedPure::Reflect(reflectContext);
ExecutionStateInterpretedPureOnGraphStart::Reflect(reflectContext);
ExecutionStateInterpretedSingleton::Reflect(reflectContext);
}
@@ -76,6 +76,8 @@ namespace ScriptCanvas
AZ::EntityId GetScriptCanvasId() const;
const VariableData& GetVariableOverrides() const;
virtual void Initialize() = 0;
ExecutionStatePtr SharedFromThis();
@@ -64,7 +64,7 @@ namespace ExecutionInterpretedAPICpp
int DeleteNodeable(lua_State* lua)
{
AZ::LuaUserData* userData = reinterpret_cast<AZ::LuaUserData*>(lua_touserdata(lua, -1));
AZ_Assert(userData && userData->magicData == AZ_CRC("AZLuaUserData", 0x7d76a773), "this isn't user data");
AZ_Assert(userData && userData->magicData == AZ_CRC_CE("AZLuaUserData"), "this isn't user data");
delete reinterpret_cast<ScriptCanvas::Nodeable*>(userData->value);
userData->value = nullptr;
return 0;
@@ -413,7 +413,7 @@ namespace ScriptCanvas
AZ_Assert(lua_istable(lua, -1), "Error in compiled lua file, 2nd argument to OverrideNodeableMetatable is not a Lua table");
auto userData = reinterpret_cast<AZ::LuaUserData*>(lua_touserdata(lua, -2));
AZ_Assert(userData && userData->magicData == AZ_CRC("AZLuaUserData", 0x7d76a773), "this isn't user data");
AZ_Assert(userData && userData->magicData == AZ_CRC_CE("AZLuaUserData"), "this isn't user data");
// Lua: LuaUserData::nodeable, class_mt
lua_newtable(lua);
// Lua: LuaUserData::nodeable, class_mt, proxy
@@ -472,6 +472,8 @@ namespace ScriptCanvas
lua_register(lua, k_NodeableSetExecutionOutResultName, &SetExecutionOutResult);
lua_register(lua, k_NodeableSetExecutionOutUserSubgraphName, &SetExecutionOutUserSubgraph);
lua_register(lua, k_OverrideNodeableMetatableName, &OverrideNodeableMetatable);
lua_register(lua, k_UnpackDependencyConstructionArgsFunctionName, &UnpackDependencyConstructionArgs);
lua_register(lua, k_UnpackDependencyConstructionArgsLeafFunctionName, &UnpackDependencyConstructionArgsLeaf);
#if defined(PERFORMANCE_BUILD)
lua_pushboolean(lua, true);
@@ -693,6 +695,49 @@ namespace ScriptCanvas
AZ::ScriptSystemRequestBus::Broadcast(&AZ::ScriptSystemRequests::ClearAssetReferences, runtimeData.m_script.GetId());
}
struct DependencyConstructionPack
{
ExecutionStateInterpreted* executionState;
AZStd::vector<AZ::Data::Asset<RuntimeAsset>>* dependentAssets;
const size_t dependentAssetsIndex;
RuntimeData& runtimeData;
};
DependencyConstructionPack UnpackDependencyConstructionArgsSanitize(lua_State* lua)
{
auto executionState = AZ::ScriptValue<ExecutionStateInterpreted*>::StackRead(lua, 1);
AZ_Assert(executionState, "Error in compiled lua file, 1st argument to UnpackDependencyArgs is not an ExecutionStateInterpreted");
AZ_Assert(lua_islightuserdata(lua, 2), "Error in compiled lua file, 2nd argument to UnpackDependencyArgs is not userdata (AZStd::vector<AZ::Data::Asset<RuntimeAsset>>*), but a :%s", lua_typename(lua, 2));
auto dependentAssets = reinterpret_cast<AZStd::vector<AZ::Data::Asset<RuntimeAsset>>*>(lua_touserdata(lua, 2));
AZ_Assert(lua_isinteger(lua, 3), "Error in compiled Lua file, 3rd argument to UnpackDependencyArgs is not a number");
const size_t dependentAssetsIndex = lua_tointeger(lua, 3);
return DependencyConstructionPack{ executionState, dependentAssets, dependentAssetsIndex, (*dependentAssets)[dependentAssetsIndex].Get()->m_runtimeData };
}
int Unpack(lua_State* lua, DependencyConstructionPack& args)
{
ActivationInputArray storage;
ActivationData data(args.executionState->GetEntityId(), args.executionState->GetVariableOverrides(), args.runtimeData, storage);
ActivationInputRange range = Execution::Context::CreateActivateInputRange(data);
PushActivationArgs(lua, range.inputs, range.totalCount);
return range.totalCount;
}
int UnpackDependencyConstructionArgs(lua_State* lua)
{
// Lua: executionState, dependentAssets, dependentAssetsIndex
DependencyConstructionPack pack = UnpackDependencyConstructionArgsSanitize(lua);
lua_pushlightuserdata(lua, const_cast<void*>(reinterpret_cast<const void*>(&pack.runtimeData.m_requiredAssets)));
return 1 + Unpack(lua, pack);
}
int UnpackDependencyConstructionArgsLeaf(lua_State* lua)
{
// Lua: executionState, dependentAssets, dependentAssetsIndex
DependencyConstructionPack constructionArgs = UnpackDependencyConstructionArgsSanitize(lua);
return Unpack(lua, constructionArgs);
}
}
}
@@ -45,6 +45,8 @@ namespace ScriptCanvas
int InterpretedSafeCall(lua_State* lua, int argCount, int returnValueCount);
void InterpretedUnloadData(RuntimeData& runtimeData);
void InitializeInterpretedStatics(const RuntimeData& runtimeData);
int InitializeNodeableOutKeys(lua_State* lua);
@@ -76,8 +78,13 @@ namespace ScriptCanvas
bool StackRead(lua_State* lua, AZ::BehaviorContext* context, int index, AZ::BehaviorValueParameter& param, AZ::StackVariableAllocator* allocator);
void InterpretedUnloadData(RuntimeData& runtimeData);
// Lua: executionState, dependentAssets, dependentAssetsIndex
// leaves dependentAssets[dependentAssetsIndex], and all the construction args at the top of the stack
int UnpackDependencyConstructionArgs(lua_State* lua);
// Lua: executionState, dependentAssets, dependentAssetsIndex
// leaves all the construction args at the top of the stack
int UnpackDependencyConstructionArgsLeaf(lua_State* lua);
}
}
@@ -51,8 +51,9 @@ namespace ScriptCanvas
AZ::StackVariableAllocator tempData;
AZ::BehaviorValueParameter address = BehaviorValueParameterFromTypeIdString(aztypeidStr, behaviorContext);
// \todo check for nil if required...if the address is a BCO...and is NOT a pointer type...nil check is required
// that will have to be checked at compile time actually.
AZ_Verify(StackRead(lua, &behaviorContext, -1, address, &tempData), "Error in compiled lua file, failed to read 2nd argument to EBusHandlerConnectTo");
lua_pushboolean(lua, ebusHandler->ConnectTo(address));
return 1;
}
@@ -39,41 +39,7 @@ namespace ScriptCanvas
}
void ExecutionStateInterpretedPerActivation::Execute()
{
const auto registryIndex = GetLuaRegistryIndex();
AZ_Assert(registryIndex != LUA_NOREF, "ExecutionStateInterpretedPerActivation::Activate called but Init is was never called");
auto& lua = m_luaState;
// Lua:
lua_rawgeti(lua, LUA_REGISTRYINDEX, registryIndex);
// Lua: instance
lua_getfield(lua, -1, Grammar::k_OnGraphStartFunctionName);
// Lua: instance, graph_VM['k_OnGraphStartFunctionName']
if (lua_isfunction(lua, -1))
{
// Lua: instance, graph_VM.k_OnGraphStartFunctionName
lua_pushvalue(lua, -2);
// Lua: instance, graph_VM.k_OnGraphStartFunctionName, instance
const int result = Execution::InterpretedSafeCall(lua, 1, 0);
// Lua: instance ?
if (result == LUA_OK)
{
// Lua: instance
lua_pop(lua, 1);
}
else
{
// Lua: instance, error
lua_pop(lua, 2);
}
}
else
{
// Lua: instance, nil
lua_pop(lua, 2);
}
// Lua:
m_deactivationRequired = true;
}
{}
void ExecutionStateInterpretedPerActivation::Initialize()
{
@@ -86,9 +52,22 @@ namespace ScriptCanvas
Execution::ActivationInputArray storage;
Execution::ActivationData data(*m_component, storage);
Execution::ActivationInputRange range = Execution::Context::CreateActivateInputRange(data);
Execution::PushActivationArgs(lua, range.inputs, range.totalCount);
// Lua: graph_VM, graph_VM['new'], userdata<ExecutionState>, args...
AZ::Internal::LuaSafeCall(lua, aznumeric_caster(1 + range.totalCount), 1);
if (range.requiresDependencyConstructionParameters)
{
lua_pushlightuserdata(lua, const_cast<void*>(reinterpret_cast<const void*>(&data.runtimeData.m_requiredAssets)));
// Lua: graph_VM, graph_VM['new'], userdata<ExecutionState>, dependencies
Execution::PushActivationArgs(lua, range.inputs, range.totalCount);
// Lua: graph_VM, graph_VM['new'], userdata<ExecutionState>, dependencies, args...
AZ::Internal::LuaSafeCall(lua, aznumeric_caster(2 + range.totalCount), 1);
}
else
{
Execution::PushActivationArgs(lua, range.inputs, range.totalCount);
// Lua: graph_VM, graph_VM['new'], userdata<ExecutionState>, args...
AZ::Internal::LuaSafeCall(lua, aznumeric_caster(1 + range.totalCount), 1);
}
// Lua: graph_VM, instance
ReferenceExecutionState();
// Lua: graph_VM,
@@ -100,7 +79,7 @@ namespace ScriptCanvas
void ExecutionStateInterpretedPerActivation::StopExecution()
{
const auto registryIndex = GetLuaRegistryIndex();
AZ_Assert(registryIndex != LUA_NOREF, "ExecutionStateInterpretedPerActivation::Deactivate called but Initialize is was never called");
AZ_Assert(registryIndex != LUA_NOREF, "ExecutionStateInterpretedPerActivation::StopExecution called but Initialize is was never called");
auto& lua = m_luaState;
// Lua:
lua_rawgeti(lua, LUA_REGISTRYINDEX, registryIndex);
@@ -125,4 +104,45 @@ namespace ScriptCanvas
}
}
ExecutionStateInterpretedPerActivationOnGraphStart::ExecutionStateInterpretedPerActivationOnGraphStart(const ExecutionStateConfig& config)
: ExecutionStateInterpretedPerActivation(config)
{}
void ExecutionStateInterpretedPerActivationOnGraphStart::Execute()
{
const auto registryIndex = GetLuaRegistryIndex();
AZ_Assert(registryIndex != LUA_NOREF, "ExecutionStateInterpretedPerActivationOnGraphStart::Execute called but Initialize is was never called");
auto& lua = m_luaState;
// Lua:
lua_rawgeti(lua, LUA_REGISTRYINDEX, registryIndex);
// Lua: instance
lua_getfield(lua, -1, Grammar::k_OnGraphStartFunctionName);
// Lua: instance, graph_VM.k_OnGraphStartFunctionName
lua_pushvalue(lua, -2);
// Lua: instance, graph_VM.k_OnGraphStartFunctionName, instance
const int result = Execution::InterpretedSafeCall(lua, 1, 0);
// Lua: instance ?
if (result == LUA_OK)
{
// Lua: instance
lua_pop(lua, 1);
}
else
{
// Lua: instance, error
lua_pop(lua, 2);
}
// Lua:
m_deactivationRequired = true;
}
void ExecutionStateInterpretedPerActivationOnGraphStart::Reflect(AZ::ReflectContext* reflectContext)
{
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(reflectContext))
{
behaviorContext->Class<ExecutionStateInterpretedPerActivationOnGraphStart>()
;
}
}
}
@@ -35,6 +35,23 @@ namespace ScriptCanvas
void StopExecution() override;
protected:
bool m_deactivationRequired = false;
};
class ExecutionStateInterpretedPerActivationOnGraphStart
: public ExecutionStateInterpretedPerActivation
{
public:
AZ_RTTI(ExecutionStateInterpretedPerActivationOnGraphStart, "{039AA0BF-C179-4F9C-A7CD-248F24453C4B}", ExecutionStateInterpretedPerActivation);
AZ_CLASS_ALLOCATOR(ExecutionStateInterpretedPerActivation, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* reflectContext);
ExecutionStateInterpretedPerActivationOnGraphStart(const ExecutionStateConfig& config);
void Execute() override;
private:
bool m_deactivationRequired = false;
};
@@ -22,17 +22,39 @@ namespace ScriptCanvas
{
ExecutionStateInterpretedPure::ExecutionStateInterpretedPure(const ExecutionStateConfig& config)
: ExecutionStateInterpreted(config)
{
}
{}
void ExecutionStateInterpretedPure::Execute()
{}
void ExecutionStateInterpretedPure::Initialize()
{}
void ExecutionStateInterpretedPure::StopExecution()
{}
void ExecutionStateInterpretedPure::Reflect(AZ::ReflectContext* reflectContext)
{
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(reflectContext))
{
behaviorContext->Class<ExecutionStateInterpretedPure>()
;
}
}
ExecutionStateInterpretedPureOnGraphStart::ExecutionStateInterpretedPureOnGraphStart(const ExecutionStateConfig& config)
: ExecutionStateInterpretedPure(config)
{}
// #functions2 dependency - ctor - args adjust for (pure only) on graph start args
void ExecutionStateInterpretedPureOnGraphStart::Execute()
{
// execute the script in a single call
auto lua = LoadLuaScript();
// Lua: graph_VM
AZ::Internal::azlua_getfield(lua, -1, Grammar::k_OnGraphStartFunctionName);
// Lua: graph_VM, graph_VM['k_OnGraphStartFunctionName']
AZ::Internal::LuaClassToStack(lua, this, azrtti_typeid<ExecutionStateInterpretedPure>(), AZ::ObjectToLua::ByReference, AZ::AcquisitionOnPush::None);
AZ::Internal::LuaClassToStack(lua, this, azrtti_typeid<ExecutionStateInterpretedPureOnGraphStart>(), AZ::ObjectToLua::ByReference, AZ::AcquisitionOnPush::None);
// Lua: graph_VM, graph_VM['k_OnGraphStartFunctionName'], userdata<ExecutionState>
Execution::ActivationInputArray storage;
Execution::ActivationData data(*m_component, storage);
@@ -52,18 +74,12 @@ namespace ScriptCanvas
lua_pop(lua, 2);
}
}
void ExecutionStateInterpretedPure::Initialize()
{}
void ExecutionStateInterpretedPure::StopExecution()
{}
void ExecutionStateInterpretedPure::Reflect(AZ::ReflectContext* reflectContext)
void ExecutionStateInterpretedPureOnGraphStart::Reflect(AZ::ReflectContext* reflectContext)
{
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(reflectContext))
{
behaviorContext->Class<ExecutionStateInterpretedPure>()
behaviorContext->Class<ExecutionStateInterpretedPureOnGraphStart>()
;
}
}
@@ -33,4 +33,18 @@ namespace ScriptCanvas
void StopExecution() override;
};
class ExecutionStateInterpretedPureOnGraphStart
: public ExecutionStateInterpretedPure
{
public:
AZ_RTTI(ExecutionStateInterpretedPureOnGraphStart, "{D4CA9731-31CE-4B27-A91F-6E71E1DE8B7D}", ExecutionStateInterpretedPure);
AZ_CLASS_ALLOCATOR(ExecutionStateInterpretedPureOnGraphStart, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* reflectContext);
ExecutionStateInterpretedPureOnGraphStart(const ExecutionStateConfig& config);
void Execute() override;
};
}
File diff suppressed because it is too large Load Diff
@@ -54,8 +54,9 @@ namespace ScriptCanvas
class AbstractCodeModel
: public AZStd::enable_shared_from_this<AbstractCodeModel>
{
public:
friend struct PrintMetaData;
public:
static bool RequiresCreationFunction(Data::eType type);
static AbstractCodeModelConstPtr Parse(const Source& source, bool terminateOnError = false, bool terminateOnInternalError = false);
@@ -68,11 +69,23 @@ namespace ScriptCanvas
~AbstractCodeModel();
AZStd::vector<Grammar::VariableConstPtr> CombineVariableLists
void AddError(ExecutionTreeConstPtr execution, ValidationConstPtr&& error) const;
AZStd::string AddTranslationVariableName(const AZStd::string& name) const;
AZStd::optional<AZStd::pair<size_t, Grammar::DependencyInfo>> CheckUserNodeableDependencyConstructionIndex(VariableConstPtr nodeable) const;
AZStd::vector<VariableConstPtr> CombineVariableLists
( const AZStd::vector<Nodeable*>& constructionNodeables
, const AZStd::vector<AZStd::pair<VariableId, Datum>>& constructionInputVariableIds
, const AZStd::vector<AZStd::pair<VariableId, Data::EntityIDType>>& entityIds) const;
AZStd::optional<AZStd::string> FindNodeableSimpleName(VariableConstPtr variable) const;
const AZStd::pair<Grammar::VariableConstPtr, AZStd::string>* FindStaticVariable(VariableConstPtr) const;
AZStd::vector<ExecutionTreeConstPtr> GetAllExecutionRoots() const;
const size_t* GetDebugInfoInIndex(ExecutionTreeConstPtr execution) const;
const size_t* GetDebugInfoOutIndex(ExecutionTreeConstPtr execution, size_t index) const;
@@ -83,7 +96,9 @@ namespace ScriptCanvas
const size_t* GetDebugInfoVariableSetIndex(OutputAssignmentConstPtr output) const;
const DependencyReport& GetDependencies() const;
const DebugSymbolMap& GetDebugMap() const;
const OrderedDependencies& GetOrderedDependencies() const;
EBusHandlingConstPtr GetEBusEventHandling(const Node*) const;
@@ -93,17 +108,21 @@ namespace ScriptCanvas
AZStd::vector<EventHandlingConstPtr> GetEventHandlings() const;
Grammar::ExecutionCharacteristics GetExecutionCharacteristics() const;
AZStd::vector<ExecutionTreeConstPtr> GetFunctions() const;
VariableConstPtr GetImplicitVariable(ExecutionTreeConstPtr execution) const;
AZStd::vector<VariableConstPtr> GetLocalVariablesUser() const;
const SubgraphInterface& GetInterface() const;
AZStd::vector<VariableConstPtr> GetMemberVariables() const;
const AZStd::unordered_set<VariableConstPtr>* GetLocalVariables(ExecutionTreeConstPtr execution) const;
AZStd::vector<NodeableParseConstPtr> GetNodeableParse() const;
Grammar::ExecutionCharacteristics GetRuntimeCharacteristics() const;
AZStd::sys_time_t GetParseDuration() const;
const ParsedRuntimeInputs& GetRuntimeInputs() const;
const Source& GetSource() const;
@@ -111,6 +130,10 @@ namespace ScriptCanvas
ExecutionTreeConstPtr GetStart() const;
const AZStd::vector<AZStd::pair<Grammar::VariableConstPtr, AZStd::string>>& GetStaticVariablesNames() const;
const AZStd::vector<AZStd::pair<Grammar::VariableConstPtr, AZStd::string>>& GetStaticVariablesNames(Grammar::ExecutionTreeConstPtr functionBlock) const;
const ValidationResults::ValidationEventList& GetValidationEvents() const { return m_validationEvents; }
VariableWriteHandlingConstPtr GetVariableHandling(const Slot* slot) const;
@@ -119,8 +142,6 @@ namespace ScriptCanvas
const AZStd::vector<VariableConstPtr>& GetVariables() const;
VariableScopeMeaning GetVariableScopeMeaning() const;
bool IsErrorFree() const;
// has modified data or handlers
@@ -134,9 +155,12 @@ namespace ScriptCanvas
bool IsUserNodeable(VariableConstPtr variable) const;
bool HasUserNodeableDependenciesInVariables() const;
template<typename T>
AZStd::vector<Grammar::VariableConstPtr> ToVariableList(const AZStd::vector<AZStd::pair<VariableId, T>>& source) const;
private:
//////////////////////////////////////////////////////////////////////////
// Internal parsing
//////////////////////////////////////////////////////////////////////////
@@ -145,29 +169,11 @@ namespace ScriptCanvas
bool m_hasOtherConnections = false;
AZStd::vector<VariableConstPtr> m_returnValuesOrReferences;
};
ExecutionTreePtr m_start;
AZStd::vector<const Nodes::Core::Start*> m_startNodes;
ScopePtr m_graphScope;
const Source m_source;
DependencyReport m_dependencies;
AZStd::unordered_set<VariableConstPtr> m_userNodeables;
AZStd::vector<VariableConstPtr> m_variables;
AZStd::vector<const Node*> m_possibleExecutionRoots;
VariableScopeMeaning m_variableScopeMeaning = VariableScopeMeaning::ValueInitialization;
// true iff there are no internal errors and no error validation events
bool m_isErrorFree = true;
// for post parsing validation
ValidationResults::ValidationEventList m_validationEvents;
DebugSymbolMap m_debugMap;
DebugSymbolMapReverse m_debugMapReverse;
void AddAllVariablesPreParse();
void AddAllVariablesPreParse_LegacyFunctions();
void AddDebugInformation();
void AddDebugInformation(ExecutionChild& execution);
@@ -182,8 +188,6 @@ namespace ScriptCanvas
void AddDebugInfiniteLoopDetectionInHandler(ExecutionTreePtr execution);
void AddError(ExecutionTreeConstPtr execution, ValidationConstPtr&& error) const;
void AddError(const AZ::EntityId& nodeId, ExecutionTreeConstPtr execution, const AZStd::string_view error) const;
VariablePtr AddMemberVariable(const Datum& datum, AZStd::string_view rawName);
@@ -228,15 +232,19 @@ namespace ScriptCanvas
bool CreateEventHandling(const Node& node);
bool CreateNodeableParse(const Node& node);
bool CheckCreateNodeableParse(const Node& node);
OutputAssignmentPtr CreateOutput(ExecutionTreePtr execution, const Slot& outputSlot, AZStd::string_view slotNameOverride, AZStd::string_view suffix);
OutputAssignmentPtr CreateOutputAssignment(VariableConstPtr variable);
bool CreateUserEventHandling(const Node& node);
bool CheckCreateUserEventHandling(const Node& node);
bool CreateUserFunctionDefinition(const Node& node);
bool CheckCreateUserFunctionDefinition(const Node& node);
void ConvertAllMemberVariablesToLocal(ExecutionTreePtr newSource);
void CreateUserFunctionDefinition(const Node& node, const Slot& entrySlot);
bool CreateVariableWriteHandling(const Node& node);
@@ -244,6 +252,8 @@ namespace ScriptCanvas
OutputAssignmentConstPtr CreateOutputData(ExecutionTreePtr execution, ExecutionChild& executionChild, const Slot& output);
void CullUnusedVariables();
// Execution cycle detection is done first, before parsing starts.
// This way, infinite loops in the parser execution itself are prevented, and input
// used from previous ACM execution nodes are properly handled.
@@ -251,34 +261,22 @@ namespace ScriptCanvas
// which properly respects both the Ordered Sequencer node, and multiple Execution Outs connections
// from a single slot.
// Errors from poorly routed input are NOT detected here, and should not be, those are detected later.
bool ExecutionContainsCycles(const Node& node, const Slot& outSlot) const;
bool ExecutionContainsCyclesRecurse(const Node& node, const Slot& outSlot) const;
bool ExecutionContainsCyclesRecurse(const EndpointsResolved& nextEndpoints, AZStd::unordered_set<const Slot*>& previousIns) const;
bool ExecutionContainsCyclesRecurse(const EndpointResolved& in, AZStd::unordered_set<const Slot*>& previousIns) const;
bool ExecutionContainsCyclesCheck(const Node& node, const Slot& outSlot);
ReturnValueConnections FindAssignments(ExecutionTreeConstPtr execution, const Slot& output);
VariableConstPtr FindMemberVariable(const AZ::EntityId& sourceNodeId) const;
VariableConstPtr FindVariable(const AZ::EntityId& sourceNodeId) const;
VariableConstPtr FindMemberVariable(const VariableId& sourceVariableId) const;
VariableConstPtr FindVariable(const VariableId& sourceVariableId) const;
VariableConstPtr FindReferencedVariableChecked(ExecutionTreeConstPtr execution, const Slot& slot) const;
AZStd::pair<ExecutionTreeConstPtr, VariableConstPtr> FindReturnValueOnThread(ExecutionTreeConstPtr executionNode, const Node* node, const Slot* slot) const;
AZStd::vector<ExecutionTreeConstPtr> GetAllExecutionRoots() const;
const SubgraphInterface& GetInterface() const;
AZStd::string GetOriginalVariableName(const VariableId& sourceVariableId);
AZStd::string GetOriginalVariableName(VariableConstPtr variable, const Node* node);
AZStd::string GetOutputSlotNameOverride(ExecutionTreePtr execution, const Slot& outputSlot);
AZStd::sys_time_t GetParseDuration() const;
VariableConstPtr GetReadVariable(ExecutionTreePtr execution);
VariableConstPtr GetWrittenVariable(ExecutionTreePtr execution);
@@ -289,6 +287,10 @@ namespace ScriptCanvas
AZStd::vector<ExecutionTreePtr> ModAllExecutionRoots();
AZStd::vector<AZStd::pair<Grammar::VariableConstPtr, AZStd::string>>& ModStaticVariablesNames();
AZStd::vector<AZStd::pair<Grammar::VariableConstPtr, AZStd::string>>& ModStaticVariablesNames(Grammar::ExecutionTreeConstPtr functionBlock);
ExecutionTreePtr OpenScope(ExecutionTreePtr parent, const Node* node, const Slot* outSlot) const;
void Parse();
@@ -308,7 +310,9 @@ namespace ScriptCanvas
};
VariableConstPtr ParseConnectedInputData(const Slot& inputSlot, ExecutionTreePtr executionWithInput, const EndpointsResolved& scriptCanvasNodesConnectedToInput, FirstNode firstNode);
SlotsOutcome ParseDataOutSlots(ExecutionTreePtr execution, ExecutionChild& executionChild) const;
void ParseConstructionInputVariables();
ConstSlotsOutcome ParseDataOutSlots(ExecutionTreePtr execution, ExecutionChild& executionChild) const;
void ParseDeactivation();
@@ -316,10 +320,16 @@ namespace ScriptCanvas
void ParseDependencies(const Node& node);
void ParseDependenciesAssetIndicies();
void ParseEntityIdInput(ExecutionTreePtr execution);
void ParseExecutionBreak(ExecutionTreePtr execution);
void ParseExecutionCharacteristics();
void ParseExecutionCharacteristics(ExecutionTreePtr execution);
void ParseExecutionCycleStatement(ExecutionTreePtr execution);
ExecutionTreePtr ParseExecutionForEachLoop(ExecutionTreePtr execution, const Slot& loopSlot, const Slot& breakSlot);
@@ -377,6 +387,8 @@ namespace ScriptCanvas
void ParseMultiExecutionPre(ExecutionTreePtr execution);
void ParseNodelingVariables(const Node& node, NodelingType nodelingType);
void ParseOperatorArithmetic(ExecutionTreePtr execution);
void ParseOutputData(ExecutionTreePtr execution, ExecutionChild& executionChild);
@@ -409,6 +421,9 @@ namespace ScriptCanvas
void ParseVariableHandling();
// tracks all local/member variable use, return true if uses a declared member variable
bool ParseVariableUseAndPurity(ExecutionTreePtr execution);
void PostParseErrorDetect(ExecutionTreePtr root);
void PostParseProcess(ExecutionTreePtr root);
@@ -419,8 +434,6 @@ namespace ScriptCanvas
void RemoveFromTree(ExecutionTreePtr execution);
protected:
struct ConnectionInPreviouslyExecutedScope
{
size_t m_childIndex = 0;
@@ -434,11 +447,18 @@ namespace ScriptCanvas
ExecutionTreePtr m_mostParent;
};
struct ReturnValueDescription
{
AZStd::vector<VariablePtr> returnValues;
size_t outCallCount = 1;
};
struct UserInParseTopologyResult
{
bool addSingleOutToMap;
bool addNewOutToLeavesWithout;
bool addReturnValuesToOuts;
bool addExplicitOutCalls;
bool isSimpleFunction;
};
void AccountForEBusConnectionControl(ExecutionTreePtr execution);
@@ -465,7 +485,7 @@ namespace ScriptCanvas
void AddExecutionMapLatentOut(const Nodes::Core::FunctionDefinitionNode& nodeling, ExecutionTreePtr out);
void AddUserOut(ExecutionTreePtr parent, ExecutionTreeConstPtr root, AZStd::string_view name);
void AddUserOutToLeaf(ExecutionTreePtr parent, ExecutionTreeConstPtr root, AZStd::string_view name);
void AddPreviouslyExecutedScopeVariableToOutputAssignments(VariableConstPtr newInputVariable, const ConnectionsInPreviouslyExecutedScope& connectedInputInPreviouslyExecutedScope);
@@ -485,11 +505,30 @@ namespace ScriptCanvas
bool InSimultaneousDataPath(const Node& node, const Slot& reference, const Slot& candidate) const;
void MarkAllFunctionsPure();
static UserInParseTopologyResult ParseUserInTolopology(size_t nodelingsOutCount, size_t leavesWithoutNodelingsCount);
ExecutionTreePtr m_start;
AZStd::vector<const Nodes::Core::Start*> m_startNodes;
ScopePtr m_graphScope;
const Source m_source;
OrderedDependencies m_orderedDependencies;
AZStd::unordered_set<VariableConstPtr> m_userNodeables;
AZStd::unordered_map<VariableConstPtr, DependencyInfo> m_dependencyByVariable;
private:
AZStd::vector<VariableConstPtr> m_variables;
AZStd::vector<const Node*> m_possibleExecutionRoots;
// true iff there are no internal errors and no error validation events
bool m_isErrorFree = true;
// for post parsing validation
ValidationResults::ValidationEventList m_validationEvents;
DebugSymbolMap m_debugMap;
DebugSymbolMapReverse m_debugMapReverse;
AZStd::sys_time_t m_parseDuration;
AZStd::chrono::system_clock::time_point m_parseStartTime;
EBusHandlingByNode m_ebusHandlingByNode;
@@ -510,6 +549,16 @@ namespace ScriptCanvas
AZStd::unordered_set<const Nodes::Core::FunctionDefinitionNode*> m_outsMarkedImmediate;
AZStd::unordered_set<const Nodes::Core::FunctionDefinitionNode*> m_processedOuts;
// the output slots of the In-Nodeling
AZStd::unordered_map<const Slot*, VariablePtr> m_inputVariableByNodelingInSlot;
// the output slots of the Out-Nodeling
AZStd::unordered_map<const Slot*, VariablePtr> m_returnVariableByNodelingOutSlot;
// the input slots of the Out-Nodeling
AZStd::unordered_map<const Slot*, VariablePtr> m_outputVariableByNodelingOutSlot;
AZStd::unordered_map<const Nodes::Core::FunctionDefinitionNode*, ReturnValueDescription> m_returnValuesByUserFunctionDefinition;
AZStd::unordered_map<const Datum*, const GraphVariable*> m_sourceVariableByDatum;
AZStd::unordered_set<const Node*> m_subgraphStartCalls;
AZStd::unordered_set<const Node*> m_activeDefaultObject;
@@ -517,14 +566,21 @@ namespace ScriptCanvas
AZStd::unordered_set<AZStd::string> m_uniqueOutNames;
AZStd::unordered_set<AZStd::string> m_uniqueInNames;
AZStd::vector<AZStd::pair<Grammar::VariableConstPtr, AZStd::string>> m_staticVariableNames;
AZStd::unordered_map<Grammar::ExecutionTreeConstPtr, AZStd::vector<AZStd::pair<Grammar::VariableConstPtr, AZStd::string>>> m_staticVariableNamesByFunctionBlock;
AZStd::vector<VariablePtr> FindAllVariablesInVariableFlagScope(VariableFlags::Scope scope) const;
AZStd::unordered_map<ExecutionTreeConstPtr, VariableUseage> m_variableUseByExecution;
VariableUseage m_variableUse;
// scrape variables for scope, every Scope::In and InOut
AZStd::vector<VariablePtr> FindSubGraphInputValues() const;
ParsedRuntimeInputs m_runtimeInputs;
// scrape variables for scope, every Scope::Out and InOut
AZStd::vector<VariablePtr> FindSubGraphOutputValues() const;
AZStd::vector<VariablePtr> FindUserImmediateInput(ExecutionTreePtr call) const;
const ReturnValueDescription* FindUserImmediateOutput(ExecutionTreePtr call) const;
AZStd::vector<VariablePtr> FindUserLatentOutput(ExecutionTreePtr call) const;
AZStd::vector<VariablePtr> FindUserLatentReturnValues(ExecutionTreePtr call) const;
bool IsSourceInScope(VariableConstPtr variable, VariableFlags::Scope scope) const;
@@ -539,8 +595,25 @@ namespace ScriptCanvas
void ParseExecutionIfStatementBooleanExpression(ExecutionTreePtr booleanExpressionExecution, AZStd::string executionName, LexicalScope lexicalScope);
void ParseExecutionIfStatementInternalFunction(ExecutionTreePtr internalFunctionExecution);
};
#if defined(FUNCTION_LEGACY_SUPPORT_ENABLED)
public:
AZStd::vector<VariablePtr> FindAllVariablesInVariableFlagScope(VariableFlags::Scope scope) const;
// scrape variables for scope, every Scope::In and InOut
AZStd::vector<VariablePtr> FindSubGraphInputValues() const;
// scrape variables for scope, every Scope::Out and InOut
AZStd::vector<VariablePtr> FindSubGraphOutputValues() const;
AZStd::vector<VariableConstPtr> GetLocalVariablesUser() const;
VariableScopeMeaning_LegacyFunctions GetVariableScopeMeaning() const;
private:
VariableScopeMeaning_LegacyFunctions m_variableScopeMeaning = VariableScopeMeaning_LegacyFunctions::ValueInitialization;
#endif
}; // class AbstractCodeModel
template<typename T>
AZStd::vector<Grammar::VariableConstPtr> AbstractCodeModel::ToVariableList(const AZStd::vector<AZStd::pair<VariableId, T>>& source) const
@@ -0,0 +1,136 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <ScriptCanvas/Core/Datum.h>
#include <ScriptCanvas/Core/EBusHandler.h>
#include <ScriptCanvas/Core/Graph.h>
#include <ScriptCanvas/Core/Nodeable.h>
#include <ScriptCanvas/Core/NodeableNode.h>
#include <ScriptCanvas/Core/NodeableNodeOverloaded.h>
#include <ScriptCanvas/Core/SubgraphInterfaceUtility.h>
#include <ScriptCanvas/Debugger/ValidationEvents/DataValidation/ScopedDataConnectionEvent.h>
#include <ScriptCanvas/Debugger/ValidationEvents/ParsingValidation/ParsingValidations.h>
#include <ScriptCanvas/Grammar/ParsingMetaData.h>
#include <ScriptCanvas/Libraries/Core/AzEventHandler.h>
#include <ScriptCanvas/Libraries/Core/EBusEventHandler.h>
#include <ScriptCanvas/Libraries/Core/FunctionDefinitionNode.h>
#include <ScriptCanvas/Libraries/Core/ExtractProperty.h>
#include <ScriptCanvas/Libraries/Core/ForEach.h>
#include <ScriptCanvas/Libraries/Core/FunctionCallNode.h>
#include <ScriptCanvas/Libraries/Core/Method.h>
#include <ScriptCanvas/Libraries/Core/Start.h>
#include <ScriptCanvas/Translation/TranslationUtilities.h>
#include <ScriptCanvas/Variable/VariableData.h>
#include "ExecutionTraversalListeners.h"
#include "GrammarContextBus.h"
#include "ParsingUtilities.h"
#include "Primitives.h"
namespace ScriptCanvas
{
namespace Grammar
{
void NodelingInParserIterationListener::CountOnlyGrammarCalls()
{
m_countOnlyGrammarCalls = true;
}
void NodelingInParserIterationListener::EvaluateLeaf(ExecutionTreeConstPtr node, const Slot*, int)
{
bool without = true;
bool addedToOutCall = false;
if (node->GetSymbol() == Symbol::UserOut)
{
m_outCalls.push_back(node);
without = false;
addedToOutCall = true;
}
if (auto nodeling = azrtti_cast<const ScriptCanvas::Nodes::Core::FunctionDefinitionNode*>(node->GetId().m_node))
{
if (!m_countOnlyGrammarCalls && !addedToOutCall)
{
m_outCalls.push_back(node);
}
m_uniqueNodelings.insert(nodeling);
without = false;
}
if (without)
{
m_leavesWithoutNodelings.push_back(node);
}
}
const AZStd::vector<ExecutionTreeConstPtr>& NodelingInParserIterationListener::GetLeavesWithoutNodelings() const
{
return m_leavesWithoutNodelings;
}
const AZStd::unordered_set<const ScriptCanvas::Nodes::Core::FunctionDefinitionNode*>& NodelingInParserIterationListener::GetNodelingsOut() const
{
return m_uniqueNodelings;
}
const AZStd::vector<ExecutionTreeConstPtr>& NodelingInParserIterationListener::GetOutCalls() const
{
return m_outCalls;
}
void NodelingInParserIterationListener::Reset()
{
m_uniqueNodelings.clear();
m_outCalls.clear();
m_leavesWithoutNodelings.clear();
}
void PureFunctionListener::Evaluate(ExecutionTreeConstPtr node, [[maybe_unused]] const Slot* slot, [[maybe_unused]] int level)
{
ParseVariableUse(node, m_usedVariables);
m_isPure = m_isPure
&& Grammar::IsPure(node->GetSymbol())
&& Grammar::IsPure(node->GetId().m_node, node->GetId().m_slot);
}
const VariableUseage& PureFunctionListener::GetUsedVariables() const
{
return m_usedVariables;
}
bool PureFunctionListener::IsPure() const
{
return m_isPure && m_usedVariables.memberVariables.empty();
}
VariableUseage&& PureFunctionListener::MoveUsedVariables()
{
return AZStd::move(m_usedVariables);
}
void UserOutCallCollector::Evaluate(const EndpointResolved& endpoint)
{
if (auto nodeling = IsUserOutNode(endpoint.first))
{
m_outCalls.insert(nodeling);
}
}
const AZStd::unordered_set<const ScriptCanvas::Nodes::Core::FunctionDefinitionNode*>& UserOutCallCollector::GetOutCalls() const
{
return m_outCalls;
}
}
}
@@ -0,0 +1,85 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include "PrimitivesDeclarations.h"
#include "PrimitivesExecution.h"
namespace ScriptCanvas
{
namespace Nodes
{
namespace Core
{
class FunctionDefinitionNode;
}
}
namespace Grammar
{
class NodelingInParserIterationListener
: public ExecutionTreeTraversalListener
{
public:
void CountOnlyGrammarCalls();
const AZStd::vector<ExecutionTreeConstPtr>& GetLeavesWithoutNodelings() const;
const AZStd::unordered_set<const ScriptCanvas::Nodes::Core::FunctionDefinitionNode*>& GetNodelingsOut() const;
const AZStd::vector<ExecutionTreeConstPtr>& GetOutCalls() const;
void Reset() override;
protected:
void EvaluateLeaf(ExecutionTreeConstPtr node, const Slot*, int) override;
private:
bool m_countOnlyGrammarCalls = false;
AZStd::unordered_set<const ScriptCanvas::Nodes::Core::FunctionDefinitionNode*> m_uniqueNodelings;
AZStd::vector<ExecutionTreeConstPtr> m_outCalls;
AZStd::vector<ExecutionTreeConstPtr> m_leavesWithoutNodelings;
};
class PureFunctionListener
: public ExecutionTreeTraversalListener
{
public:
const VariableUseage& GetUsedVariables() const;
bool IsPure() const;
VariableUseage&& MoveUsedVariables();
protected:
void Evaluate(ExecutionTreeConstPtr node, const Slot* slot, [[maybe_unused]] int) override;
private:
bool m_isPure = true;
VariableUseage m_usedVariables;
};
class UserOutCallCollector
: public GraphExecutionPathTraversalListener
{
public:
const AZStd::unordered_set<const ScriptCanvas::Nodes::Core::FunctionDefinitionNode*>& GetOutCalls() const;
protected:
void Evaluate(const EndpointResolved& endpoint) override;
private:
AZStd::unordered_set<const ScriptCanvas::Nodes::Core::FunctionDefinitionNode*> m_outCalls;
};
}
}
@@ -0,0 +1,288 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "PrimitivesDeclarations.h"
#if defined(FUNCTION_LEGACY_SUPPORT_ENABLED)
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <ScriptCanvas/Asset/RuntimeAsset.h>
#include <ScriptCanvas/Core/Datum.h>
#include <ScriptCanvas/Core/EBusHandler.h>
#include <ScriptCanvas/Core/Graph.h>
#include <ScriptCanvas/Core/GraphData.h>
#include <ScriptCanvas/Core/ModifiableDatumView.h>
#include <ScriptCanvas/Core/Nodeable.h>
#include <ScriptCanvas/Core/NodeableNode.h>
#include <ScriptCanvas/Core/NodeableNodeOverloaded.h>
#include <ScriptCanvas/Core/ScriptCanvasBus.h>
#include <ScriptCanvas/Core/SlotNames.h>
#include <ScriptCanvas/Core/SubgraphInterfaceUtility.h>
#include <ScriptCanvas/Debugger/ValidationEvents/DataValidation/ScopedDataConnectionEvent.h>
#include <ScriptCanvas/Debugger/ValidationEvents/ParsingValidation/ParsingValidations.h>
#include <ScriptCanvas/Execution/RuntimeComponent.h>
#include <ScriptCanvas/Grammar/ParsingMetaData.h>
#include <ScriptCanvas/Libraries/Core/AzEventHandler.h>
#include <ScriptCanvas/Libraries/Core/EBusEventHandler.h>
#include <ScriptCanvas/Libraries/Core/FunctionDefinitionNode.h>
#include <ScriptCanvas/Libraries/Core/ExtractProperty.h>
#include <ScriptCanvas/Libraries/Core/ForEach.h>
#include <ScriptCanvas/Libraries/Core/FunctionCallNode.h>
#include <ScriptCanvas/Libraries/Core/Method.h>
#include <ScriptCanvas/Libraries/Core/MethodUtility.h>
#include <ScriptCanvas/Libraries/Core/Start.h>
#include <ScriptCanvas/Translation/TranslationUtilities.h>
#include <ScriptCanvas/Utils/VersionConverters.h>
#include <ScriptCanvas/Variable/GraphVariableManagerComponent.h>
#include <ScriptCanvas/Variable/VariableBus.h>
#include <ScriptCanvas/Variable/VariableData.h>
#include <ScriptEvents/ScriptEventsAsset.h>
#include <ScriptEvents/ScriptEventsBus.h>
#include "AbstractCodeModel.h"
#include "FunctionsLegacySupport.h"
#include "GrammarContextBus.h"
#include "ParsingUtilities.h"
#include "Primitives.h"
namespace ScriptCanvas
{
namespace Grammar
{
void AbstractCodeModel::AddAllVariablesPreParse_LegacyFunctions()
{
// all variables assumed to be NOT persistent - in the live code they are reset when activated
// variables with no scope In/Out is assumed to be persistent, this is a mess with tick handlers
// warn on any variable attempted to be read before written
AZ_Assert(m_variableScopeMeaning == VariableScopeMeaning_LegacyFunctions::FunctionPrototype, "new graph type added without full support");
auto& sourceVariables = m_source.m_variableData->GetVariables();
AZStd::set<const GraphVariable*, GraphVariable::Comparator> sortedVariables;
for (const auto& variablePair : sourceVariables)
{
sortedVariables.insert(&variablePair.second);
}
for (auto& sourceVariable : sortedVariables)
{
auto datum = sourceVariable->GetDatum();
AZ_Assert(datum != nullptr, "the datum must be valid");
AddVariable(*datum, sourceVariable->GetVariableName(), sourceVariable->GetVariableId());
}
}
AZStd::vector<VariablePtr> AbstractCodeModel::FindSubGraphInputValues() const
{
return FindAllVariablesInVariableFlagScope(VariableFlags::Scope::Input);
}
AZStd::vector<VariablePtr> AbstractCodeModel::FindSubGraphOutputValues() const
{
return FindAllVariablesInVariableFlagScope(VariableFlags::Scope::Output);
}
AZStd::vector<VariablePtr> AbstractCodeModel::FindAllVariablesInVariableFlagScope(VariableFlags::Scope scope) const
{
AZStd::vector<VariablePtr> variables;
auto& sourceVariables = m_source.m_variableData->GetVariables();
for (auto& variable : m_variables)
{
if (IsSourceInScope(variable, scope))
{
variables.push_back(variable);
}
}
// sort by variable id
AZStd::sort(variables.begin(), variables.end(), [](const auto& lhs, const auto& rhs) { return lhs->m_sourceVariableId < rhs->m_sourceVariableId; });
return variables;
}
AZStd::vector<VariableConstPtr> AbstractCodeModel::GetLocalVariablesUser() const
{
AZStd::vector<VariableConstPtr> userLocalVariables;
if (m_variableScopeMeaning == VariableScopeMeaning_LegacyFunctions::FunctionPrototype)
{
for (auto variable : m_variables)
{
if (!variable->m_isMember
&& variable->m_sourceVariableId.IsValid()
&& !IsSourceInScope(variable, VariableFlags::Scope::Input)
&& !IsSourceInScope(variable, VariableFlags::Scope::Output))
{
userLocalVariables.push_back(variable);
}
}
}
return userLocalVariables;
}
VariableScopeMeaning_LegacyFunctions AbstractCodeModel::GetVariableScopeMeaning() const
{
return m_variableScopeMeaning;
}
bool SubgraphInterface::IsAllInputOutputShared() const
{
return m_isAllInputOutputShared;
}
void SubgraphInterface::MarkAllInputOutputShared()
{
m_isAllInputOutputShared = true;
}
} // namespace Grammar
namespace Nodes
{
namespace Core
{
void FunctionCallNode::BuildNodeFromSubgraphInterface
(const AZ::Data::Asset<ScriptCanvas::SubgraphInterfaceAsset>& runtimeAsset
, const SlotExecution::Map& previousMap)
{
// build the node here, from the asset topology, take the node/variable ordering from the function runtime data as a suggestion
// deal with updates and conversions after
const Grammar::SubgraphInterface& subgraphInterface = runtimeAsset.Get()->m_runtimeData.m_interface;
m_prettyName = runtimeAsset.Get()->m_runtimeData.m_name;
if (!subgraphInterface.IsAllInputOutputShared())
{
AZ_Error("ScriptCanvas", false, "the current assumption is that there is no way to distinguish between the input/output of different nodelings");
return;
}
// for now, all outputs are shared
Grammar::Outputs outputs;
bool sharedOutputInitialized = false;
SlotExecution::Ins slotMapIns;
SlotExecution::Outs slotMapLatents;
int slotOffset = 0;
// add all ins->outs, in their display groups
for (size_t indexIn = 0; indexIn < subgraphInterface.GetInCount(); ++indexIn)
{
const Grammar::In& interfaceIn = subgraphInterface.GetIn(indexIn);
SlotExecution::In slotMapIn = AddExecutionInSlotFromInterface(interfaceIn, slotOffset++, previousMap.FindInSlotIdBySource(interfaceIn.sourceID));
if (!slotMapIn.slotId.IsValid())
{
AZ_Error("ScriptCanvas", false, "Failed to add Execution In slot from sub graph interface");
return;
}
slotMapIn.inputs = AddDataInputSlotFromInterface(interfaceIn.inputs, interfaceIn.sourceID, interfaceIn.displayName, previousMap, slotOffset);
for (auto& input : slotMapIn.inputs)
{
if (!input.slotId.IsValid())
{
AZ_Error("ScriptCanvas", false, "Failed to add Input slot from sub graph interface");
return;
}
}
for (auto& interfaceOut : interfaceIn.outs)
{
SlotExecution::Out slotMapOut = AddExecutionOutSlotFromInterface(interfaceIn, interfaceOut, slotOffset++, previousMap.FindOutSlotIdBySource(interfaceIn.sourceID, interfaceOut.sourceID));
if (!slotMapOut.slotId.IsValid())
{
AZ_Error("ScriptCanvas", false, "Failed to add Execution Out slot from sub graph interface");
return;
}
if (!sharedOutputInitialized)
{
outputs = interfaceOut.outputs;
sharedOutputInitialized = true;
}
slotMapIn.outs.push_back(slotMapOut);
}
slotMapIns.push_back(slotMapIn);
}
// add all latents in their display groups
for (size_t indexLatent = 0; indexLatent < subgraphInterface.GetLatentOutCount(); ++indexLatent)
{
const Grammar::Out& interfaceLatent = subgraphInterface.GetLatentOut(indexLatent);
SlotExecution::Out slotMapLatentOut = AddExecutionLatentOutSlotFromInterface(interfaceLatent, slotOffset++, previousMap.FindLatentSlotIdBySource(interfaceLatent.sourceID));
if (!slotMapLatentOut.slotId.IsValid())
{
AZ_Error("ScriptCanvas", false, "Failed to add Latent Out slot from sub graph interface");
return;
}
slotMapLatentOut.returnValues.values = AddDataInputSlotFromInterface(interfaceLatent.returnValues, interfaceLatent.sourceID, interfaceLatent.displayName, previousMap, slotOffset);
for (auto& input : slotMapLatentOut.returnValues.values)
{
if (!input.slotId.IsValid())
{
AZ_Error("ScriptCanvas", false, "Failed to add Input slot from sub graph interface");
return;
}
}
if (!sharedOutputInitialized)
{
outputs = interfaceLatent.outputs;
sharedOutputInitialized = true;
}
slotMapLatents.push_back(slotMapLatentOut);
}
// add all outputs one time, since they are currently all required to be part of all the signatures [\todo must fix] , in a variable display group
SlotExecution::Outputs slotMapOutputs = AddDataOutputSlotFromInterface(outputs, "", previousMap, slotOffset);
for (auto& output : slotMapOutputs)
{
if (!output.slotId.IsValid())
{
AZ_Error("ScriptCanvas", false, "Failed to add Output slot from sub graph interface");
return;
}
}
if (!subgraphInterface.IsLatent())
{
for (auto& slotMapIn : slotMapIns)
{
for (auto& slotMapOut : slotMapIn.outs)
{
slotMapOut.outputs = slotMapOutputs;
}
}
}
else
{
for (auto& slotMapLatent : slotMapLatents)
{
slotMapLatent.outputs = slotMapOutputs;
}
}
// when returning variables: sort variables by source slot id, they are sorted in the slot map, so just take them from the slot map
m_slotExecutionMap = AZStd::move(SlotExecution::Map(AZStd::move(slotMapIns), AZStd::move(slotMapLatents)));
m_slotExecutionMapSourceInterface = subgraphInterface;
m_asset = runtimeAsset;
SignalSlotsReordered();
}
} // namespace Core
} // namespace Nodes
}
#endif
@@ -0,0 +1,25 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
namespace ScriptCanvas
{
namespace Grammar
{
enum class VariableScopeMeaning_LegacyFunctions : AZ::u32
{
ValueInitialization,
FunctionPrototype,
};
}
}
@@ -22,7 +22,7 @@
#include <ScriptCanvas/Libraries/Core/FunctionDefinitionNode.h>
#include <ScriptCanvas/Libraries/Core/ExtractProperty.h>
#include <ScriptCanvas/Libraries/Core/ForEach.h>
#include <ScriptCanvas/Libraries/Core/FunctionNode.h>
#include <ScriptCanvas/Libraries/Core/FunctionCallNode.h>
#include <ScriptCanvas/Libraries/Core/GetVariable.h>
#include <ScriptCanvas/Libraries/Core/Method.h>
#include <ScriptCanvas/Libraries/Core/ReceiveScriptEvent.h>
@@ -53,7 +53,7 @@ namespace ParsingUtilitiesCpp
using namespace ScriptCanvas::Grammar;
class PrettyPrinter
: public ExecutionTreeIterationListener
: public ExecutionTreeTraversalListener
{
public:
PrettyPrinter() = default;
@@ -137,6 +137,33 @@ namespace ScriptCanvas
, lexicalScope(scopeType)
{}
void VariableUseage::Clear()
{
localVariables.clear();
memberVariables.clear();
}
void VariableUseage::Parse(VariableConstPtr variable)
{
usesExternallyInitializedVariables = usesExternallyInitializedVariables || IsExternallyInitialized(variable);
if (IsManuallyDeclaredUserVariable(variable))
{
if (variable->m_isMember)
{
memberVariables.insert(variable);
}
else
{
localVariables.insert(variable);
}
}
else if (variable->m_isMember)
{
implicitMemberVariables.insert(variable);
}
}
bool ActivatesSelf(const ExecutionTreeConstPtr& execution)
{
auto methodNode = azrtti_cast<const ScriptCanvas::Nodes::Core::Method*>(execution->GetId().m_node);
@@ -271,6 +298,23 @@ namespace ScriptCanvas
return execution->GetSymbol();
}
NodelingType CheckNodelingType(const Node& node)
{
if (auto nodeling = azrtti_cast<const ScriptCanvas::Nodes::Core::FunctionDefinitionNode*>(&node))
{
if (nodeling->IsExecutionEntry())
{
return NodelingType::In;
}
else if (nodeling->IsExecutionExit())
{
return NodelingType::Out;
}
}
return NodelingType::None;
}
CheckOperatorResult CheckOperatorArithmeticSymbol(const ExecutionTreeConstPtr& execution)
{
if (azrtti_istypeof<const ScriptCanvas::Nodes::Operators::OperatorArithmetic*>(execution->GetId().m_node))
@@ -345,6 +389,12 @@ namespace ScriptCanvas
}
}
bool ExecutionContainsCycles(const Node& node, const Slot& outSlot)
{
GraphExecutionPathTraversalListener listener;
return TraverseExecutionConnections(node, outSlot, listener) != ExecutionTraversalResult::Success;
}
bool ExecutionWritesVariable(ExecutionTreeConstPtr execution, VariableConstPtr variable)
{
for (size_t i = 0, sentinel = execution->GetChildrenCount(); i < sentinel; ++i)
@@ -435,6 +485,14 @@ namespace ScriptCanvas
return azrtti_istypeof<const ScriptCanvas::Nodes::Logic::Break*>(execution->GetId().m_node);
}
bool IsCodeConstructable(Grammar::VariableConstPtr value)
{
return Data::IsValueType(value->m_datum.GetType())
// || value->m_datum.GetType().GetAZType() == azrtti_typeid<Nodeable>() // <--- cut this.. can't be needed or correct
|| value->m_datum.GetAsDanger() == nullptr;
;
}
bool IsCycle(const Node& node)
{
return azrtti_istypeof<const ScriptCanvas::Nodes::Logic::Cycle>(node);
@@ -504,6 +562,13 @@ namespace ScriptCanvas
return execution->GetExecutedPropertyExtraction() != nullptr;
}
bool IsExternallyInitialized(VariableConstPtr value)
{
const auto requirement = ParseConstructionRequirement(value);
return !(requirement == VariableConstructionRequirement::None || requirement == VariableConstructionRequirement::Static);
}
bool IsFloatingPointNumberEqualityComparison(ExecutionTreeConstPtr execution)
{
const auto symbol = execution->GetSymbol();
@@ -524,7 +589,7 @@ namespace ScriptCanvas
|| IsRandomSwitchStatement(execution)
|| IsSequenceNode(execution)
|| IsSwitchStatement(execution)
|| IsUserOut(execution)
|| IsUserOutNode(execution)
|| IsWhileLoop(execution);
}
@@ -678,6 +743,15 @@ namespace ScriptCanvas
|| symbol == Symbol::While;
}
bool IsManuallyDeclaredUserVariable(VariableConstPtr variable)
{
return variable
&& variable->m_source == nullptr
&& !variable->m_sourceSlotId.IsValid()
&& variable->m_sourceVariableId.IsValid()
&& !variable->m_nodeableNodeId.IsValid();
}
bool IsMidSequence(const ExecutionTreeConstPtr& execution)
{
if (!execution)
@@ -866,6 +940,28 @@ namespace ScriptCanvas
return azrtti_istypeof<const ScriptCanvas::Nodes::Core::ExtractProperty*>(execution->GetId().m_node);
}
bool IsPure(Symbol symbol)
{
return symbol != Symbol::Cycle;
}
bool IsPure(const Node* node, const Slot* slot)
{
if (auto userFunctionCall = azrtti_cast<const ScriptCanvas::Nodes::Core::FunctionCallNode*>(node))
{
if (!userFunctionCall->IsSlotPure(slot))
{
return false;
}
}
else if (node && IsOnce(*node))
{
return false;
}
return true;
}
bool IsRandomSwitchStatement(const ExecutionTreeConstPtr& execution)
{
return azrtti_istypeof<const ScriptCanvas::Nodes::Logic::WeightedRandomSequencer>(execution->GetId().m_node)
@@ -892,28 +988,25 @@ namespace ScriptCanvas
bool IsUserFunctionCall(const ExecutionTreeConstPtr& execution)
{
return (execution->GetSymbol() == Symbol::FunctionCall)
&& azrtti_istypeof<const ScriptCanvas::Nodes::Core::FunctionNode*>(execution->GetId().m_node);
}
bool IsUserFunctionCallPure(const ExecutionTreeConstPtr& execution)
{
const auto& id = execution->GetId();
return execution->GetSymbol() == Symbol::FunctionCall
&& azrtti_istypeof<const ScriptCanvas::Nodes::Core::FunctionNode*>(id.m_node)
&& azrtti_cast<const ScriptCanvas::Nodes::Core::FunctionNode*>(id.m_node)->IsSlotPure(execution->GetId().m_slot);
&& azrtti_istypeof<const ScriptCanvas::Nodes::Core::FunctionCallNode*>(execution->GetId().m_node);
}
bool IsUserFunctionDefinition(const ExecutionTreeConstPtr& execution)
{
return (execution->GetSymbol() == Symbol::FunctionDefinition)
&& azrtti_istypeof<const ScriptCanvas::Nodes::Core::FunctionNode*>(execution->GetId().m_node);
auto nodeling = azrtti_cast<const ScriptCanvas::Nodes::Core::FunctionDefinitionNode*>(execution->GetId().m_node);
return nodeling && nodeling->IsExecutionEntry() && execution->GetSymbol() == Symbol::FunctionDefinition;
}
bool IsUserOut(const ExecutionTreeConstPtr& execution)
const ScriptCanvas::Nodes::Core::FunctionDefinitionNode* IsUserOutNode(const Node* node)
{
auto nodeling = azrtti_cast<const ScriptCanvas::Nodes::Core::FunctionDefinitionNode*>(execution->GetId().m_node);
// \todo change this evaluation, it is too brittle
return nodeling && !nodeling->IsEntryPoint();
auto nodeling = azrtti_cast<const ScriptCanvas::Nodes::Core::FunctionDefinitionNode*>(node);
return nodeling && nodeling->IsExecutionExit() ? nodeling : nullptr;
}
const ScriptCanvas::Nodes::Core::FunctionDefinitionNode* IsUserOutNode(const ExecutionTreeConstPtr& execution)
{
auto nodeling = IsUserOutNode(execution->GetId().m_node);
return nodeling ? nodeling : nullptr;
}
bool IsVariableGet(const ExecutionTreeConstPtr& execution)
@@ -944,6 +1037,86 @@ namespace ScriptCanvas
return AZStd::string::format("%s%s", k_memberNamePrefix, name.data());
}
VariableConstructionRequirement ParseConstructionRequirement(VariableConstPtr variable)
{
if (IsEntityIdThatRequiresRuntimeRemap(variable))
{
return VariableConstructionRequirement::InputEntityId;
}
else if (variable->m_isExposedToConstruction)
{
if (variable->m_sourceVariableId.IsValid())
{
return VariableConstructionRequirement::InputVariable;
}
else if (variable->m_nodeableNodeId.IsValid())
{
return VariableConstructionRequirement::InputNodeable;
}
else
{
AZ_Assert(false, "A member variable in the model has no valid id");
}
}
else if (variable->m_sourceVariableId.IsValid() && !IsCodeConstructable(variable))
{
return VariableConstructionRequirement::Static;
}
return VariableConstructionRequirement::None;
}
void ParseVariableUse(const OutputAssignment& outputAssignment, VariableUseage& variableUse)
{
variableUse.Parse(outputAssignment.m_source);
for (const auto& assignment : outputAssignment.m_assignments)
{
variableUse.Parse(assignment);
}
}
void ParseVariableUse(ExecutionTreeConstPtr execution, VariableUseage& variableUse)
{
for (size_t inputIdx = 0; inputIdx != execution->GetInputCount(); ++inputIdx)
{
variableUse.Parse(execution->GetInput(inputIdx).m_value);
}
for (size_t returnIdx = 0; returnIdx != execution->GetReturnValueCount(); ++returnIdx)
{
if (auto returnValue = execution->GetReturnValue(returnIdx).second)
{
ParseVariableUse(*returnValue, variableUse);
}
}
if (auto localOutputPtr = execution->GetLocalOutput())
{
for (const auto& localOuput : *localOutputPtr)
{
if (localOuput.second)
{
return ParseVariableUse(*localOuput.second, variableUse);
}
}
}
else
{
for (size_t childIdx = 0; childIdx != execution->GetChildrenCount(); ++childIdx)
{
const auto& child = execution->GetChild(childIdx);
for (const auto& localOuput : child.m_output)
{
if (localOuput.second)
{
ParseVariableUse(*localOuput.second, variableUse);
}
}
}
}
}
void PrettyPrint(AZStd::string& result, const AbstractCodeModel& model)
{
if (model.IsPerEntityDataRequired())
@@ -979,65 +1152,12 @@ namespace ScriptCanvas
result = printer.TakeResult();
}
void TraverseTreeRecurse(const ExecutionTreeConstPtr& execution, ExecutionTreeIterationListener& listener, const Slot* slot, int depth = 0);
void TraverseTree(const AbstractCodeModel& model, ExecutionTreeIterationListener& listener)
{
for (auto root : model.GetAllExecutionRoots())
{
TraverseTree(root, listener);
}
}
void TraverseTree(const ExecutionTreeConstPtr& execution, ExecutionTreeIterationListener& listener)
{
listener.Reset();
TraverseTreeRecurse(execution, listener, nullptr, 0);
}
void TraverseTreeRecurse(const ExecutionTreeConstPtr& execution, ExecutionTreeIterationListener& listener, const Slot* slot, int level)
{
if (!execution->GetParent())
{
listener.EvaluateRoot(execution, slot);
}
listener.Evaluate(execution, slot, level);
if (execution->GetChildrenCount() == 0 && !IsInLoop(execution) && !IsMidSequence(execution))
{
listener.EvaluateLeaf(execution, slot, level);
}
else
{
for (size_t i(0); i < execution->GetChildrenCount(); ++i)
{
auto& childIter = execution->GetChild(i);
if (childIter.m_execution)
{
listener.EvaluateChildPre(execution, childIter.m_slot, i, level + 1);
TraverseTreeRecurse(childIter.m_execution, listener, childIter.m_slot, level + 1);
listener.EvaluateChildPost(execution, childIter.m_slot, i, level + 1);
}
else if (!IsInLoop(execution) && !IsMidSequence(execution))
{
listener.EvaluateNullChildLeaf(execution, childIter.m_slot, i, level + 1);
}
}
}
}
void ProtectReservedWords(AZStd::string& name)
{
if (!name.ends_with(k_reservedWordProtection))
{
name.append(k_reservedWordProtection);
}
else
{
AZ_TracePrintf("ScriptCanvas", "%s name was already safe", name.data());
}
}
OutputAssignmentPtr RemoveOutput(ExecutionChild& executionChild, const SlotId& slotId)
@@ -1087,6 +1207,161 @@ namespace ScriptCanvas
return identifier;
}
}
ExecutionTraversalResult TraverseExecutionConnectionsRecurse(const EndpointsResolved& nextEndpoints, AZStd::unordered_set<const Slot*>& previousIns, GraphExecutionPathTraversalListener& listener);
ExecutionTraversalResult TraverseExecutionConnectionsRecurse(const EndpointResolved& in, AZStd::unordered_set<const Slot*>& previousIns, GraphExecutionPathTraversalListener& listener);
ExecutionTraversalResult TraverseExecutionConnections(const Node& node, const Slot& outSlot, GraphExecutionPathTraversalListener& listener)
{
AZStd::unordered_set<const Slot*> path;
return TraverseExecutionConnectionsRecurse({ &node, &outSlot }, path, listener);
}
ExecutionTraversalResult TraverseExecutionConnectionsRecurse(const EndpointsResolved& nextEndpoints, AZStd::unordered_set<const Slot*>& previousPath, GraphExecutionPathTraversalListener& listener)
{
if (listener.CancelledTraversal())
{
return ExecutionTraversalResult::Success;
}
if (!nextEndpoints.empty())
{
if (nextEndpoints.size() == 1)
{
auto status = TraverseExecutionConnectionsRecurse(nextEndpoints[0], previousPath, listener);
if (status != ExecutionTraversalResult::Success)
{
return status;
}
}
else
{
// Subsequent connections after an the multiple Execution Out connections syntax sugar
// only have to check for loops up to the sequence point.
// Duplicate endpoints after the sequence are not necessarily loops, but are likely just the normal
// ScriptCanvas way allowing users to use the same visual path (thus preventing "duplicate code").
for (auto nextEndpoint : nextEndpoints)
{
AZStd::unordered_set<const Slot*> pathUpToSequenceSyntaxSugar(previousPath);
auto status = TraverseExecutionConnectionsRecurse(nextEndpoint, pathUpToSequenceSyntaxSugar, listener);
if (status != ExecutionTraversalResult::Success)
{
return status;
}
}
}
}
return ExecutionTraversalResult::Success;
}
ExecutionTraversalResult TraverseExecutionConnectionsRecurse(const EndpointResolved& in, AZStd::unordered_set<const Slot*>& previousPath, GraphExecutionPathTraversalListener& listener)
{
if (previousPath.contains(in.second))
{
return ExecutionTraversalResult::ContainsCycle;
}
if (!in.second)
{
return ExecutionTraversalResult::NullSlot;
}
listener.Evaluate(in);
if (listener.CancelledTraversal())
{
return ExecutionTraversalResult::Success;
}
AZStd::vector<const Slot*> outSlots;
if (in.second->IsLatent())
{
outSlots.push_back(in.second);
}
else
{
previousPath.insert(in.second);
auto outSlotsOutcome = in.first->GetSlotsInExecutionThreadByType(*in.second, CombinedSlotType::ExecutionOut);
if (!outSlotsOutcome.IsSuccess())
{
return ExecutionTraversalResult::GetSlotError;
}
outSlots = outSlotsOutcome.GetValue();
}
for (auto branch : outSlots)
{
auto nextEndpoints = in.first->GetConnectedNodes(*branch);
AZStd::unordered_set<const Slot*> pathUpToBranchOrSyntaxSugar(previousPath);
const auto status = TraverseExecutionConnectionsRecurse(nextEndpoints, pathUpToBranchOrSyntaxSugar, listener);
if (status != ExecutionTraversalResult::Success)
{
return status;
}
}
return ExecutionTraversalResult::Success;
}
void TraverseTreeRecurse(const ExecutionTreeConstPtr& execution, ExecutionTreeTraversalListener& listener, const Slot* slot, int depth = 0);
void TraverseTree(const AbstractCodeModel& model, ExecutionTreeTraversalListener& listener)
{
for (auto root : model.GetAllExecutionRoots())
{
TraverseTree(root, listener);
}
}
void TraverseTree(const ExecutionTreeConstPtr& execution, ExecutionTreeTraversalListener& listener)
{
listener.Reset();
TraverseTreeRecurse(execution, listener, nullptr, 0);
}
void TraverseTreeRecurse(const ExecutionTreeConstPtr& execution, ExecutionTreeTraversalListener& listener, const Slot* slot, int level)
{
if (listener.CancelledTraversal())
{
return;
}
if (!execution->GetParent())
{
listener.EvaluateRoot(execution, slot);
}
listener.Evaluate(execution, slot, level);
if (execution->GetChildrenCount() == 0 && !IsInLoop(execution) && !IsMidSequence(execution))
{
listener.EvaluateLeaf(execution, slot, level);
}
else
{
for (size_t i(0); i < execution->GetChildrenCount(); ++i)
{
auto& childIter = execution->GetChild(i);
if (childIter.m_execution)
{
listener.EvaluateChildPre(execution, childIter.m_slot, i, level + 1);
TraverseTreeRecurse(childIter.m_execution, listener, childIter.m_slot, level + 1);
listener.EvaluateChildPost(execution, childIter.m_slot, i, level + 1);
}
else if (!IsInLoop(execution) && !IsMidSequence(execution))
{
listener.EvaluateNullChildLeaf(execution, childIter.m_slot, i, level + 1);
}
}
}
}
}
}
@@ -17,6 +17,11 @@
namespace ScriptCanvas
{
namespace Nodes::Core
{
class FunctionDefinitionNode;
}
namespace Grammar
{
struct CheckOperatorResult
@@ -30,6 +35,18 @@ namespace ScriptCanvas
CheckOperatorResult(Symbol symbol, AZStd::string_view name, LexicalScopeType scopeType);
};
struct VariableUseage
{
bool usesExternallyInitializedVariables = false;
AZStd::unordered_set<VariableConstPtr> localVariables;
AZStd::unordered_set<VariableConstPtr> memberVariables;
AZStd::unordered_set<VariableConstPtr> implicitMemberVariables;
void Clear();
void Parse(VariableConstPtr variable);
};
bool ActivatesSelf(const ExecutionTreeConstPtr& execution);
EventHandingType CheckEventHandlingType(const ExecutionTreeConstPtr& execution);
@@ -38,10 +55,16 @@ namespace ScriptCanvas
Symbol CheckLogicalExpressionSymbol(const ExecutionTreeConstPtr& execution);
NodelingType CheckNodelingType(const Node& node);
CheckOperatorResult CheckOperatorArithmeticSymbol(const ExecutionTreeConstPtr& execution);
void DenumberFirstCharacter(AZStd::string& identifier);
bool ExecutionContainsCycles(const Node& node, const Slot& outSlot);
ExecutionTraversalResult TraverseExecutionConnections(const Node& node, const Slot& outSlot, GraphExecutionPathTraversalListener& listener);
bool ExecutionWritesVariable(ExecutionTreeConstPtr execution, VariableConstPtr variable);
const Slot* GetOnceOnResetSlot(const Node& node);
@@ -56,6 +79,8 @@ namespace ScriptCanvas
bool IsBreak(const ExecutionTreeConstPtr& execution);
bool IsCodeConstructable(VariableConstPtr value);
bool IsCycle(const Node& node);
bool IsCycle(const ExecutionTreeConstPtr& execution);
@@ -70,6 +95,8 @@ namespace ScriptCanvas
bool IsExecutedPropertyExtraction(const ExecutionTreeConstPtr& execution);
bool IsExternallyInitialized(VariableConstPtr value);
bool IsFloatingPointNumberEqualityComparison(ExecutionTreeConstPtr execution);
bool IsFlowControl(const ExecutionTreeConstPtr& execution);
@@ -96,6 +123,8 @@ namespace ScriptCanvas
bool IsLooping(Symbol symbol);
bool IsManuallyDeclaredUserVariable(VariableConstPtr variable);
bool IsMidSequence(const ExecutionTreeConstPtr& execution);
bool IsNoOp(const AbstractCodeModel& model, const ExecutionTreeConstPtr& parent, const Grammar::ExecutionChild& child);
@@ -116,6 +145,10 @@ namespace ScriptCanvas
bool IsPropertyExtractionNode(const ExecutionTreeConstPtr& execution);
bool IsPure(Symbol symbol);
bool IsPure(const Node* node, const Slot* slot);
bool IsRandomSwitchStatement(const ExecutionTreeConstPtr& execution);
bool IsSequenceNode(const Node* node);
@@ -126,11 +159,11 @@ namespace ScriptCanvas
bool IsUserFunctionCall(const ExecutionTreeConstPtr& execution);
bool IsUserFunctionCallPure(const ExecutionTreeConstPtr& execution);
bool IsUserFunctionDefinition(const ExecutionTreeConstPtr& execution);
bool IsUserOut(const ExecutionTreeConstPtr& execution);
const ScriptCanvas::Nodes::Core::FunctionDefinitionNode* IsUserOutNode(const Node* node);
const ScriptCanvas::Nodes::Core::FunctionDefinitionNode* IsUserOutNode(const ExecutionTreeConstPtr& execution);
bool IsVariableGet(const ExecutionTreeConstPtr& execution);
@@ -140,12 +173,12 @@ namespace ScriptCanvas
bool IsWrittenMathExpression(const ExecutionTreeConstPtr& execution);
void TraverseTree(const AbstractCodeModel& execution, ExecutionTreeIterationListener& listener);
void TraverseTree(const ExecutionTreeConstPtr& execution, ExecutionTreeIterationListener& listener);
AZStd::string MakeMemberVariableName(AZStd::string_view name);
VariableConstructionRequirement ParseConstructionRequirement(Grammar::VariableConstPtr value);
void ParseVariableUse(ExecutionTreeConstPtr execution, VariableUseage& variableUse);
void PrettyPrint(AZStd::string& result, const AbstractCodeModel& model);
void PrettyPrint(AZStd::string& result, const ExecutionTreeConstPtr& execution, ExecutionTreeConstPtr marker = nullptr);
@@ -162,6 +195,9 @@ namespace ScriptCanvas
AZStd::string ToIdentifierSafe(AZStd::string_view name);
void TraverseTree(const AbstractCodeModel& execution, ExecutionTreeTraversalListener& listener);
void TraverseTree(const ExecutionTreeConstPtr& execution, ExecutionTreeTraversalListener& listener);
}
}

Some files were not shown because too many files have changed in this diff Show More