const FPinConnectionResponse UEdGraphSchema_BehaviorTreeDecorator::CanCreateConnection(const UEdGraphPin* PinA, const UEdGraphPin* PinB) const { if (PinA == NULL || PinB == NULL) { return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, TEXT("One of the Pins is NULL")); } // Make sure the pins are not on the same node if (PinA->GetOwningNode() == PinB->GetOwningNode()) { return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, TEXT("Both are on the same node")); } // multiple links if (PinA->LinkedTo.Num() > 0 || PinB->LinkedTo.Num() > 0) { return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, TEXT("")); } // Compare the directions if (PinA->Direction == PinB->Direction) { return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, TEXT("")); } return FPinConnectionResponse(CONNECT_RESPONSE_MAKE, TEXT("")); }
const FPinConnectionResponse UMaterialGraphSchema::CanCreateConnection(const UEdGraphPin* A, const UEdGraphPin* B) const { bool bPreventInvalidConnections = CVarPreventInvalidMaterialConnections.GetValueOnGameThread() != 0; // Make sure the pins are not on the same node if (A->GetOwningNode() == B->GetOwningNode()) { return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("ConnectionSameNode", "Both are on the same node")); } // Compare the directions const UEdGraphPin* InputPin = NULL; const UEdGraphPin* OutputPin = NULL; if (!CategorizePinsByDirection(A, B, /*out*/ InputPin, /*out*/ OutputPin)) { return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("ConnectionIncompatible", "Directions are not compatible")); } // Check for new and existing loops FText ResponseMessage; if (ConnectionCausesLoop(InputPin, OutputPin)) { ResponseMessage = LOCTEXT("ConnectionLoop", "Connection could cause loop"); // TODO: re-enable this if loops are going to be removed completely //return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("ConnectionLoop", "Connection would cause loop").ToString()); } // Check for incompatible pins and get description if they cannot connect if (!ArePinsCompatible(InputPin, OutputPin, ResponseMessage) && bPreventInvalidConnections) { return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, ResponseMessage); } // Break existing connections on inputs only - multiple output connections are acceptable if (InputPin->LinkedTo.Num() > 0) { ECanCreateConnectionResponse ReplyBreakOutputs; if (InputPin == A) { ReplyBreakOutputs = CONNECT_RESPONSE_BREAK_OTHERS_A; } else { ReplyBreakOutputs = CONNECT_RESPONSE_BREAK_OTHERS_B; } if (ResponseMessage.IsEmpty()) { ResponseMessage = LOCTEXT("ConnectionReplace", "Replace existing connections"); } return FPinConnectionResponse(ReplyBreakOutputs, ResponseMessage); } return FPinConnectionResponse(CONNECT_RESPONSE_MAKE, ResponseMessage); }
FPinConnectionResponse UEdGraphSchema::CopyPinLinks(UEdGraphPin& CopyFromPin, UEdGraphPin& CopyToPin, bool bIsIntermediateCopy) const { #if WITH_EDITOR ensureMsg(bIsIntermediateCopy || !CopyToPin.GetOwningNode()->GetGraph()->HasAnyFlags(RF_Transient), TEXT("When copying to an Intermediate pin, use FKismetCompilerContext::CopyPinLinksToIntermediate() instead of UEdGraphSchema::CopyPinLinks()")); #endif // #if WITH_EDITOR FPinConnectionResponse FinalResponse = FPinConnectionResponse(CONNECT_RESPONSE_MAKE, TEXT("")); for (int32 i=0; i<CopyFromPin.LinkedTo.Num(); i++) { UEdGraphPin* NewLink = CopyFromPin.LinkedTo[i]; FPinConnectionResponse Response = CanCreateConnection(&CopyToPin, NewLink); if (Response.CanSafeConnect()) { CopyToPin.MakeLinkTo(NewLink); } else { FinalResponse = Response; } } CopyToPin.DefaultValue = CopyFromPin.DefaultValue; CopyToPin.DefaultObject = CopyFromPin.DefaultObject; CopyToPin.DefaultTextValue = CopyFromPin.DefaultTextValue; return FinalResponse; }
FPinConnectionResponse UEdGraphSchema::MovePinLinks(UEdGraphPin& MoveFromPin, UEdGraphPin& MoveToPin, bool bIsIntermediateMove) const { #if WITH_EDITOR ensureMsg(bIsIntermediateMove || !MoveToPin.GetOwningNode()->GetGraph()->HasAnyFlags(RF_Transient), TEXT("When moving to an Intermediate pin, use FKismetCompilerContext::MovePinLinksToIntermediate() instead of UEdGraphSchema::MovePinLinks()")); #endif // #if WITH_EDITOR FPinConnectionResponse FinalResponse = FPinConnectionResponse(CONNECT_RESPONSE_MAKE, TEXT("")); // First copy the current set of links TArray<UEdGraphPin*> CurrentLinks = MoveFromPin.LinkedTo; // Then break all links at pin we are moving from MoveFromPin.BreakAllPinLinks(); // Try and make each new connection for (int32 i=0; i<CurrentLinks.Num(); i++) { UEdGraphPin* NewLink = CurrentLinks[i]; FPinConnectionResponse Response = CanCreateConnection(&MoveToPin, NewLink); if(Response.CanSafeConnect()) { MoveToPin.MakeLinkTo(NewLink); } else { FinalResponse = Response; } } // Move over the default values MoveToPin.DefaultValue = MoveFromPin.DefaultValue; MoveToPin.DefaultObject = MoveFromPin.DefaultObject; MoveToPin.DefaultTextValue = MoveFromPin.DefaultTextValue; return FinalResponse; }
const FPinConnectionResponse UAnimationGraphSchema::DetermineConnectionResponseOfCompatibleTypedPins(const UEdGraphPin* PinA, const UEdGraphPin* PinB, const UEdGraphPin* InputPin, const UEdGraphPin* OutputPin) const { // Enforce a tree hierarchy; where poses can only have one output (parent) connection if (IsPosePin(OutputPin->PinType) && IsPosePin(InputPin->PinType)) { if ((OutputPin->LinkedTo.Num() > 0) || (InputPin->LinkedTo.Num() > 0)) { const ECanCreateConnectionResponse ReplyBreakOutputs = CONNECT_RESPONSE_BREAK_OTHERS_AB; return FPinConnectionResponse(ReplyBreakOutputs, TEXT("Replace existing connections")); } } // Fall back to standard K2 rules return Super::DetermineConnectionResponseOfCompatibleTypedPins(PinA, PinB, InputPin, OutputPin); }
const FPinConnectionResponse UEdGraphSchema_Niagara::CanCreateConnection(const UEdGraphPin* PinA, const UEdGraphPin* PinB) const { // Make sure the pins are not on the same node if (PinA->GetOwningNode() == PinB->GetOwningNode()) { return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, TEXT("Both are on the same node")); } // Check both pins support connections if(PinA->bNotConnectable || PinB->bNotConnectable) { return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, TEXT("Pin doesn't support connections.")); } // Compare the directions const UEdGraphPin* InputPin = NULL; const UEdGraphPin* OutputPin = NULL; if (!CategorizePinsByDirection(PinA, PinB, /*out*/ InputPin, /*out*/ OutputPin)) { return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, TEXT("Directions are not compatible")); } // Types must match exactly if(PinA->PinType != PinB->PinType) { return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, TEXT("Types are not compatible")); } // See if we want to break existing connections (if its an input with an existing connection) const bool bBreakExistingDueToDataInput = (InputPin->LinkedTo.Num() > 0); if (bBreakExistingDueToDataInput) { const ECanCreateConnectionResponse ReplyBreakInputs = (PinA == InputPin) ? CONNECT_RESPONSE_BREAK_OTHERS_A : CONNECT_RESPONSE_BREAK_OTHERS_B; return FPinConnectionResponse(ReplyBreakInputs, TEXT("Replace existing input connections")); } else { return FPinConnectionResponse(CONNECT_RESPONSE_MAKE, TEXT("")); } }
const FPinConnectionResponse UCreatureAnimGraphSchema::CanCreateConnection(const UEdGraphPin* A, const UEdGraphPin* B) const { return FPinConnectionResponse(CONNECT_RESPONSE_MAKE, TEXT("")); }
FPinConnectionResponse UReferenceViewerSchema::CopyPinLinks(UEdGraphPin& CopyFromPin, UEdGraphPin& CopyToPin, bool bIsItermeadiateCopy) const { // Don't allow copying any links return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, TEXT("")); }
FPinConnectionResponse UReferenceViewerSchema::MovePinLinks(UEdGraphPin& MoveFromPin, UEdGraphPin& MoveToPin, bool bIsItermeadiateMove) const { // Don't allow moving any links return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, TEXT("")); }
const FPinConnectionResponse UAnimationStateMachineSchema::CanCreateConnection(const UEdGraphPin* PinA, const UEdGraphPin* PinB) const { // Make sure the pins are not on the same node if (PinA->GetOwningNode() == PinB->GetOwningNode()) { return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, TEXT("Both are on the same node")); } // Connect entry node to a state is OK const bool bPinAIsEntry = PinA->GetOwningNode()->IsA(UAnimStateEntryNode::StaticClass()); const bool bPinBIsEntry = PinB->GetOwningNode()->IsA(UAnimStateEntryNode::StaticClass()); const bool bPinAIsStateNode = PinA->GetOwningNode()->IsA(UAnimStateNodeBase::StaticClass()); const bool bPinBIsStateNode = PinB->GetOwningNode()->IsA(UAnimStateNodeBase::StaticClass()); if (bPinAIsEntry || bPinBIsEntry) { if (bPinAIsEntry && bPinBIsStateNode) { return FPinConnectionResponse(CONNECT_RESPONSE_BREAK_OTHERS_A, TEXT("")); } if (bPinBIsEntry && bPinAIsStateNode) { return FPinConnectionResponse(CONNECT_RESPONSE_BREAK_OTHERS_B, TEXT("")); } return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, TEXT("Entry must connect to a state node")); } const bool bPinAIsTransition = PinA->GetOwningNode()->IsA(UAnimStateTransitionNode::StaticClass()); const bool bPinBIsTransition = PinB->GetOwningNode()->IsA(UAnimStateTransitionNode::StaticClass()); if (bPinAIsTransition && bPinBIsTransition) { return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, TEXT("Cannot wire a transition to a transition")); } // Compare the directions bool bDirectionsOK = false; if ((PinA->Direction == EGPD_Input) && (PinB->Direction == EGPD_Output)) { bDirectionsOK = true; } else if ((PinB->Direction == EGPD_Input) && (PinA->Direction == EGPD_Output)) { bDirectionsOK = true; } /* if (!bDirectionsOK) { return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, TEXT("Directions are not compatible")); } */ // Transitions are exclusive (both input and output), but states are not if (bPinAIsTransition) { return FPinConnectionResponse(CONNECT_RESPONSE_BREAK_OTHERS_A, TEXT("")); } else if (bPinBIsTransition) { return FPinConnectionResponse(CONNECT_RESPONSE_BREAK_OTHERS_B, TEXT("")); } else if (!bPinAIsTransition && !bPinBIsTransition) { return FPinConnectionResponse(CONNECT_RESPONSE_MAKE_WITH_CONVERSION_NODE, TEXT("Create a transition")); } else { return FPinConnectionResponse(CONNECT_RESPONSE_MAKE, TEXT("")); } }