// Copyright Epic Games, Inc. All Rights Reserved. #include "RigVMModel/RigVMGraph.h" #include "RigVMModel/RigVMFunctionLibrary.h" #include "RigVMModel/RigVMController.h" #include "RigVMModel/Nodes/RigVMLibraryNode.h" #include "RigVMModel/Nodes/RigVMFunctionEntryNode.h" #include "RigVMModel/Nodes/RigVMFunctionReturnNode.h" #include "UObject/Package.h" URigVMGraph::URigVMGraph() : DiagnosticsAST(nullptr) , RuntimeAST(nullptr) { } const TArray& URigVMGraph::GetNodes() const { return Nodes; } const TArray& URigVMGraph::GetLinks() const { return Links; } TArray URigVMGraph::GetContainedGraphs(bool bRecursive) const { TArray Graphs; for (URigVMNode* Node : GetNodes()) { if (URigVMCollapseNode* CollapseNode = Cast(Node)) { Graphs.Add(CollapseNode->GetContainedGraph()); if (bRecursive) { Graphs.Append(CollapseNode->GetContainedGraph()->GetContainedGraphs(true)); } } } return Graphs; } URigVMFunctionEntryNode* URigVMGraph::GetEntryNode() const { for (URigVMNode* Node : Nodes) { if (URigVMFunctionEntryNode* EntryNode = Cast(Node)) { return EntryNode; } } return nullptr; } URigVMFunctionReturnNode* URigVMGraph::GetReturnNode() const { for (URigVMNode* Node : Nodes) { if (URigVMFunctionReturnNode* ReturnNode = Cast(Node)) { return ReturnNode; } } return nullptr; } TArray URigVMGraph::GetVariableDescriptions() const { TArray Variables; for (URigVMNode* Node : Nodes) { if (URigVMVariableNode* VariableNode = Cast(Node)) { Variables.AddUnique(VariableNode->GetVariableDescription()); } } return Variables; } TArray URigVMGraph::GetParameterDescriptions() const { TArray Parameters; for (URigVMNode* Node : Nodes) { if (URigVMParameterNode* ParameterNode = Cast(Node)) { Parameters.AddUnique(ParameterNode->GetParameterDescription()); } } return Parameters; } FString URigVMGraph::GetNodePath() const { if (URigVMCollapseNode* CollapseNode = Cast(GetOuter())) { return CollapseNode->GetNodePath(true /* recursive */); } return FString(); } FString URigVMGraph::GetGraphName() const { if (URigVMCollapseNode* CollapseNode = Cast(GetOuter())) { return CollapseNode->GetNodePath(false /* recursive */); } return FString(); } URigVMNode* URigVMGraph::FindNodeByName(const FName& InNodeName) const { for (URigVMNode* Node : Nodes) { if (Node == nullptr) { continue; } if (Node->GetFName() == InNodeName) { return Node; } } return nullptr; } URigVMNode* URigVMGraph::FindNode(const FString& InNodePath) const { if (InNodePath.IsEmpty()) { return nullptr; } FString Left = InNodePath, Right; URigVMNode::SplitNodePathAtStart(InNodePath, Left, Right); if (Right.IsEmpty()) { return FindNodeByName(*Left); } if (URigVMLibraryNode* LibraryNode = Cast< URigVMLibraryNode>(FindNodeByName(*Left))) { return LibraryNode->GetContainedGraph()->FindNode(Right); } return nullptr; } URigVMPin* URigVMGraph::FindPin(const FString& InPinPath) const { FString Left, Right; if (!URigVMPin::SplitPinPathAtStart(InPinPath, Left, Right)) { Left = InPinPath; } URigVMNode* Node = FindNode(Left); if (Node) { return Node->FindPin(Right); } return nullptr; } URigVMLink* URigVMGraph::FindLink(const FString& InLinkPinPathRepresentation) const { for(URigVMLink* Link : Links) { if(Link->GetPinPathRepresentation() == InLinkPinPathRepresentation) { return Link; } } return nullptr; } bool URigVMGraph::IsNodeSelected(const FName& InNodeName) const { return SelectedNodes.Contains(InNodeName); } const TArray& URigVMGraph::GetSelectNodes() const { return SelectedNodes; } bool URigVMGraph::IsTopLevelGraph() const { if (GetOuter()->IsA()) { return false; } return true; } URigVMFunctionLibrary* URigVMGraph::GetDefaultFunctionLibrary() const { if (DefaultFunctionLibraryPtr.IsValid()) { return CastChecked(DefaultFunctionLibraryPtr.Get()); } if (URigVMLibraryNode* OuterLibraryNode = Cast(GetOuter())) { if (URigVMGraph* OuterGraph = OuterLibraryNode->GetGraph()) { return OuterGraph->GetDefaultFunctionLibrary(); } } return nullptr; } void URigVMGraph::SetDefaultFunctionLibrary(URigVMFunctionLibrary* InFunctionLibrary) { DefaultFunctionLibraryPtr = InFunctionLibrary; } FRigVMGraphModifiedEvent& URigVMGraph::OnModified() { return ModifiedEvent; } void URigVMGraph::Notify(ERigVMGraphNotifType InNotifType, UObject* InSubject) { ModifiedEvent.Broadcast(InNotifType, this, InSubject); } TSharedPtr URigVMGraph::GetDiagnosticsAST(bool bForceRefresh, TArray InLinksToSkip) { // only refresh the diagnostics AST if have a different set of links to skip if (!bForceRefresh && DiagnosticsAST.IsValid()) { const TArray PreviousLinksToSkip = DiagnosticsAST->GetSettings().LinksToSkip; if (PreviousLinksToSkip.Num() < InLinksToSkip.Num()) { bForceRefresh = true; } else { for (int32 LinkIndex = 0; LinkIndex < InLinksToSkip.Num(); LinkIndex++) { if (PreviousLinksToSkip[LinkIndex] != InLinksToSkip[LinkIndex]) { bForceRefresh = true; break; } } } } if (DiagnosticsAST == nullptr || bForceRefresh) { FRigVMParserASTSettings Settings = FRigVMParserASTSettings::Fast(); Settings.LinksToSkip = InLinksToSkip; DiagnosticsAST = MakeShareable(new FRigVMParserAST(this, nullptr, Settings)); } return DiagnosticsAST; } TSharedPtr URigVMGraph::GetRuntimeAST(const FRigVMParserASTSettings& InSettings, bool bForceRefresh) { if (RuntimeAST == nullptr || bForceRefresh) { RuntimeAST = MakeShareable(new FRigVMParserAST(this, nullptr, InSettings)); } return RuntimeAST; } void URigVMGraph::ClearAST(bool bClearDiagnostics, bool bClearRuntime) { if (bClearDiagnostics) { DiagnosticsAST.Reset(); } if (bClearRuntime) { RuntimeAST.Reset(); } } bool URigVMGraph::IsNameAvailable(const FString& InName) { for (URigVMNode* Node : Nodes) { if (Node->GetName() == InName) { return false; } } return true; } void URigVMGraph::PrepareCycleChecking(URigVMPin* InPin, bool bAsInput) { TArray LinksToSkip; if (InPin) { LinksToSkip = InPin->GetLinks(); } GetDiagnosticsAST(false, LinksToSkip)->PrepareCycleChecking(InPin); } bool URigVMGraph::CanLink(URigVMPin* InSourcePin, URigVMPin* InTargetPin, FString* OutFailureReason, const FRigVMByteCode* InByteCode) { if (!URigVMPin::CanLink(InSourcePin, InTargetPin, OutFailureReason, InByteCode)) { return false; } return GetDiagnosticsAST()->CanLink(InSourcePin, InTargetPin, OutFailureReason); }