diff --git a/Code/Framework/AzCore/AzCore/RTTI/AzStdOnDemandReflection.inl b/Code/Framework/AzCore/AzCore/RTTI/AzStdOnDemandReflection.inl index 079c70c878..537d3e5c83 100644 --- a/Code/Framework/AzCore/AzCore/RTTI/AzStdOnDemandReflection.inl +++ b/Code/Framework/AzCore/AzCore/RTTI/AzStdOnDemandReflection.inl @@ -1020,29 +1020,60 @@ namespace AZ } }; - /// OnDemand reflection for AZStd::set + + template + class Iterator_VM> + { + public: + using ContainerType = AZStd::unordered_set; + using IteratorType = typename ContainerType::iterator; + Iterator_VM(ContainerType& container) + : m_iterator(container.begin()) + , m_end(container.end()) + {} + + const t_Key& GetKeyUnchecked() const + { + return *m_iterator; + } + + bool IsNotAtEnd() const + { + return m_iterator != m_end; + } + + t_Key& ModValueUnchecked() + { + return *m_iterator; + } + + void Next() + { + ++m_iterator; + } + + private: + IteratorType m_iterator; + IteratorType m_end; + }; + + /// OnDemand reflection for AZStd::unordered_set template struct OnDemandReflection< AZStd::unordered_set > { using ContainerType = AZStd::unordered_set; using KeyListType = AZStd::vector; - static AZ::Outcome Erase(ContainerType& thisMap, Key& key) + using ValueIteratorType = Iterator_VM; + + static bool EraseCheck_VM(ContainerType& thisSet, Key& key) { - const auto result = thisMap.erase(key); - if (result) - { - return AZ::Success(); - } - else - { - return AZ::Failure(); - } + return thisSet.erase(key) != 0; } - static void Insert(ContainerType& thisSet, Key& key) + static ContainerType& ErasePost_VM(ContainerType& thisSet, [[maybe_unused]] Key&) { - thisSet.insert(key); + return thisSet; } static KeyListType GetKeys(ContainerType& thisSet) @@ -1055,6 +1086,17 @@ namespace AZ return keys; } + static ContainerType& Insert(ContainerType& thisSet, Key& key) + { + thisSet.insert(key); + return thisSet; + } + + static ValueIteratorType Iterate_VM(ContainerType& thisContainer) + { + return ValueIteratorType(thisContainer); + } + static void Swap(ContainerType& thisSet, ContainerType& otherSet) { thisSet.swap(otherSet); @@ -1064,33 +1106,68 @@ namespace AZ { if (BehaviorContext* behaviorContext = azrtti_cast(context)) { + BranchOnResultInfo emptyBranchInfo; + emptyBranchInfo.m_returnResultInBranches = true; + emptyBranchInfo.m_trueToolTip = "The container is empty"; + emptyBranchInfo.m_falseToolTip = "The container is not empty"; + auto ContainsTransparent = [](const ContainerType& containerType, typename ContainerType::key_type& key)->bool { return containerType.contains(key); }; + ExplicitOverloadInfo explicitOverloadInfo; behaviorContext->Class() - ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::ListOnly) ->Attribute(AZ::ScriptCanvasAttributes::PrettyName, ScriptCanvasOnDemandReflection::OnDemandPrettyName::Get(*behaviorContext)) ->Attribute(AZ::Script::Attributes::ToolTip, ScriptCanvasOnDemandReflection::OnDemandToolTip::Get(*behaviorContext)) ->Attribute(AZ::Script::Attributes::Category, ScriptCanvasOnDemandReflection::OnDemandCategoryName::Get(*behaviorContext)) ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::ScriptOwn) ->Method("BucketCount", static_cast(&ContainerType::bucket_count)) - ->Method("Erase", &Erase) - ->Method("Empty", [](ContainerType& thisSet)->bool { return thisSet.empty(); }) + ->Method("Empty", static_cast(&ContainerType::empty), { { { "Container", "The container to check if it is empty", nullptr, {} } } }) + ->Attribute(AZ::ScriptCanvasAttributes::ExplicitOverloadCrc, ExplicitOverloadInfo("Is Empty", "Containers")) + ->Attribute(AZ::ScriptCanvasAttributes::BranchOnResult, emptyBranchInfo) + ->Method("EraseCheck_VM", &EraseCheck_VM) + ->Attribute(AZ::Script::Attributes::TreatAsMemberFunction, AZ::AttributeIsValid::IfPresent) + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) + ->Method("Erase", &ErasePost_VM) + ->Attribute(AZ::Script::Attributes::TreatAsMemberFunction, AZ::AttributeIsValid::IfPresent) + ->Attribute(AZ::ScriptCanvasAttributes::ExplicitOverloadCrc, ExplicitOverloadInfo("Erase", "Containers")) + ->Attribute(AZ::ScriptCanvasAttributes::CheckedOperation, CheckedOperationInfo("EraseCheck_VM", {}, "Out", "Key Not Found", true)) + ->Attribute(AZ::ScriptCanvasAttributes::OverloadArgumentGroup, AZ::OverloadArgumentGroupInfo({ "ContainerGroup", "" }, { "ContainerGroup" })) ->Method("contains", ContainsTransparent) + ->Attribute(AZ::ScriptCanvasAttributes::ExplicitOverloadCrc, ExplicitOverloadInfo("Has Key", "Containers")) ->Attribute(AZ::Script::Attributes::TreatAsMemberFunction, AZ::AttributeIsValid::IfPresent) ->Method("Insert", &Insert) + ->Attribute(AZ::Script::Attributes::TreatAsMemberFunction, AZ::AttributeIsValid::IfPresent) + ->Attribute(AZ::ScriptCanvasAttributes::ExplicitOverloadCrc, ExplicitOverloadInfo("Insert", "Containers")) + ->Attribute(AZ::ScriptCanvasAttributes::OverloadArgumentGroup, AZ::OverloadArgumentGroupInfo({ "ContainerGroup", "", "" }, { "ContainerGroup" })) ->Method(k_sizeName, [](ContainerType* thisPtr) { return aznumeric_cast(thisPtr->size()); }) ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Length) ->Method("GetKeys", &GetKeys) ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) + ->Method("GetSize", [](ContainerType& thisPtr) { return aznumeric_cast(thisPtr.size()); }) + ->Attribute(AZ::ScriptCanvasAttributes::ExplicitOverloadCrc, ExplicitOverloadInfo("Get Size", "Containers")) + ->Attribute(AZ::Script::Attributes::TreatAsMemberFunction, AZ::AttributeIsValid::IfPresent) ->Method("Reserve", static_cast(&ContainerType::reserve)) ->Method("Swap", &Swap) + ->Method("Clear", [](ContainerType& thisContainer)->ContainerType& { thisContainer.clear(); return thisContainer; }) + ->Attribute(AZ::Script::Attributes::TreatAsMemberFunction, AZ::AttributeIsValid::IfPresent) + ->Attribute(AZ::ScriptCanvasAttributes::ExplicitOverloadCrc, ExplicitOverloadInfo("Clear All Elements", "Containers")) + ->Attribute(AZ::ScriptCanvasAttributes::OverloadArgumentGroup, AZ::OverloadArgumentGroupInfo({ "ContainerGroup" }, { "ContainerGroup" })) + ->Method(k_iteratorConstructorName, &Iterate_VM) + ; + + behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::ListOnly) + ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::ScriptOwn) + ->Method(k_iteratorGetKeyName, &ValueIteratorType::GetKeyUnchecked) + ->Method(k_iteratorModValueName, &ValueIteratorType::ModValueUnchecked) + ->Method(k_iteratorIsNotAtEndName, &ValueIteratorType::IsNotAtEnd) + ->Method(k_iteratorNextName, &ValueIteratorType::Next) ; } } - }; template <> diff --git a/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.cpp b/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.cpp index 635d160434..31a2cfc09e 100644 --- a/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.cpp +++ b/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.cpp @@ -165,7 +165,7 @@ namespace AZ if (HasResult() != overload->HasResult()) { - AZ_Error("Reflection", false, "Overload failure, all methods must have the same result, or none at all"); + AZ_Error("Reflection", false, "Overload failure, all methods must have the same result, or none at all: %s", m_name.c_str()); return false; } @@ -176,7 +176,7 @@ namespace AZ if (!(methodResult->m_typeId == overloadResult->m_typeId && methodResult->m_traits == overloadResult->m_traits)) { - AZ_Error("Reflection", false, "Overload failure, all methods must have the same result, or none at all"); + AZ_Error("Reflection", false, "Overload failure, all methods must have the same result, or none at all: %s", m_name.c_str()); return false; } } @@ -575,7 +575,7 @@ namespace AZ } else { - AZ_Error("BehaviorContext", false, "safety check declared for method %s but it was not found in the class"); + AZ_Error("BehaviorContext", false, "Method: %s, declared safety check: %s, but it was not found in class: %s", method.m_name.c_str(), m_name.c_str(), checkedOperationInfo.m_safetyCheckName.c_str()); } } } diff --git a/Code/Framework/AzCore/AzCore/RTTI/BehaviorContextUtilities.cpp b/Code/Framework/AzCore/AzCore/RTTI/BehaviorContextUtilities.cpp index c64b86ae0f..f6aac0fa16 100644 --- a/Code/Framework/AzCore/AzCore/RTTI/BehaviorContextUtilities.cpp +++ b/Code/Framework/AzCore/AzCore/RTTI/BehaviorContextUtilities.cpp @@ -34,10 +34,17 @@ namespace BehaviorContextUtilitiesCPP using argument_type = const BehaviorParameter*; using result_type = size_t; result_type operator()(const argument_type& value) const - { - result_type result = AZStd::hash()(value->m_typeId); - AZStd::hash_combine(result, CleanTraits(value->m_traits)); - return result; + { + if (value) + { + result_type result = AZStd::hash()(value->m_typeId); + AZStd::hash_combine(result, CleanTraits(value->m_traits)); + return result; + } + else + { + return 0; + } } }; @@ -45,7 +52,11 @@ namespace BehaviorContextUtilitiesCPP { bool operator()(const BehaviorParameter* left, const BehaviorParameter* right) const { - return left->m_typeId == right->m_typeId && CleanTraits(left->m_traits) == CleanTraits(right->m_traits); + return (left == nullptr && right == nullptr) + || (left != nullptr + && right != nullptr + && left->m_typeId == right->m_typeId + && CleanTraits(left->m_traits) == CleanTraits(right->m_traits)); } }; @@ -137,7 +148,7 @@ namespace AZ for (size_t argIndex = 0, argSentinel = overload.GetNumArguments(); argIndex < argSentinel; ++argIndex) { auto overloadedArgIter = variance.m_input.find(argIndex); - if (overloadedArgIter != variance.m_input.end()) + if (overloadedArgIter != variance.m_input.end() && overloadedArgIter->second[overloadIndex]) { // if this doesn't work try the type name overloadName += ReplaceCppArtifacts(overloadedArgIter->second[overloadIndex]->m_name); @@ -185,16 +196,24 @@ namespace AZ { auto argument = overloads[overloadIndex].first->GetArgument(0); - const bool isThisPointer - = (argument->m_traits & AZ::BehaviorParameter::Traits::TR_THIS_PTR) != 0 - || AZ::FindAttribute(AZ::Script::Attributes::TreatAsMemberFunction, overloads[overloadIndex].first->m_attributes); + if (argument) + { + const bool isThisPointer + = (argument->m_traits & AZ::BehaviorParameter::Traits::TR_THIS_PTR) != 0 + || AZ::FindAttribute(AZ::Script::Attributes::TreatAsMemberFunction, overloads[overloadIndex].first->m_attributes); - oneArgIsThisPointer = oneArgIsThisPointer || isThisPointer; + oneArgIsThisPointer = oneArgIsThisPointer || isThisPointer; + } types.insert(argument); stripedArgs.emplace_back(argument); } + if (types.size() == overloads.size()) + { + variance.m_unambiguousInput.insert(0); + } + if (types.size() > 1 && (onThis == VariantOnThis::Yes || !oneArgIsThisPointer)) { variance.m_input.insert(AZStd::make_pair(0, stripedArgs)); @@ -210,11 +229,15 @@ namespace AZ for (size_t overloadIndex = 0, overloadSentinel = overloads.size(); overloadIndex < overloadSentinel; ++overloadIndex) { auto argument = overloads[overloadIndex].first->GetArgument(argIndex); - types.insert(argument); stripedArgs.emplace_back(argument); } + if (types.size() == overloads.size()) + { + variance.m_unambiguousInput.insert(0); + } + if (types.size() > 1) { variance.m_input.insert(AZStd::make_pair(argIndex, stripedArgs)); diff --git a/Code/Framework/AzCore/AzCore/RTTI/BehaviorContextUtilities.h b/Code/Framework/AzCore/AzCore/RTTI/BehaviorContextUtilities.h index 4663635cdf..0dc9ecc969 100644 --- a/Code/Framework/AzCore/AzCore/RTTI/BehaviorContextUtilities.h +++ b/Code/Framework/AzCore/AzCore/RTTI/BehaviorContextUtilities.h @@ -27,6 +27,8 @@ namespace AZ struct OverloadVariance { AZStd::unordered_map> m_input; + // the indices of inputs that make selection of overload unambiguous + AZStd::unordered_set m_unambiguousInput; AZStd::vector m_output; }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/GenericComboBoxCtrl.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/GenericComboBoxCtrl.h index 48b5148d3c..4cf6d077e7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/GenericComboBoxCtrl.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/GenericComboBoxCtrl.h @@ -83,7 +83,7 @@ namespace AzToolsFramework protected: QWidget* GetFirstInTabOrder() override; QWidget* GetLastInTabOrder() override; - void UpdateTabOrder() override; + void UpdateTabOrder() override; void onChildComboBoxValueChange(int comboBoxIndex) override; @@ -93,7 +93,7 @@ namespace AzToolsFramework void addElementImpl(const AZStd::pair& genericValue); - QLabel* m_warningLabel = nullptr; + QLabel* m_warningLabel = nullptr; DHQComboBox* m_pComboBox; AZStd::vector> m_values; AZ::AttributeFunction * m_postChangeNotifyCB{}; @@ -131,6 +131,11 @@ namespace AzToolsFramework template AzToolsFramework::PropertyHandlerBase* RegisterGenericComboBoxHandler() { + if (!AzToolsFramework::PropertyTypeRegistrationMessages::Bus::FindFirstHandler()) + { + return nullptr; + } + auto propertyHandler = aznew GenericComboBoxHandler(); AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Broadcast(&AzToolsFramework::PropertyTypeRegistrationMessages::RegisterPropertyType, propertyHandler); return propertyHandler; diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp index 9c9297ec1c..6f28cbfe19 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp @@ -512,7 +512,7 @@ namespace ScriptCanvasEditor } } - bool Graph::SanityCheckNodeReplacement(ScriptCanvas::Node* oldNode, ScriptCanvas::Node* newNode, AZStd::unordered_map>& outSlotIdMap) + bool Graph::SanityCheckNodeReplacement(ScriptCanvas::Node* oldNode, ScriptCanvas::Node* newNode, ScriptCanvas::NodeUpdateSlotReport& nodeUpdateSlotReport) { auto findReplacementMatch = [](const ScriptCanvas::Slot* oldSlot, const AZStd::vector& newSlots)->ScriptCanvas::SlotId { @@ -529,14 +529,14 @@ namespace ScriptCanvasEditor return {}; }; - oldNode->CustomizeReplacementNode(newNode, outSlotIdMap); - if (!newNode) { AZ_Warning("ScriptCanvas", false, "Replacement node can not be null."); return false; } + oldNode->CustomizeReplacementNode(newNode, nodeUpdateSlotReport.m_oldSlotsToNewSlots); + AZStd::unordered_map> slotNameMap = oldNode->GetReplacementSlotsMap(); const auto newSlots = newNode->GetAllSlots(); @@ -544,16 +544,19 @@ namespace ScriptCanvasEditor bool usingDefaults = true; size_t defaultMatchesFound = 0; + auto& oldSlotsToNewSlots = nodeUpdateSlotReport.m_oldSlotsToNewSlots; + for (auto oldSlot : oldSlots) { const ScriptCanvas::SlotId oldSlotId = oldSlot->GetId(); const AZStd::string oldSlotName = oldSlot->GetName(); - auto slotIdsIter = outSlotIdMap.find(oldSlotId); + + auto slotIdsIter = oldSlotsToNewSlots.find(oldSlotId); auto slotNamesIter = slotNameMap.find(oldSlotName); // For old node slot remapping, we should get: // 1. if old slot name is not static, we should find the mapping in user provided slot id map // 2. if old slot name is static, we should find the mapping in codegen generated map (case 1 can override case 2) - if (slotIdsIter != outSlotIdMap.end()) + if (slotIdsIter != oldSlotsToNewSlots.end()) { for (auto newSlotId : slotIdsIter->second) { @@ -581,9 +584,10 @@ namespace ScriptCanvasEditor if (!newSlotName.empty()) { auto newSlot = newNode->GetSlotByName(newSlotName); + if (!newSlot) { - AZ_Warning("ScriptCanvas", false, "Failed to find slot with name %s in replacement Node(%s).", newSlotName.c_str(), newNode->GetNodeName().c_str()); + AZ_Warning("ScriptCanvas", false, "Failed to find slot with name %s in replacement Node (%s).", newSlotName.c_str(), newNode->GetNodeName().c_str()); return false; } else if (newSlot && oldSlot->GetType() != newSlot->GetType()) @@ -591,10 +595,11 @@ namespace ScriptCanvasEditor AZ_Warning("ScriptCanvas", false, "Failed to map deprecated Node (%s) Slot (%s) to replacement Node (%s) Slot (%s).", oldNode->GetNodeName().c_str(), oldSlot->GetName().c_str(), newNode->GetNodeName().c_str(), newSlot->GetName().c_str()); return false; } + newSlotIds.push_back(newSlot->GetId()); } } - outSlotIdMap.emplace(oldSlot->GetId(), newSlotIds); + oldSlotsToNewSlots.emplace(oldSlot->GetId(), newSlotIds); } else if (slotNameMap.empty()) { @@ -605,7 +610,7 @@ namespace ScriptCanvasEditor { ++defaultMatchesFound; AZStd::vector slotIds{ newSlotId }; - outSlotIdMap.emplace(oldSlot->GetId(), slotIds); + oldSlotsToNewSlots.emplace(oldSlot->GetId(), slotIds); } } else @@ -615,7 +620,7 @@ namespace ScriptCanvasEditor } } - if (usingDefaults && defaultMatchesFound != oldSlots.size()) + if (usingDefaults && oldSlotsToNewSlots.size() != oldSlots.size()) { AZ_Warning("ScriptCanvas", false, "Failed to remap deprecated Node(%s) not all old slots were present in the new node.", oldNode->GetNodeName().c_str()); } @@ -690,8 +695,10 @@ namespace ScriptCanvasEditor } } - AZ::Outcome Graph::ReplaceNodeByConfig(ScriptCanvas::Node* oldNode, const ScriptCanvas::NodeConfiguration& nodeConfig, - ScriptCanvas::ReplacementConnectionMap& remapConnections) + AZ::Outcome Graph::ReplaceNodeByConfig + ( ScriptCanvas::Node* oldNode + , const ScriptCanvas::NodeConfiguration& nodeConfig + , ScriptCanvas::NodeUpdateSlotReport& nodeUpdateSlotReport) { auto nodeEntity = oldNode->GetEntity(); if (!nodeEntity) @@ -731,8 +738,8 @@ namespace ScriptCanvasEditor AddNode(newNode->GetEntityId()); ScriptCanvas::NodeUtils::InitializeNode(newNode, nodeConfig); - AZStd::unordered_map> slotIdMap; - rollbackRequired = !SanityCheckNodeReplacement(oldNode, newNode, slotIdMap); + rollbackRequired = !SanityCheckNodeReplacement(oldNode, newNode, nodeUpdateSlotReport); + auto& slotIdMap = nodeUpdateSlotReport.m_oldSlotsToNewSlots; if (rollbackRequired) { @@ -748,25 +755,15 @@ namespace ScriptCanvasEditor else { nodeEntity->Activate(); - newNode->SignalReconfigurationBegin(); - newNode->SetNodeDisabledFlag(oldNode->GetNodeDisabledFlag()); + for (auto slotIdIter : slotIdMap) { ScriptCanvas::Slot* oldSlot = oldNode->GetSlot(slotIdIter.first); const ScriptCanvas::Endpoint oldEndpoint{ nodeEntity->GetId(), oldSlot->GetId() }; if (slotIdIter.second.size() == 0) { - // If remap id is empty, then we should just cache the old slot connection for delete - if (oldSlot->IsInput()) - { - ScriptCanvas::VersioningUtils::CreateRemapConnectionsForTargetEndpoint(*this, oldEndpoint, ScriptCanvas::Endpoint(), remapConnections); - } - else - { - ScriptCanvas::VersioningUtils::CreateRemapConnectionsForSourceEndpoint(*this, oldEndpoint, ScriptCanvas::Endpoint(), remapConnections); - } continue; } @@ -808,35 +805,11 @@ namespace ScriptCanvasEditor ScriptCanvas::VersioningUtils::CopyOldValueToDataSlot(newSlot, oldSlot->GetVariableReference(), oldSlot->FindDatum()); } - - // if old slot is visible, we need to check its connections for remapping - if (oldSlot->IsVisible()) - { - ScriptCanvas::Endpoint newEndpoint; - if (newSlot) - { - newEndpoint = { nodeEntity->GetId(), newSlot->GetId() }; - } - else - { - AZ_Warning("ScriptCanvas", false, "Invalid slot! Unable to create new connection for Node (%s).", newNode->GetNodeName().c_str()); - } - - if (oldSlot->IsInput()) - { - ScriptCanvas::VersioningUtils::CreateRemapConnectionsForTargetEndpoint(*this, oldEndpoint, newEndpoint, remapConnections); - } - else - { - ScriptCanvas::VersioningUtils::CreateRemapConnectionsForSourceEndpoint(*this, oldEndpoint, newEndpoint, remapConnections); - } - } } } + delete oldNode; - newNode->SignalReconfigurationEnd(); - return AZ::Success(newNode); } } @@ -3634,8 +3607,7 @@ namespace ScriptCanvasEditor AZStd::unordered_map< AZ::EntityId, AZ::EntityId > scriptCanvasToGraphCanvasMapping; - bool graphNeedsDirtying = false; - + bool graphNeedsDirtying = !GetVersion().IsLatest(); { QScopedValueRollback ignoreRequests(m_ignoreSaveRequests, true); @@ -3659,7 +3631,8 @@ namespace ScriptCanvasEditor AZStd::unordered_set deletedNodes; AZStd::unordered_set assetSanitizationSet; AZStd::unordered_set sanityCheckRequiredNodes; - ScriptCanvas::ReplacementConnectionMap remapConnections; + + ScriptCanvas::GraphUpdateSlotReport graphUpdateSlotReport; for (const AZ::EntityId& scriptCanvasNodeId : nodeList) { @@ -3674,12 +3647,15 @@ namespace ScriptCanvasEditor ScriptCanvas::NodeConfiguration nodeConfig = scriptCanvasNode->GetReplacementNodeConfiguration(); if (nodeConfig.IsValid()) { - auto nodeOutcome = ReplaceNodeByConfig(scriptCanvasNode, nodeConfig, remapConnections); + ScriptCanvas::NodeUpdateSlotReport nodeUpdateSlotReport; + auto nodeOutcome = ReplaceNodeByConfig(scriptCanvasNode, nodeConfig, nodeUpdateSlotReport); + if (nodeOutcome.IsSuccess()) { graphNeedsDirtying = true; scriptCanvasNode = nodeOutcome.GetValue(); m_updateStrings.insert(AZStd::string::format("Replaced node (%s)", scriptCanvasNode->GetNodeName().c_str())); + ScriptCanvas::MergeUpdateSlotReport(scriptCanvasNodeId, graphUpdateSlotReport, nodeUpdateSlotReport); } } } @@ -3688,7 +3664,6 @@ namespace ScriptCanvasEditor scriptCanvasToGraphCanvasMapping[scriptCanvasNodeId] = graphCanvasNodeId; auto saveDataIter2 = m_graphCanvasSaveData.find(scriptCanvasNodeId); - if (saveDataIter2 != m_graphCanvasSaveData.end()) { GraphCanvas::EntitySaveDataRequestBus::Event(graphCanvasNodeId, &GraphCanvas::EntitySaveDataRequests::ReadSaveData, (*saveDataIter2->second)); @@ -3699,7 +3674,7 @@ namespace ScriptCanvasEditor GraphCanvas::SceneRequestBus::Event(graphCanvasGraphId, &GraphCanvas::SceneRequests::AddNode, graphCanvasNodeId, position, false); - // If the node is deprecated, we want to stomp whatever style it had saved and apply the deperecated style + // If the node is deprecated, we want to stomp whatever style it had saved and apply the deprecated style if (scriptCanvasNode->IsDeprecated()) { GraphCanvas::NodeTitleRequestBus::Event(graphCanvasNodeId, &GraphCanvas::NodeTitleRequests::SetPaletteOverride, "DeprecatedNodeTitlePalette"); @@ -3719,27 +3694,13 @@ namespace ScriptCanvasEditor } } - // Remap connections step should be done before editor processing connections for graph - // - // Delete underlying data conenections. - for (auto remapConnection : remapConnections) + if (!graphUpdateSlotReport.IsEmpty()) { - RemoveConnection(remapConnection.first); + // currently, it is expected that there are no deleted old slots, those need manual correction + AZ_Error("ScriptCanvas", graphUpdateSlotReport.m_deletedOldSlots.empty(), "Graph upgrade path: If old slots are deleted, manual upgrading is required"); + UpdateConnectionStatus(*this, graphUpdateSlotReport); } - // Recreate connections in a separate pass to avoid triggering display updates for invalid slot ids. - for (auto remapConnection : remapConnections) - { - for (auto newEndpointPair : remapConnection.second) - { - if (newEndpointPair.first.IsValid() && newEndpointPair.second.IsValid()) - { - ConnectByEndpoint(newEndpointPair.first, newEndpointPair.second); - } - } - } - //// - AZStd::unordered_set graphCanvasNodesToDelete; for (auto scriptCanvasNode : outOfDateNodes) diff --git a/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp b/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp index 7762e1d095..581c3775d6 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp @@ -424,24 +424,11 @@ namespace ScriptCanvasEditor EditorGraphUpgradeMachine* sm = GetStateMachine(); auto* graph = sm->m_graph; - // Delete underlying data connections. - for (auto remapConnection : sm->m_replacementConnections) + if (!sm->m_updateReport.IsEmpty()) { - graph->RemoveConnection(remapConnection.first); - } - - // Recreate connections in a separate pass to avoid triggering display updates for invalid slot ids. - for (auto remapConnection : sm->m_replacementConnections) - { - for (auto newEndpointPair : remapConnection.second) - { - if (newEndpointPair.first.IsValid() && newEndpointPair.second.IsValid()) - { - graph->ConnectByEndpoint(newEndpointPair.first, newEndpointPair.second); - - Log("Replaced Connection: %s\n", Helpers::ConnectionToText(graph, newEndpointPair.first, newEndpointPair.second).c_str()); - } - } + // currently, it is expected that there are no deleted old slots, those need manual correction + AZ_Error("ScriptCanvas", sm->m_updateReport.m_deletedOldSlots.empty(), "Graph upgrade path: If old slots are deleted, manual upgrading is required"); + UpdateConnectionStatus(*graph, sm->m_updateReport); } } @@ -455,16 +442,18 @@ namespace ScriptCanvasEditor ScriptCanvas::NodeConfiguration nodeConfig = node->GetReplacementNodeConfiguration(); if (nodeConfig.IsValid()) { - auto nodeOutcome = graph->ReplaceNodeByConfig(node, nodeConfig, sm->m_replacementConnections); + ScriptCanvas::NodeUpdateSlotReport nodeUpdateSlotReport; + auto nodeOutcome = graph->ReplaceNodeByConfig(node, nodeConfig, nodeUpdateSlotReport); if (nodeOutcome.IsSuccess()) { + ScriptCanvas::MergeUpdateSlotReport(node->GetEntityId(), sm->m_updateReport, nodeUpdateSlotReport); + sm->m_allNodes.erase(node); sm->m_outOfDateNodes.erase(node); sm->m_sanityCheckRequiredNodes.erase(node); - sm->m_graphNeedsDirtying = true; - auto replacedNode = nodeOutcome.GetValue(); + auto replacedNode = nodeOutcome.GetValue(); sm->m_allNodes.insert(replacedNode); if (replacedNode->IsOutOfDate(graph->GetVersion())) diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h index 3bd8270629..687d783e63 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/EditorGraph.h @@ -42,6 +42,7 @@ namespace ScriptCanvas { struct NodeConfiguration; + struct NodeUpdateSlotReport; } namespace ScriptCanvasEditor @@ -361,8 +362,8 @@ namespace ScriptCanvasEditor void HandleFunctionDefinitionExtension(ScriptCanvas::Node* node, GraphCanvas::SlotId graphCanvasSlotId, const GraphCanvas::NodeId& nodeId); //// Version Update code - AZ::Outcome ReplaceNodeByConfig(ScriptCanvas::Node*, const ScriptCanvas::NodeConfiguration&, ScriptCanvas::ReplacementConnectionMap&); - bool SanityCheckNodeReplacement(ScriptCanvas::Node*, ScriptCanvas::Node*, AZStd::unordered_map>&); + AZ::Outcome ReplaceNodeByConfig(ScriptCanvas::Node*, const ScriptCanvas::NodeConfiguration&, ScriptCanvas::NodeUpdateSlotReport& nodeUpdateSlotReport); + bool SanityCheckNodeReplacement(ScriptCanvas::Node*, ScriptCanvas::Node*, ScriptCanvas::NodeUpdateSlotReport& nodeUpdateSlotReport); bool m_allowVersionUpdate = false; AZStd::unordered_set< AZ::EntityId > m_queuedConvertingNodes; diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/GraphUpgrade.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/GraphUpgrade.h index 791e649e3a..cc5315808e 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/GraphUpgrade.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/GraphUpgrade.h @@ -159,7 +159,7 @@ namespace ScriptCanvasEditor AZStd::unordered_set m_deletedNodes; AZStd::unordered_set m_assetSanitizationSet; - ScriptCanvas::ReplacementConnectionMap m_replacementConnections; + ScriptCanvas::GraphUpdateSlotReport m_updateReport; AZStd::unordered_map< AZ::EntityId, AZ::EntityId > m_scriptCanvasToGraphCanvasMapping; diff --git a/Gems/ScriptCanvas/Code/Editor/Static/Include/ScriptCanvas/View/EditCtrls/GenericLineEditCtrl.h b/Gems/ScriptCanvas/Code/Editor/Static/Include/ScriptCanvas/View/EditCtrls/GenericLineEditCtrl.h index 74f363f569..06a63fe8b6 100644 --- a/Gems/ScriptCanvas/Code/Editor/Static/Include/ScriptCanvas/View/EditCtrls/GenericLineEditCtrl.h +++ b/Gems/ScriptCanvas/Code/Editor/Static/Include/ScriptCanvas/View/EditCtrls/GenericLineEditCtrl.h @@ -123,6 +123,11 @@ namespace ScriptCanvasEditor template AzToolsFramework::PropertyHandlerBase* RegisterGenericLineEditHandler(const EditCtrl::PropertyToStringCB& propertyToStringCB, const EditCtrl::StringToPropertyCB& stringToPropertyCB) { + if (!AzToolsFramework::PropertyTypeRegistrationMessages::Bus::FindFirstHandler()) + { + return nullptr; + } + auto propertyHandler(aznew GenericLineEditHandler(propertyToStringCB, stringToPropertyCB)); AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Broadcast(&AzToolsFramework::PropertyTypeRegistrationMessages::RegisterPropertyType, propertyHandler); return propertyHandler; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasGrammar_Header.jinja b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasGrammar_Header.jinja index 089e5fe6ff..fbf2bd5355 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasGrammar_Header.jinja +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasGrammar_Header.jinja @@ -75,7 +75,7 @@ public: \ void ConfigureSlots() override; \ bool RequiresDynamicSlotOrdering() const override; \ bool IsDeprecated() const override; \ -{% if deprecationUuid is defined %} NodeConfiguration GetReplacementNodeConfiguration() const override; \ +{% if deprecationUuid is defined %} ScriptCanvas::NodeConfiguration GetReplacementNodeConfiguration() const override; \ {% endif %} using Node::FindDatum; \ {% if Class.attrib['GraphEntryPoint'] is defined %} bool IsEntryPoint() const override { return {%if Class.attrib['GraphEntryPoint'] == "True" %}true{%else%}false{%endif%}; } \ @@ -168,4 +168,4 @@ struct {{ className | replace(' ','') }}Property {% endfor %} -{% endfor %} +{% endfor %} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Connection.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Connection.h index 155e5bb4c2..e2cd7008c8 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Connection.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Connection.h @@ -22,6 +22,7 @@ namespace ScriptCanvas { class Slot; + struct NodeUpdateSlotReport; class Connection : public AZ::Component @@ -64,6 +65,8 @@ namespace ScriptCanvas // GraphNotificationBus void OnNodeRemoved(const ID& nodeId) override; + void UpdateConnectionStatus(NodeUpdateSlotReport& report); + protected: //------------------------------------------------------------------------- static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Contracts/MethodOverloadContract.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Contracts/MethodOverloadContract.cpp index dd223f34ec..0f49fb8b5d 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Contracts/MethodOverloadContract.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Contracts/MethodOverloadContract.cpp @@ -33,7 +33,7 @@ namespace ScriptCanvas { if (m_availableIndexes.empty()) { - return -1; + return std::numeric_limits::max(); } return (*m_availableIndexes.begin()); @@ -151,19 +151,22 @@ namespace ScriptCanvas for (const AZ::BehaviorParameter* behaviorParameter : paramTypes.second) { - ScriptCanvas::Data::Type dataType = ScriptCanvas::Data::FromAZType(behaviorParameter->m_typeId); - if (ScriptCanvas::Data::IsValueType(dataType)) + if (behaviorParameter) { - isValueType = true; - } - else if (ScriptCanvas::Data::IsContainerType(dataType)) - { - isContainerType = true; - } + ScriptCanvas::Data::Type dataType = ScriptCanvas::Data::FromAZType(behaviorParameter->m_typeId); + if (ScriptCanvas::Data::IsValueType(dataType)) + { + isValueType = true; + } + else if (ScriptCanvas::Data::IsContainerType(dataType)) + { + isContainerType = true; + } - if (isValueType && isContainerType) - { - break; + if (isValueType && isContainerType) + { + break; + } } } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp index 8d24b67b4f..1637a2e71b 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.cpp @@ -616,6 +616,34 @@ namespace ScriptCanvas return false; } + + void Graph::RemoveAllConnections() + { + for (auto connectionEntity : m_graphData.m_connections) + { + if (auto connection = connectionEntity ? AZ::EntityUtils::FindFirstDerivedComponent(connectionEntity) : nullptr) + { + if (connection->GetSourceEndpoint().IsValid()) + { + EndpointNotificationBus::Event(connection->GetSourceEndpoint(), &EndpointNotifications::OnEndpointDisconnected, connection->GetTargetEndpoint()); + } + if (connection->GetTargetEndpoint().IsValid()) + { + EndpointNotificationBus::Event(connection->GetTargetEndpoint(), &EndpointNotifications::OnEndpointDisconnected, connection->GetSourceEndpoint()); + } + } + + GraphNotificationBus::Event(GetScriptCanvasId(), &GraphNotifications::OnConnectionRemoved, connectionEntity->GetId()); + } + + for (auto& connectionRef : m_graphData.m_connections) + { + delete connectionRef; + } + + m_graphData.m_connections.clear(); + } + bool Graph::RemoveConnection(const AZ::EntityId& connectionId) { if (connectionId.IsValid()) @@ -752,7 +780,6 @@ namespace ScriptCanvas auto* connectionEntity = aznew AZ::Entity("Connection"); connectionEntity->CreateComponent(sourceEndpoint, targetEndpoint); - AZ::Entity* nodeEntity{}; AZ::ComponentApplicationBus::BroadcastResult(nodeEntity, &AZ::ComponentApplicationRequests::FindEntity, sourceEndpoint.GetNodeId()); auto node = nodeEntity ? AZ::EntityUtils::FindFirstDerivedComponent(nodeEntity) : nullptr; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.h index 1862ce4966..49b22db2bf 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Graph.h @@ -87,6 +87,7 @@ namespace ScriptCanvas Slot* FindSlot(const Endpoint& endpoint) const override; bool AddConnection(const AZ::EntityId&) override; + void RemoveAllConnections(); bool RemoveConnection(const AZ::EntityId& connectionId) override; AZStd::vector GetConnections() const override; AZStd::vector GetConnectedEndpoints(const Endpoint& firstEndpoint) const override; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/PureData.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/PureData.h index e34bdb1c71..8426e90515 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/PureData.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/PureData.h @@ -53,7 +53,9 @@ namespace ScriptCanvas template void AddDefaultInputAndOutputTypeSlot(DatumType&& defaultValue); void AddInputTypeAndOutputTypeSlot(const Data::Type& type); - + + bool IsDeprecated() const override { return true; } + void OnActivate() override; void OnInputChanged(const Datum& input, const SlotId& id) override; void MarkDefaultableInput() override {} diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Slot.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Slot.cpp index d37427af0b..9784cc97c4 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Slot.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Slot.cpp @@ -347,6 +347,11 @@ namespace ScriptCanvas } } + void Slot::ClearDynamicGroup() + { + m_dynamicGroup = AZ::Crc32{}; + } + void Slot::ConvertToLatentExecutionOut() { if (IsExecution() && IsOutput()) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Slot.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Slot.h index c65d4efc84..794ce091b1 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Slot.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Slot.h @@ -68,6 +68,8 @@ namespace ScriptCanvas void AddContract(const ContractDescriptor& contractDesc); + void ClearDynamicGroup(); + template T* FindContract() { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp index 8dff6da9b1..732455857e 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp @@ -1036,12 +1036,12 @@ namespace ScriptCanvas if (azrtti_istypeof(&node)) { // todo Add node to these errors - AddError(nullptr, ValidationConstPtr(aznew NotYetImplemented(node.GetEntityId(), AZStd::string::format("NodeableNodeOverloaded doesn't have enough data connected to select a valid overload: %s", node.GetDebugName().data())))); + AddError(nullptr, ValidationConstPtr(aznew Internal::ParseError(node.GetEntityId(), AZStd::string::format("%s: %s", ParseErrors::NodeableNodeOverloadAmbiguous, node.GetDebugName().data())))); } else { // todo Add node to these errors - AddError(nullptr, ValidationConstPtr(aznew NotYetImplemented(node.GetEntityId(), AZStd::string::format("NodeableNode did not construct its internal node: %s", node.GetDebugName().data())))); + AddError(nullptr, ValidationConstPtr(aznew Internal::ParseError(node.GetEntityId(), AZStd::string::format("%s: %s", ParseErrors::NodeableNodeDidNotConstructInternalNodeable, node.GetDebugName().data())))); } } } @@ -2535,7 +2535,7 @@ namespace ScriptCanvas if (IsInfiniteVariableWriteHandlingLoop(*this, variableHandling, variableHandling->m_function, true)) { - AddError(variableHandling->m_function, aznew NotYetImplemented(AZ::EntityId(), ScriptCanvas::ParseErrors::InfiniteLoopWritingToVariable)); + AddError(variableHandling->m_function, aznew Internal::ParseError(AZ::EntityId(), ScriptCanvas::ParseErrors::InfiniteLoopWritingToVariable)); return false; } @@ -3312,7 +3312,7 @@ namespace ScriptCanvas } else { - AddError(execution, aznew NotYetImplemented(execution->GetNodeId(), childOutSlotsOutcome.TakeError())); + AddError(execution, aznew Internal::ParseError(execution->GetNodeId(), childOutSlotsOutcome.TakeError())); } } } @@ -3615,9 +3615,11 @@ namespace ScriptCanvas void AbstractCodeModel::ParseExecutionMultipleOutSyntaxSugar(ExecutionTreePtr execution, const EndpointsResolved& executionOutNodes, const AZStd::vector& outSlots) { + const auto executionNodeId = execution->GetId().m_node ? execution->GetId().m_node->GetEntityId() : AZ::EntityId(); + if (executionOutNodes.size() != outSlots.size()) { - AddError(AZ::EntityId(), execution, ParseErrors::ParseExecutionMultipleOutSyntaxSugarMismatchOutSize); + AddError(executionNodeId, execution, ParseErrors::ParseExecutionMultipleOutSyntaxSugarMismatchOutSize); } if (execution->GetSymbol() != Symbol::Sequence) @@ -3630,13 +3632,13 @@ namespace ScriptCanvas if (!child) { - AddError(AZ::EntityId(), execution, ParseErrors::ParseExecutionMultipleOutSyntaxSugarNullChildFound); + AddError(executionNodeId, execution, ParseErrors::ParseExecutionMultipleOutSyntaxSugarNullChildFound); return; } if (child->m_execution) { - AddError(AZ::EntityId(), execution, ParseErrors::ParseExecutionMultipleOutSyntaxSugarNonNullChildExecutionFound); + AddError(executionNodeId, execution, ParseErrors::ParseExecutionMultipleOutSyntaxSugarNonNullChildExecutionFound); return; } @@ -3660,7 +3662,7 @@ namespace ScriptCanvas if (execution->GetChildrenCount() != executionOutNodes.size()) { - AddError(AZ::EntityId(), execution, ParseErrors::ParseExecutionMultipleOutSyntaxSugarChildExecutionRemovedAndNotReplaced); + AddError(executionNodeId, execution, ParseErrors::ParseExecutionMultipleOutSyntaxSugarChildExecutionRemovedAndNotReplaced); return; } } @@ -4187,7 +4189,7 @@ namespace ScriptCanvas } else { - AddError(nullptr, aznew NotYetImplemented(execution->GetNodeId(), dataSlotsOutcome.TakeError())); + AddError(nullptr, aznew Internal::ParseError(execution->GetNodeId(), dataSlotsOutcome.TakeError())); } } } @@ -4494,13 +4496,13 @@ namespace ScriptCanvas } else { - AddError(execution, aznew NotYetImplemented(execution->GetNodeId(), returnSlotsOutcome.TakeError())); + AddError(execution, aznew Internal::ParseError(execution->GetNodeId(), returnSlotsOutcome.TakeError())); } } } else { - AddError(execution, aznew NotYetImplemented(execution->GetNodeId(), outputSlotsOutcome.TakeError())); + AddError(execution, aznew Internal::ParseError(execution->GetNodeId(), outputSlotsOutcome.TakeError())); } } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/BinaryOperator.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/BinaryOperator.cpp index e04f7c1725..cda93c1b36 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/BinaryOperator.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/BinaryOperator.cpp @@ -35,15 +35,6 @@ namespace ScriptCanvas } } - AZStd::unordered_map> ArithmeticExpression::GetReplacementSlotsMap() const - { - AZStd::unordered_map> slotsMap; - slotsMap.emplace(k_evaluateName, AZStd::vector{ "In" }); - slotsMap.emplace(k_outName, AZStd::vector{ "Out" }); - slotsMap.emplace(k_resultName, AZStd::vector{ "Result" }); - return slotsMap; - } - void ArithmeticExpression::OnInit() { { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/BinaryOperator.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/BinaryOperator.h index 351d02f2cc..7c230b359a 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/BinaryOperator.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/BinaryOperator.h @@ -72,7 +72,6 @@ namespace ScriptCanvas bool IsDeprecated() const override { return true; } - AZStd::unordered_map> GetReplacementSlotsMap() const override; void CustomizeReplacementNode(Node* replacementNode, AZStd::unordered_map>& outSlotIdMap) const override; protected: diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ForEach.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ForEach.cpp index 0b7b6020e3..d730b6bcc9 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ForEach.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ForEach.cpp @@ -94,8 +94,6 @@ namespace ScriptCanvas void ForEach::OnInit() { - ResetLoop(); - if (!m_sourceSlot.IsValid()) { DynamicDataSlotConfiguration slotConfiguration; @@ -130,33 +128,6 @@ namespace ScriptCanvas EndpointNotificationBus::Handler::BusConnect({ GetEntityId(), m_sourceSlot }); } - void ForEach::OnInputSignal(const SlotId& slotId) - { - auto inSlotId = ForEachProperty::GetInSlotId(this); - if (slotId == inSlotId || slotId == SlotId{}) - { - if (slotId == inSlotId) - { - if (!InitializeLoop()) - { - // Loop initialization failed - SignalOutput(ForEachProperty::GetFinishedSlotId(this)); - return; - } - } - - if (!m_breakCalled) - { - Iterate(); - } - } - else if (slotId == ForEachProperty::GetBreakSlotId(this)) - { - m_breakCalled = true; - SignalOutput(ForEachProperty::GetFinishedSlotId(this)); - } - } - UpdateResult ForEach::OnUpdateNode() { if (auto continueSlot = GetSlotByNameAndType("Continue", CombinedSlotType::ExecutionIn)) @@ -167,161 +138,6 @@ namespace ScriptCanvas return UpdateResult::DirtyGraph; } - bool ForEach::InitializeLoop() - { - ResetLoop(); - - const Datum* input = FindDatum(m_sourceSlot); - - if (input && !input->Empty()) - { - if (!Data::IsContainerType(input->GetType())) - { - SCRIPTCANVAS_REPORT_ERROR((*this), "Iteration not supported on this type: %s", Data::GetName(m_sourceContainer.GetType()).c_str()); - return false; - } - - // Make a copy of the source datum - m_sourceContainer = *input; - - // Get the size of the container - auto sizeOutcome = BehaviorContextMethodHelper::CallMethodOnDatum(m_sourceContainer, "Size"); - - if (!sizeOutcome) - { - SCRIPTCANVAS_REPORT_ERROR((*this), "Failed to get size of container: %s", sizeOutcome.GetError().c_str()); - return false; - } - - Datum sizeResult = sizeOutcome.TakeValue(); - const size_t* sizePtr = sizeResult.GetAs(); - m_size = sizePtr ? *sizePtr : 0; - - if (Data::IsSetContainerType(m_sourceContainer.GetType()) || Data::IsMapContainerType(m_sourceContainer.GetType())) - { - // If it's a map or set, get the vector of keys - auto keysVectorOutcome = BehaviorContextMethodHelper::CallMethodOnDatum(m_sourceContainer, "GetKeys"); - - if (!keysVectorOutcome) - { - SCRIPTCANVAS_REPORT_ERROR((*this), "Failed to get vector of keys: %s", keysVectorOutcome.GetError().c_str()); - return false; - } - - m_keysVector = keysVectorOutcome.TakeValue(); - - // Check size of vector of keys for safety - auto keysSizeOutcome = BehaviorContextMethodHelper::CallMethodOnDatum(m_keysVector, "Size"); - - if (!keysSizeOutcome) - { - SCRIPTCANVAS_REPORT_ERROR((*this), "Failed to get size of vector of keys: %s", keysSizeOutcome.GetError().c_str()); - return false; - } - - Datum keysSizeResult = keysSizeOutcome.TakeValue(); - const size_t* keysSizePtr = keysSizeResult.GetAs(); - size_t keysSize = keysSizePtr ? *keysSizePtr : 0; - - if (m_size != keysSize) - { - // This shouldn't happen - SCRIPTCANVAS_REPORT_ERROR((*this), "Container size and vector of keys size mismatch."); - return false; - } - } - - return true; - } - - return false; - } - - void ForEach::Iterate() - { - if (m_sourceContainer.Empty() || m_index >= m_size) - { - SignalOutput(ForEachProperty::GetFinishedSlotId(this)); - return; - } - - Datum& container = Data::IsVectorContainerType(m_sourceContainer.GetType()) ? m_sourceContainer : m_keysVector; - - auto keyAtOutcome = BehaviorContextMethodHelper::CallMethodOnDatumUnpackOutcomeSuccess(container, "At", m_index); - - if (!keyAtOutcome) - { - SCRIPTCANVAS_REPORT_ERROR((*this), "Failed to get key in container: %s", keyAtOutcome.GetError().c_str()); - return; - } - - Datum keyAtResult = keyAtOutcome.TakeValue(); - - if (!SetPropertySlotData(keyAtResult, k_keySlotIndex)) - { - // Unable to set property slot - SCRIPTCANVAS_REPORT_ERROR((*this), "Unable to set one of the property slots on this node."); - SignalOutput(ForEachProperty::GetFinishedSlotId(this)); - return; - } - - if (Data::IsMapContainerType(m_sourceContainer.GetType())) - { - // If the container is a map, we want to get the value for the current key - auto valueAtOutcome = BehaviorContextMethodHelper::CallMethodOnDatumUnpackOutcomeSuccess(m_sourceContainer, "At", keyAtResult); - - if (!valueAtOutcome) - { - SCRIPTCANVAS_REPORT_ERROR((*this), "Failed to get value for key in container: %s", valueAtOutcome.GetError().c_str()); - return; - } - - Datum valueAtResult = valueAtOutcome.TakeValue(); - - if (!SetPropertySlotData(valueAtResult, k_valueSlotIndex)) - { - // Unable to set property slot - SCRIPTCANVAS_REPORT_ERROR((*this), "Unable to set one of the property slots on this node."); - SignalOutput(ForEachProperty::GetFinishedSlotId(this)); - return; - } - } - - ++m_index; - - SignalOutput(ForEachProperty::GetEachSlotId(this)); - } - - bool ForEach::SetPropertySlotData(Datum& atResult, size_t propertyIndex) - { - if (atResult.Empty()) - { - // Something went wrong with the Behavior Context call - SCRIPTCANVAS_REPORT_ERROR((*this), "Behavior Context call failed; unable to retrieve element from container."); - return false; - } - - if (m_propertySlots.size() <= propertyIndex) - { - // Missing a property slot - SCRIPTCANVAS_REPORT_ERROR((*this), "Node in invalid state; missing a property slot."); - return false; - } - - PushOutput(atResult, *GetSlot(m_propertySlots[propertyIndex].m_propertySlotId)); - return true; - } - - void ForEach::ResetLoop() - { - // Reset node state - m_index = 0; - m_size = 0; - m_breakCalled = false; - m_sourceContainer = Datum(); - m_keysVector = Datum(); - } - void ForEach::OnDynamicGroupDisplayTypeChanged(const AZ::Crc32& dynamicGroup, const Data::Type& dataType) { if (dynamicGroup == GetContainerGroupId() && dataType.IsValid()) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ForEach.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ForEach.h index 68e75adc80..32bca9eefd 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ForEach.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ForEach.h @@ -56,44 +56,29 @@ namespace ScriptCanvas bool IsBreakSlot(const SlotId&) const; - bool IsOutOfDate(const VersionData& graphVersion) const override; - - + bool IsOutOfDate(const VersionData& graphVersion) const override; UpdateResult OnUpdateNode() override; - protected: - ExecutionNameMap GetExecutionNameMap() const override; - - void OnInit() override; - void OnInputSignal(const SlotId&) override; - - bool InitializeLoop(); - void Iterate(); - bool SetPropertySlotData(Datum& atResult, size_t propertyIndex); - void ResetLoop(); - - void OnDynamicGroupDisplayTypeChanged(const AZ::Crc32& dynamicGroup, const Data::Type& dataType) override; - - void ClearPropertySlots(); - void AddPropertySlotsFromType(const Data::Type& dataType); - - static AZ::Crc32 GetContainerGroupId() { return AZ_CRC("ContainerGroup", 0xb81ed451); } - - SlotId m_sourceSlot; - AZ::TypeId m_previousTypeId; - AZStd::vector m_propertySlots; - + private: static const size_t k_keySlotIndex; static const size_t k_valueSlotIndex; - size_t m_index; - size_t m_size; + static AZ::Crc32 GetContainerGroupId() { return AZ_CRC("ContainerGroup", 0xb81ed451); } - bool m_breakCalled; + void AddPropertySlotsFromType(const Data::Type& dataType); - Datum m_sourceContainer; - Datum m_keysVector; + void ClearPropertySlots(); + + ExecutionNameMap GetExecutionNameMap() const override; + + void OnInit() override; + + void OnDynamicGroupDisplayTypeChanged(const AZ::Crc32& dynamicGroup, const Data::Type& dataType) override; + + SlotId m_sourceSlot; + AZ::TypeId m_previousTypeId; + AZStd::vector m_propertySlots; }; } } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionCallNode.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionCallNode.cpp index cec643d799..678ca60ef3 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionCallNode.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionCallNode.cpp @@ -410,6 +410,11 @@ namespace ScriptCanvas return m_asset.GetId(); } + const AZStd::string& FunctionCallNode::GetAssetHint() const + { + return m_asset.GetHint(); + } + AZ::Outcome FunctionCallNode::GetDependencies() const { DependencyReport report; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionCallNode.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionCallNode.h index fe5b453cf3..003bc2581b 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionCallNode.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionCallNode.h @@ -70,6 +70,8 @@ namespace ScriptCanvas AZ::Data::AssetId GetAssetId() const; + const AZStd::string& GetAssetHint() const; + const AZStd::string& GetName() const; void Initialize(AZ::Data::AssetId assetId, const ScriptCanvas::Grammar::FunctionSourceId& sourceId); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionDefinitionNode.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionDefinitionNode.cpp index ad556ae093..a849983deb 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionDefinitionNode.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionDefinitionNode.cpp @@ -19,6 +19,32 @@ #include +namespace FunctionDefinitionNodeCpp +{ + void VersionUpdateRemoveDefaultDisplayGroup(ScriptCanvas::Nodes::Core::FunctionDefinitionNode& node) + { + using namespace ScriptCanvas; + using namespace ScriptCanvas::Nodes::Core; + + AZ::SerializeContext* serializeContext{}; + AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext); + if (serializeContext) + { + const auto& classData = serializeContext->FindClassData(azrtti_typeid()); + if (classData && classData->m_version < FunctionDefinitionNode::NodeVersion::RemoveDefaultDisplayGroup) + { + for (auto& slot : node.ModAllSlots()) + { + if (slot->GetType() == CombinedSlotType::DataIn || slot->GetType() == CombinedSlotType::DataOut) + { + slot->ClearDynamicGroup(); + } + } + } + } + } +} + namespace ScriptCanvas { namespace Nodes @@ -113,6 +139,12 @@ namespace ScriptCanvas } } + void FunctionDefinitionNode::OnInit() + { + Nodeling::OnInit(); + FunctionDefinitionNodeCpp::VersionUpdateRemoveDefaultDisplayGroup(*this); + } + void FunctionDefinitionNode::SetupSlots() { auto groupedSlots = GetSlotsWithDisplayGroup(GetSlotDisplayGroup()); @@ -208,7 +240,6 @@ namespace ScriptCanvas slotConfiguration.SetConnectionType(connectionType); slotConfiguration.m_displayGroup = GetDataDisplayGroup(); - slotConfiguration.m_dynamicGroup = GetDataDynamicTypeGroup(); slotConfiguration.m_dynamicDataType = DynamicDataType::Any; slotConfiguration.m_isUserAdded = true; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionDefinitionNode.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionDefinitionNode.h index 20b20cb65d..04dc0c7103 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionDefinitionNode.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/FunctionDefinitionNode.h @@ -29,14 +29,13 @@ namespace ScriptCanvas class FunctionDefinitionNode : public Internal::Nodeling { - private: + public: enum NodeVersion { - Initial = 1 + Initial = 1, + RemoveDefaultDisplayGroup, }; - public: - SCRIPTCANVAS_NODE(FunctionDefinitionNode); FunctionDefinitionNode() = default; @@ -78,14 +77,15 @@ namespace ScriptCanvas static constexpr AZ::Crc32 GetAddNodelingInputDataSlot() { return AZ_CRC_CE("AddNodelingInputDataSlot"); } static constexpr AZ::Crc32 GetAddNodelingOutputDataSlot() { return AZ_CRC_CE("AddNodelingOutputDataSlot"); } - static constexpr AZ::Crc32 GetDataDynamicTypeGroup() { return AZ_CRC_CE("DataGroup"); } - + AZStd::string GetDataDisplayGroup() const { return "DataDisplayGroup"; } SlotId HandleExtension(AZ::Crc32 extensionId) override; void ConfigureVisualExtensions() override; + void OnInit() override; + void OnSetup() override; private: diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.cpp index b6f7bc2972..4a9e8ac3e3 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.cpp @@ -208,7 +208,6 @@ namespace ScriptCanvas } } - void Method::InitializeMethod(const MethodConfiguration& config) { m_namespaces = config.m_namespaces ? *config.m_namespaces : m_namespaces; @@ -239,7 +238,11 @@ namespace ScriptCanvas for (size_t argIndex(0), sentinel(config.m_method.GetNumArguments()); argIndex != sentinel; ++argIndex) { SlotId addedSlot = AddMethodInputSlot(config, argIndex); - MethodHelper::SetSlotToDefaultValue(*this, addedSlot, config, argIndex); + + if (addedSlot.IsValid()) + { + MethodHelper::SetSlotToDefaultValue(*this, addedSlot, config, argIndex); + } } } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.h index 6a53054ddf..829dff2c29 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.h @@ -132,6 +132,8 @@ namespace ScriptCanvas const Slot* GetIfBranchSlot(bool branch) const; + AZ_INLINE const AZStd::string& GetLookupName() const { return m_lookupName; } + AZ_INLINE AZStd::recursive_mutex& GetMutex() { return m_mutex; } ConstSlotsOutcome GetSlotsInExecutionThreadByTypeImpl(const Slot& executionSlot, CombinedSlotType targetSlotType, const Slot* executionChildSlot) const override; @@ -160,6 +162,8 @@ namespace ScriptCanvas bool SanityCheckBranchOnResultMethod(const AZ::BehaviorMethod& branchOnResultMethod) const; + AZ_INLINE void SetClassNamePretty(AZStd::string_view classNamePretty) { m_classNamePretty = classNamePretty; } + void SetMethodUnchecked(const AZ::BehaviorMethod* method, const AZ::BehaviorClass* behaviorClass); AZ_INLINE void SetWarnOnMissingFunction(bool enabled) { m_warnOnMissingFunction = enabled; } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/MethodOverloaded.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/MethodOverloaded.cpp index ed7fce7ffc..bfd0bb824d 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/MethodOverloaded.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/MethodOverloaded.cpp @@ -94,7 +94,7 @@ namespace ScriptCanvas { if (!m_updatingDisplay) { - RefreshActiveIndexes(); + RefreshActiveIndexes(true, true); UpdateSlotDisplay(); } } @@ -135,10 +135,8 @@ namespace ScriptCanvas return Data::Type::Invalid(); } - AZ::Outcome MethodOverloaded::GetFunctionCallName(const Slot* slot) const + AZ::Outcome MethodOverloaded::GetFunctionCallName([[maybe_unused]] const Slot* slot) const { - AZ_UNUSED(slot); - AZStd::string overloadName; int activeIndex = GetActiveIndex(); @@ -188,7 +186,7 @@ namespace ScriptCanvas // this prevents repeated updates based on changes to slots Method::InitializeMethod(config); - + SetClassNamePretty(""); RefreshActiveIndexes(); ConfigureContracts(); @@ -197,7 +195,12 @@ namespace ScriptCanvas SlotId MethodOverloaded::AddMethodInputSlot(const MethodConfiguration& config, size_t argumentIndex) { const AZ::BehaviorParameter* argumentPtr = config.m_method.GetArgument(argumentIndex); - AZ_Assert(argumentPtr, "Method: %s had a null argument at index: %d", config.m_lookupName->data(), argumentIndex); + + if (!argumentPtr) + { + return SlotId{}; + } + const auto& argument = *argumentPtr; auto nameAndToolTip = MethodHelper::GetArgumentNameAndToolTip(config, argumentIndex); @@ -507,7 +510,7 @@ namespace ScriptCanvas } } - void MethodOverloaded::RefreshActiveIndexes(bool checkForConnections) + void MethodOverloaded::RefreshActiveIndexes(bool checkForConnections, bool adjustSlots) { DataIndexMapping concreteInputTypes; DataIndexMapping concreteOutputTypes; @@ -519,6 +522,35 @@ namespace ScriptCanvas if (m_overloadSelection.m_availableIndexes.size() == 1) { auto methodOverload = m_overloadConfiguration.m_overloads[(*m_overloadSelection.m_availableIndexes.begin())]; + + if (adjustSlots) + { + const size_t numArguments = methodOverload.first->GetNumArguments(); + const size_t numInputSlots = m_orderedInputSlotIds.size(); + + if (numArguments > numInputSlots) + { + MethodConfiguration config(*methodOverload.first, GetMethodType()); + AZStd::string_view lookupName = GetLookupName(); + config.m_lookupName = &lookupName; + + for (size_t index = numInputSlots; index != numArguments; ++index) + { + AddMethodInputSlot(config, index); + } + } + else if (numArguments < numInputSlots) + { + const size_t removeCount = numInputSlots - numArguments; + // remove extra slots, assuming remaining ones are of valid type (if not valid name) + for (size_t count = 0; count != removeCount; ++count) + { + RemoveSlot(m_orderedInputSlotIds.back()); + m_orderedInputSlotIds.pop_back(); + } + } + } + SetMethodUnchecked(methodOverload.first, methodOverload.second); } } @@ -681,9 +713,6 @@ namespace ScriptCanvas return AZ::Success(); } - } - } - } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/MethodOverloaded.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/MethodOverloaded.h index 1fffbd7eac..517d3dd072 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/MethodOverloaded.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/MethodOverloaded.h @@ -106,7 +106,7 @@ namespace ScriptCanvas void SetupMethodData(const AZ::BehaviorMethod* lookupMethod, const AZ::BehaviorClass* lookupClass); void ConfigureContracts(); - void RefreshActiveIndexes(bool checkForConnections = true); + void RefreshActiveIndexes(bool checkForConnections = true, bool adjustSlots = false); void FindDataIndexMappings(DataIndexMapping& inputMapping, DataIndexMapping& outputMapping, bool checkForConnections) const; void UpdateSlotDisplay(); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Operators/Operator.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Operators/Operator.cpp index b8c1e9e400..6f8a23a2ed 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Operators/Operator.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Operators/Operator.cpp @@ -393,14 +393,6 @@ namespace ScriptCanvas AZ_UNUSED(sourceType); } - AZStd::unordered_map> OperatorBase::GetReplacementSlotsMap() const - { - AZStd::unordered_map> slotsMap; - slotsMap.emplace("In", AZStd::vector{ "In" }); - slotsMap.emplace("Out", AZStd::vector{ "Out" }); - return slotsMap; - } - void OperatorBase::CustomizeReplacementNode(Node* replacementNode, AZStd::unordered_map>& outSlotIdMap) const { auto newDataInSlots = replacementNode->GetSlotsByType(ScriptCanvas::CombinedSlotType::DataIn); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Operators/Operator.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Operators/Operator.h index bc49f3fac6..7091d7fa87 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Operators/Operator.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Operators/Operator.h @@ -57,7 +57,6 @@ namespace ScriptCanvas AZStd::vector< SourceSlotConfiguration > m_sourceSlotConfigurations; }; - AZStd::unordered_map> GetReplacementSlotsMap() const override; void CustomizeReplacementNode(Node* replacementNode, AZStd::unordered_map>& outSlotIdMap) const override; using TypeList = AZStd::vector; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Time/Timer.ScriptCanvasGrammar.xml b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Time/Timer.ScriptCanvasGrammar.xml index 21adecb8fe..e1ea8a4b73 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Time/Timer.ScriptCanvasGrammar.xml +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Time/Timer.ScriptCanvasGrammar.xml @@ -8,7 +8,7 @@ Base="ScriptCanvas::Node" Version="2" GeneratePropertyFriend="True" - DeprecationUUID="32A4BEDC-C207-4472-61DE-9A716402620A" + DeprecationUUID="{32A4BEDC-C207-4472-61DE-9A716402620A}" Deprecated="This node has been deprecated in favor of the nodeable form" Description="Provides a time value."> @@ -25,4 +25,4 @@ IsInput="False" IsOutput="True" /> - + \ No newline at end of file diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Results/ErrorText.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Results/ErrorText.h index 16ac7e1fa0..def4fa7761 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Results/ErrorText.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Results/ErrorText.h @@ -62,6 +62,8 @@ namespace ScriptCanvas constexpr const char* NoChildrenAfterRoot = "No children after parsing function root"; constexpr const char* NoChildrenInExtraction = "No children found in property extraction node"; constexpr const char* NoDataPresent = "Could not construct from graph, no graph data was present"; + constexpr const char* NodeableNodeOverloadAmbiguous = "NodeableNodeOverloaded doesn't have enough data connected to select a valid overload"; + constexpr const char* NodeableNodeDidNotConstructInternalNodeable = "NodeableNode did not construct its internal Nodeable"; constexpr const char* NoInputToForEach = "No Input To For Each Loop"; constexpr const char* NoOutForExecution = "No out slot for execution root"; constexpr const char* NoOutSlotInFunctionDefinitionStart = "No 'Out' slot in start of function definition"; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/VersioningUtils.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/VersioningUtils.cpp index 5bf5f83916..0dc16f721c 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/VersioningUtils.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/VersioningUtils.cpp @@ -12,9 +12,26 @@ #include "VersioningUtils.h" #include +#include namespace ScriptCanvas { + AZStd::vector GraphUpdateSlotReport::Convert(const Endpoint& oldEndpoint) const + { + auto iter = m_oldSlotsToNewSlots.find(oldEndpoint); + return iter != m_oldSlotsToNewSlots.end() ? iter->second : AZStd::vector{ oldEndpoint }; + } + + bool GraphUpdateSlotReport::IsEmpty() const + { + return m_deletedOldSlots.empty() && m_oldSlotsToNewSlots.empty(); + } + + bool NodeUpdateSlotReport::IsEmpty() const + { + return m_deletedOldSlots.empty() && m_oldSlotsToNewSlots.empty(); + } + void VersioningUtils::CopyOldValueToDataSlot(Slot* newSlot, const VariableId& oldVariableReference, const Datum* oldDatum) { if (oldVariableReference.IsValid()) @@ -36,6 +53,99 @@ namespace ScriptCanvas } } + void MergeUpdateSlotReport(const AZ::EntityId& scriptCanvasNodeId, GraphUpdateSlotReport& report, const NodeUpdateSlotReport& source) + { + report.m_deletedOldSlots.reserve(source.m_deletedOldSlots.size()); + + for (auto& slotId : source.m_deletedOldSlots) + { + report.m_deletedOldSlots.insert({ scriptCanvasNodeId, slotId }); + } + + report.m_oldSlotsToNewSlots.reserve(source.m_oldSlotsToNewSlots.size()); + + for (auto& oldToNewIter : source.m_oldSlotsToNewSlots) + { + AZStd::vector newEndpoints; + newEndpoints.reserve(oldToNewIter.second.size()); + + for (auto& targetSlotId : oldToNewIter.second) + { + newEndpoints.push_back({ scriptCanvasNodeId, targetSlotId }); + } + + report.m_oldSlotsToNewSlots[{ scriptCanvasNodeId, oldToNewIter.first}] = AZStd::move(newEndpoints); + } + } + + AZStd::vector> CollectEndpoints(const AZStd::vector& connections, bool logEntityNames) + { + AZStd::vector names; + AZStd::vector> endpoints; + + for (auto& connectionEntity : connections) + { + if (logEntityNames) + { + names.push_back(connectionEntity->GetName()); + } + + if (auto connection = AZ::EntityUtils::FindFirstDerivedComponent(connectionEntity->GetId())) + { + endpoints.push_back(AZStd::make_pair(connection->GetSourceEndpoint(), connection->GetTargetEndpoint())); + } + } + + if (logEntityNames) + { + AZStd::sort(names.begin(), names.end()); + + AZStd::string result = "\nConnection Name list:\n"; + for (auto& name : names) + { + result += "\n"; + result += name; + } + + AZ_TracePrintf("ScriptCanvas", result.c_str()); + } + + return endpoints; + } + + void UpdateConnectionStatus(Graph& graph, const GraphUpdateSlotReport& report) + { + GraphData* graphData = graph.GetGraphData(); + if (!graphData) + { + AZ_Error("ScriptCanvas", false, "Graph was missing graph data to update"); + return; + } + + AZStd::unordered_set oldConnectedSlots; + AZ_TracePrintf("ScriptCanvas", "Connections list before: "); + auto endpoints = CollectEndpoints(graphData->m_connections, true); + graph.RemoveAllConnections(); + + for (auto& iter : endpoints) + { + const AZStd::vector& sources = report.Convert(iter.first); + const AZStd::vector& targets = report.Convert(iter.second); + + for (const auto& source : sources) + { + for (const auto& target : targets) + { + graph.ConnectByEndpoint(source, target); + } + } + } + + graphData->BuildEndpointMap(); + AZ_TracePrintf("ScriptCanvas", "Connections list after: "); + CollectEndpoints(graphData->m_connections, true); + } + void VersioningUtils::CreateRemapConnectionsForSourceEndpoint(const Graph& graph, const Endpoint& oldSourceEndpoint, const Endpoint& newSourceEndpoint, ReplacementConnectionMap& connectionMap) { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/VersioningUtils.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/VersioningUtils.h index 51960e08e7..a9a40305c3 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/VersioningUtils.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Utils/VersioningUtils.h @@ -15,6 +15,8 @@ #include #include +#include +#include #include namespace AZ @@ -25,13 +27,36 @@ namespace AZ namespace ScriptCanvas { class Datum; - class Endpoint; class Graph; class Slot; - using ReplacementEndpointPairs = AZStd::unordered_set>; + using ReplacementEndpointPairs = AZStd::unordered_set>; using ReplacementConnectionMap = AZStd::unordered_map; + struct NodeUpdateSlotReport + { + AZStd::unordered_set m_deletedOldSlots; + AZStd::unordered_map> m_oldSlotsToNewSlots; + + bool IsEmpty() const; + }; + + struct GraphUpdateSlotReport + { + AZStd::unordered_set m_deletedOldSlots; + AZStd::unordered_map> m_oldSlotsToNewSlots; + + AZStd::vector Convert(const Endpoint& oldEndpoint) const; + + bool IsEmpty() const; + }; + + void MergeUpdateSlotReport(const AZ::EntityId& scriptCanvasNodeId, GraphUpdateSlotReport& report, const NodeUpdateSlotReport& source); + + AZStd::vector> CollectEndpoints(const AZStd::vector& connections, bool logEntityNames = false); + + void UpdateConnectionStatus(Graph& graph, const GraphUpdateSlotReport& report); + class VersioningUtils { public: diff --git a/Gems/StartingPointInput/Code/Source/InputNode.ScriptCanvasGrammar.xml b/Gems/StartingPointInput/Code/Source/InputNode.ScriptCanvasGrammar.xml index 9d6c555c97..8c8cc34597 100644 --- a/Gems/StartingPointInput/Code/Source/InputNode.ScriptCanvasGrammar.xml +++ b/Gems/StartingPointInput/Code/Source/InputNode.ScriptCanvasGrammar.xml @@ -6,8 +6,10 @@ PreferredClassName="Input Handler" Uuid="{0B0AC61B-4BBA-42BF-BDCD-DAF2D3CA41A8}" Base="ScriptCanvas::Node" - Icon="Icons/ScriptCanvas/Bus.png" + Icon="Editor/Icons/ScriptCanvas/Bus.png" EditAttributes="AZ::Edit::Attributes::Category@Gameplay/Input" + DeprecationUUID="{0A2EB488-5A6A-E166-BB62-23FF81499E33}" + Deprecated="This node has been deprecated in favor of the nodeable form" GraphEntryPoint="True" GeneratePropertyFriend="True" Description="Handle processed input events found in input binding assets"> @@ -25,4 +27,4 @@ IsInput="False" IsOutput="True" /> - + \ No newline at end of file