// Copyright Epic Games, Inc. All Rights Reserved. #include "ConversationGraphNode_Knot.h" #include "ConversationGraphNode.h" #include "ConversationNode.h" #include "SGraphNodeKnot.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(ConversationGraphNode_Knot) #define LOCTEXT_NAMESPACE "ConversationGraph" static const char* PC_Wildcard = "wildcard"; ///////////////////////////////////////////////////// // UConversationGraphNode_Knot UConversationGraphNode_Knot::UConversationGraphNode_Knot(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { bCanRenameNode = true; } void UConversationGraphNode_Knot::AllocateDefaultPins() { const FName InputPinName(TEXT("InputPin")); const FName OutputPinName(TEXT("OutputPin")); UEdGraphPin* MyInputPin = CreatePin(EGPD_Input, PC_Wildcard, InputPinName); MyInputPin->bDefaultValueIsIgnored = true; UEdGraphPin* MyOutputPin = CreatePin(EGPD_Output, PC_Wildcard, OutputPinName); } FText UConversationGraphNode_Knot::GetTooltipText() const { //@TODO: Should pull the tooltip from the source pin return LOCTEXT("KnotTooltip", "Reroute Node (reroutes wires)"); } FText UConversationGraphNode_Knot::GetNodeTitle(ENodeTitleType::Type TitleType) const { if (TitleType == ENodeTitleType::EditableTitle) { return FText::FromString(NodeComment); } else if (TitleType == ENodeTitleType::MenuTitle) { return LOCTEXT("KnotListTitle", "Add Reroute Node..."); } else { return LOCTEXT("KnotTitle", "Reroute Node"); } } bool UConversationGraphNode_Knot::ShouldOverridePinNames() const { return true; } FText UConversationGraphNode_Knot::GetPinNameOverride(const UEdGraphPin& Pin) const { // Keep the pin size tiny return FText::GetEmpty(); } void UConversationGraphNode_Knot::OnRenameNode(const FString& NewName) { NodeComment = NewName; } bool UConversationGraphNode_Knot::CanSplitPin(const UEdGraphPin* Pin) const { return false; } TSharedPtr UConversationGraphNode_Knot::MakeNameValidator() const { // Comments can be duplicated, etc... return MakeShareable(new FDummyNameValidator(EValidatorResult::Ok)); } UEdGraphPin* UConversationGraphNode_Knot::GetPassThroughPin(const UEdGraphPin* FromPin) const { if(FromPin && Pins.Contains(FromPin)) { return FromPin == Pins[0] ? Pins[1] : Pins[0]; } return nullptr; } TSharedPtr UConversationGraphNode_Knot::CreateVisualWidget() { return SNew(SGraphNodeKnot, this); } void UConversationGraphNode_Knot::GatherAllInBoundGraphNodes(TArray& OutGraphNodes) const { TArray VisitedKnots; GatherAllInBoundGraphNodes_Internal(OutGraphNodes, VisitedKnots); } void UConversationGraphNode_Knot::GatherAllOutBoundGraphNodes(TArray& OutGraphNodes) const { TArray VisitedKnots; GatherAllOutBoundGraphNodes_Internal(OutGraphNodes, VisitedKnots); } bool UConversationGraphNode_Knot::IsOutBoundConnectionAllowed(const UConversationGraphNode* OtherNode, FText& OutErrorMessage) const { if (!OtherNode) { return false; } if (const UConversationNodeWithLinks* OtherTaskNode = OtherNode->GetRuntimeNode()) { TArray GraphNodes; GatherAllInBoundGraphNodes(GraphNodes); for (const UConversationGraphNode* MyNode : GraphNodes) { if (const UConversationNodeWithLinks* MyTaskNode = MyNode->GetRuntimeNode()) { if (!MyTaskNode->IsOutBoundConnectionAllowed(OtherTaskNode, OutErrorMessage)) { return false; } } } } return true; } bool UConversationGraphNode_Knot::IsOutBoundConnectionAllowed(const UConversationGraphNode_Knot* OtherKnotNode, FText& OutErrorMessage) const { if (!OtherKnotNode) { return false; } TArray InGraphNodes; GatherAllInBoundGraphNodes(InGraphNodes); OtherKnotNode->GatherAllInBoundGraphNodes(InGraphNodes); TArray OutGraphNodes; GatherAllOutBoundGraphNodes(OutGraphNodes); OtherKnotNode->GatherAllOutBoundGraphNodes(OutGraphNodes); for (const UConversationGraphNode* MyNode : InGraphNodes) { if (const UConversationNodeWithLinks* MyTaskNode = MyNode->GetRuntimeNode()) { for (const UConversationGraphNode* OtherNode : OutGraphNodes) { if (const UConversationNodeWithLinks* OtherTaskNode = OtherNode->GetRuntimeNode()) { if (!MyTaskNode->IsOutBoundConnectionAllowed(OtherTaskNode, OutErrorMessage)) { return false; } } } } } return true; } void UConversationGraphNode_Knot::GatherAllInBoundGraphNodes_Internal(TArray& OutGraphNodes, TArray& VisitedKnots) const { if (VisitedKnots.Contains(this)) { return; } VisitedKnots.Add(this); for (UEdGraphPin* LinkedPin : GetInputPin()->LinkedTo) { if (UConversationGraphNode* GraphNode = Cast(LinkedPin->GetOwningNode())) { OutGraphNodes.Add(GraphNode); } else if (UConversationGraphNode_Knot* GraphKnot = Cast(LinkedPin->GetOwningNode())) { GraphKnot->GatherAllInBoundGraphNodes_Internal(OutGraphNodes, VisitedKnots); } } } void UConversationGraphNode_Knot::GatherAllOutBoundGraphNodes_Internal(TArray& OutGraphNodes, TArray& VisitedKnots) const { if (VisitedKnots.Contains(this)) { return; } VisitedKnots.Add(this); for (UEdGraphPin* LinkedPin : GetOutputPin()->LinkedTo) { if (UConversationGraphNode* GraphNode = Cast(LinkedPin->GetOwningNode())) { OutGraphNodes.Add(GraphNode); } else if (UConversationGraphNode_Knot* GraphKnot = Cast(LinkedPin->GetOwningNode())) { GraphKnot->GatherAllOutBoundGraphNodes_Internal(OutGraphNodes, VisitedKnots); } } } ///////////////////////////////////////////////////// #undef LOCTEXT_NAMESPACE