UEdGraphNode* FGraphCompilerContext::FindNodeByClass(const UEdGraph* Graph, TSubclassOf<UEdGraphNode> NodeClass, bool bExpectedUnique) const { UEdGraphNode* FirstResultNode = NULL; for (int32 NodeIndex = 0; NodeIndex < Graph->Nodes.Num(); ++NodeIndex) { UEdGraphNode* Node = Graph->Nodes[NodeIndex]; if (Node->IsA(NodeClass)) { if (bExpectedUnique) { if (FirstResultNode == NULL) { FirstResultNode = Node; } else { MessageLog.Error(*FString::Printf(TEXT("Expected only one %s node in graph @@, but found both @@ and @@"), *(NodeClass->GetName())), Graph, FirstResultNode, Node); } } else { return Node; } } } return FirstResultNode; }
void FGraphCompilerContext::FindNodesByClass(const UEdGraph* Graph, TSubclassOf<UEdGraphNode> NodeClass, TArray<UEdGraphNode*>& FoundNodes) const { for (int32 NodeIndex = 0; NodeIndex < Graph->Nodes.Num(); ++NodeIndex) { UEdGraphNode* Node = Graph->Nodes[NodeIndex]; if (Node && Node->IsA(NodeClass)) { FoundNodes.Add(Node); } } }
void TraversePin(UEdGraphPin* Pin) { if (UK2Node_Knot* Knot = Cast<UK2Node_Knot>(Pin->GetOwningNodeUnchecked())) { TraverseNodes(Knot); } else { VisitedPins.Add(Pin); for (UEdGraphPin* OtherPin : Pin->LinkedTo) { UEdGraphNode* OtherNode = OtherPin->GetOwningNodeUnchecked(); if (OtherNode && OtherNode->IsA(UK2Node_Knot::StaticClass())) { TraverseNodes(OtherNode); } } } }
void UBehaviorTreeGraph::UpdatePinConnectionTypes() { for (int32 Index = 0; Index < Nodes.Num(); ++Index) { UEdGraphNode* Node = Nodes[Index]; const bool bIsCompositeNode = Node && Node->IsA(UBehaviorTreeGraphNode_Composite::StaticClass()); for (int32 iPin = 0; iPin < Node->Pins.Num(); iPin++) { FString& PinCategory = Node->Pins[iPin]->PinType.PinCategory; if (PinCategory == TEXT("Transition")) { PinCategory = bIsCompositeNode ? UBehaviorTreeEditorTypes::PinCategory_MultipleNodes : UBehaviorTreeEditorTypes::PinCategory_SingleComposite; } } } }
void TraverseNodes(UEdGraphNode* Node) { if (VisitedNodes.Contains(Node)) { return; } VisitedNodes.Add(Node); for (UEdGraphPin* MyPin : Node->Pins) { VisitedPins.Add(MyPin); for (UEdGraphPin* OtherPin : MyPin->LinkedTo) { UEdGraphNode* OtherNode = OtherPin->GetOwningNodeUnchecked(); if (OtherNode && OtherNode->IsA(UK2Node_Knot::StaticClass())) { TraverseNodes(OtherNode); } } } }
void GraphNodeInformationDatabase::FillDatabase() { FBlueprintActionDatabase::FActionRegistry const& actionDatabase = FBlueprintActionDatabase::Get().GetAllActions(); for (auto const& actionEntry : actionDatabase) { for (UBlueprintNodeSpawner const* nodeSpawner : actionEntry.Value) { UEdGraphNode* nodeTemplate = nodeSpawner->GetTemplateNode(); if (nodeTemplate != nullptr && nodeTemplate->IsA(UK2Node::StaticClass())) { UK2Node* ukNode = Cast<UK2Node>(nodeTemplate); FBlueprintNodeSignature signature = ukNode->GetSignature(); FGuid nodeSignatureGuid = signature.AsGuid(); GraphNodeInformation nodeInfo(*ukNode); m_GraphNodeInformation.Add(nodeSignatureGuid, nodeInfo); } } } m_HasBuiltDatabase = true; }
void FKismetVariableDragDropAction::HoverTargetChanged() { UProperty* VariableProperty = GetVariableProperty(); if (VariableProperty == nullptr) { return; } FString VariableString = VariableName.ToString(); // Icon/text to draw on tooltip FSlateColor IconColor = FLinearColor::White; const FSlateBrush* StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); FText Message = LOCTEXT("InvalidDropTarget", "Invalid drop target!"); UEdGraphPin* PinUnderCursor = GetHoveredPin(); bool bCanMakeSetter = true; bool bBadSchema = false; bool bBadGraph = false; UEdGraph* HoveredGraph = GetHoveredGraph(); if (HoveredGraph) { if (Cast<const UEdGraphSchema_K2>(HoveredGraph->GetSchema()) == NULL) { bBadSchema = true; } else if(!CanVariableBeDropped(VariableProperty, *HoveredGraph)) { bBadGraph = true; } UStruct* Outer = CastChecked<UStruct>(VariableProperty->GetOuter()); FNodeConstructionParams NewNodeParams; NewNodeParams.VariableName = VariableName; const UBlueprint* DropOnBlueprint = FBlueprintEditorUtils::FindBlueprintForGraph(HoveredGraph); NewNodeParams.Graph = HoveredGraph; NewNodeParams.VariableSource = Outer; bCanMakeSetter = CanExecuteMakeSetter(NewNodeParams, VariableProperty); } UEdGraphNode* VarNodeUnderCursor = Cast<UK2Node_Variable>(GetHoveredNode()); if (bBadSchema) { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = LOCTEXT("CannotCreateInThisSchema", "Cannot access variables in this type of graph"); } else if(bBadGraph) { FFormatNamedArguments Args; Args.Add(TEXT("VariableName"), FText::FromString(VariableString)); Args.Add(TEXT("Scope"), FText::FromString(HoveredGraph->GetName())); StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); if(IsFromBlueprint(FBlueprintEditorUtils::FindBlueprintForGraph(HoveredGraph)) && VariableProperty->GetOuter()->IsA(UFunction::StaticClass())) { Message = FText::Format( LOCTEXT("IncorrectGraphForLocalVariable_Error", "Cannot place local variable '{VariableName}' in external scope '{Scope}'"), Args); } else { Message = FText::Format( LOCTEXT("IncorrectGraphForVariable_Error", "Cannot place variable '{VariableName}' in external scope '{Scope}'"), Args); } } else if (PinUnderCursor != NULL) { FFormatNamedArguments Args; Args.Add(TEXT("PinUnderCursor"), FText::FromString(PinUnderCursor->PinName)); Args.Add(TEXT("VariableName"), FText::FromString(VariableString)); if(CanVariableBeDropped(VariableProperty, *PinUnderCursor->GetOwningNode()->GetGraph())) { const UEdGraphSchema_K2* Schema = CastChecked<const UEdGraphSchema_K2>(PinUnderCursor->GetSchema()); const bool bIsRead = PinUnderCursor->Direction == EGPD_Input; const UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForNode(PinUnderCursor->GetOwningNode()); const bool bReadOnlyProperty = FBlueprintEditorUtils::IsPropertyReadOnlyInCurrentBlueprint(Blueprint, VariableProperty); const bool bCanWriteIfNeeded = bIsRead || !bReadOnlyProperty; FEdGraphPinType VariablePinType; Schema->ConvertPropertyToPinType(VariableProperty, VariablePinType); const bool bTypeMatch = Schema->ArePinTypesCompatible(VariablePinType, PinUnderCursor->PinType); Args.Add(TEXT("PinUnderCursor"), FText::FromString(PinUnderCursor->PinName)); if (bTypeMatch && bCanWriteIfNeeded) { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK")); if (bIsRead) { Message = FText::Format(LOCTEXT("MakeThisEqualThat_PinEqualVariableName", "Make {PinUnderCursor} = {VariableName}"), Args); } else { Message = FText::Format(LOCTEXT("MakeThisEqualThat_VariableNameEqualPin", "Make {VariableName} = {PinUnderCursor}"), Args); } } else { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); if (!bCanWriteIfNeeded) { Message = FText::Format(LOCTEXT("ReadOnlyVar_Error", "Cannot write to read-only variable '{VariableName}'"), Args); } else { Message = FText::Format(LOCTEXT("NotCompatible_Error", "The type of '{VariableName}' is not compatible with {PinUnderCursor}"), Args); } } } else { Args.Add(TEXT("Scope"), FText::FromString(PinUnderCursor->GetOwningNode()->GetGraph()->GetName())); StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = FText::Format( LOCTEXT("IncorrectGraphForPin_Error", "Cannot place local variable '{VariableName}' in external scope '{Scope}'"), Args); } } else if (VarNodeUnderCursor != NULL) { FFormatNamedArguments Args; Args.Add(TEXT("VariableName"), FText::FromString(VariableString)); if(CanVariableBeDropped(VariableProperty, *VarNodeUnderCursor->GetGraph())) { const bool bIsRead = VarNodeUnderCursor->IsA(UK2Node_VariableGet::StaticClass()); const UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForNode(VarNodeUnderCursor); const bool bReadOnlyProperty = FBlueprintEditorUtils::IsPropertyReadOnlyInCurrentBlueprint(Blueprint, VariableProperty); const bool bCanWriteIfNeeded = bIsRead || !bReadOnlyProperty; if (bCanWriteIfNeeded) { Args.Add(TEXT("ReadOrWrite"), bIsRead ? LOCTEXT("Read", "read") : LOCTEXT("Write", "write")); if(WillBreakLinks(VarNodeUnderCursor, VariableProperty)) { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OKWarn")); Message = FText::Format( LOCTEXT("ChangeNodeToWarnBreakLinks", "Change node to {ReadOrWrite} '{VariableName}', WARNING this will break links!"), Args); } else { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK")); Message = FText::Format( LOCTEXT("ChangeNodeTo", "Change node to {ReadOrWrite} '{VariableName}'"), Args); } } else { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = FText::Format( LOCTEXT("ReadOnlyVar_Error", "Cannot write to read-only variable '{VariableName}'"), Args); } } else { Args.Add(TEXT("Scope"), FText::FromString(VarNodeUnderCursor->GetGraph()->GetName())); StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = FText::Format( LOCTEXT("IncorrectGraphForNodeReplace_Error", "Cannot replace node with local variable '{VariableName}' in external scope '{Scope}'"), Args); } } else if (!HoveredCategoryName.IsEmpty()) { // Find Blueprint that made this class and get category of variable FText Category; UBlueprint* Blueprint; // Find the Blueprint for this property if(Cast<UFunction>(VariableSource.Get())) { Blueprint = UBlueprint::GetBlueprintFromClass(Cast<UClass>(VariableSource->GetOuter())); } else { Blueprint = UBlueprint::GetBlueprintFromClass(Cast<UClass>(VariableSource.Get())); } if(Blueprint != NULL) { Category = FBlueprintEditorUtils::GetBlueprintVariableCategory(Blueprint, VariableProperty->GetFName(), GetLocalVariableScope() ); } // See if class is native UClass* OuterClass = Cast<UClass>(VariableProperty->GetOuter()); if(OuterClass || Cast<UFunction>(VariableProperty->GetOuter())) { const bool bIsNativeVar = (OuterClass && OuterClass->ClassGeneratedBy == NULL); FFormatNamedArguments Args; Args.Add(TEXT("VariableName"), FText::FromString(VariableString)); Args.Add(TEXT("HoveredCategoryName"), HoveredCategoryName); if (bIsNativeVar) { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = FText::Format( LOCTEXT("ChangingCatagoryNotThisVar", "Cannot change category for variable '{VariableName}'"), Args ); } else if (Category.EqualTo(HoveredCategoryName)) { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = FText::Format( LOCTEXT("ChangingCatagoryAlreadyIn", "Variable '{VariableName}' is already in category '{HoveredCategoryName}'"), Args ); } else { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK")); Message = FText::Format( LOCTEXT("ChangingCatagoryOk", "Move variable '{VariableName}' to category '{HoveredCategoryName}'"), Args ); } } } else if (HoveredAction.IsValid()) { if(HoveredAction.Pin()->GetTypeId() == FEdGraphSchemaAction_K2Var::StaticGetTypeId()) { FEdGraphSchemaAction_K2Var* VarAction = (FEdGraphSchemaAction_K2Var*)HoveredAction.Pin().Get(); FName TargetVarName = VarAction->GetVariableName(); // Needs to have a valid index to move it (this excludes variables added through other means, like timelines/components int32 MoveVarIndex = INDEX_NONE; int32 TargetVarIndex = INDEX_NONE; UBlueprint* Blueprint = UBlueprint::GetBlueprintFromClass(Cast<UClass>(VariableSource.Get())); if(Blueprint != NULL) { MoveVarIndex = FBlueprintEditorUtils::FindNewVariableIndex(Blueprint, VariableName); TargetVarIndex = FBlueprintEditorUtils::FindNewVariableIndex(Blueprint, TargetVarName); } FFormatNamedArguments Args; Args.Add(TEXT("VariableName"), FText::FromString(VariableString)); Args.Add(TEXT("TargetVarName"), FText::FromName(TargetVarName)); if(MoveVarIndex == INDEX_NONE) { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = FText::Format( LOCTEXT("MoveVarDiffClass", "Cannot reorder variable '{VariableName}'."), Args ); } else if(TargetVarIndex == INDEX_NONE) { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = FText::Format( LOCTEXT("MoveVarOther", "Cannot reorder variable '{VariableName}' before '{TargetVarName}'."), Args ); } else if(VariableName == TargetVarName) { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = FText::Format( LOCTEXT("MoveVarYourself", "Cannot reorder variable '{VariableName}' before itself."), Args ); } else { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK")); Message = FText::Format( LOCTEXT("MoveVarOK", "Reorder variable '{VariableName}' before '{TargetVarName}'"), Args ); } } } else if (bAltDrag && !bCanMakeSetter) { FFormatNamedArguments Args; Args.Add(TEXT("VariableName"), FText::FromString(VariableString)); StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = FText::Format(LOCTEXT("CannotPlaceSetter", "Variable '{VariableName}' is readonly, you cannot set this variable."), Args); } // Draw variable icon else { StatusSymbol = FBlueprintEditor::GetVarIconAndColor(VariableSource.Get(), VariableName, IconColor); Message = FText::FromString(VariableString); } SetSimpleFeedbackMessage(StatusSymbol, IconColor, Message); }
/** Evaluates the graph connected to a pin. */ static int32 EvaluateGraph(FNiagaraCompilerContext& Context, UEdGraphPin* Pin) { int32 ExpressionIndex = INDEX_NONE; if (Pin) { if (Pin->LinkedTo.Num() == 1) { check(Pin->Direction == EGPD_Input); Pin = Pin->LinkedTo[0]; check(Pin->Direction == EGPD_Output); int32* CachedExpressionIndex = Context.PinToExpression.Find(Pin); if (CachedExpressionIndex) { ExpressionIndex = *CachedExpressionIndex; } else { UEdGraphNode* Node = Pin->GetOwningNode(); if (Node->IsA(UNiagaraNodeOp::StaticClass())) { UNiagaraNodeOp* OpNode = (UNiagaraNodeOp*)Node; VectorVM::FVectorVMOpInfo const& OpInfo = VectorVM::GetOpCodeInfo(OpNode->OpIndex); FNiagaraExpr NewOp; NewOp.OpIndex = OpNode->OpIndex; NewOp.SrcOperandTypeVector = 0; for (int32 SrcIndex = 0; SrcIndex < 3; ++SrcIndex) { if (OpInfo.SrcTypes[SrcIndex] != VectorVM::EOpSrc::Invalid) { UEdGraphPin* SrcPin = OpNode->FindPinChecked(UNiagaraNodeOp::InPinNames[SrcIndex]); NewOp.Src[SrcIndex] = EvaluateGraph(Context,SrcPin); if (NewOp.Src[SrcIndex] & 0x40000000) { NewOp.SrcOperandTypeVector |= (1 << SrcIndex); } } } ExpressionIndex = Context.Expressions.Add(NewOp); } else if (Node->IsA(UNiagaraNodeGetAttr::StaticClass())) { UNiagaraNodeGetAttr* AttrNode = (UNiagaraNodeGetAttr*)Node; int32 AttrIndex = INDEX_NONE; if (Context.Attributes.Find(AttrNode->AttrName, AttrIndex)) { ExpressionIndex = AttrIndex | 0x80000000; } else if (Context.ConstantNames.Find(AttrNode->AttrName, AttrIndex)) { ExpressionIndex = AttrIndex | 0x40000000; } } Context.PinToExpression.Add(Pin, ExpressionIndex); } } else if (!Pin->bDefaultValueIsIgnored) { FString ConstString = Pin->GetDefaultAsString(); FName ConstName(*ConstString); int32 ConstIndex = Context.ConstantNames.Find(ConstName); if (ConstIndex == INDEX_NONE) { TArray<FString> ResultString; ConstString.Trim(); ConstString.TrimTrailing(); ConstString.ParseIntoArray(&ResultString, TEXT(","), true); ConstIndex = 0; if (ResultString.Num() == 4) { ConstIndex = Context.Constants.Add(FVector4(FCString::Atof(*ResultString[0]), FCString::Atof(*ResultString[1]), FCString::Atof(*ResultString[2]), FCString::Atof(*ResultString[3]))); check(Context.ConstantNames.Num() == ConstIndex); Context.ConstantNames.Add(ConstName); } } check(Context.Constants.IsValidIndex(ConstIndex)); ExpressionIndex = ConstIndex | 0x40000000; } } return ExpressionIndex; }