void UK2Node_SwitchEnum::AddPinToSwitchNode() { // first try to restore unconnected pin, since connected one is always visible for(auto PinIt = Pins.CreateIterator(); PinIt; ++PinIt) { UEdGraphPin* Pin = *PinIt; if(Pin && (0 == Pin->LinkedTo.Num()) && Pin->bAdvancedView) { Pin->Modify(); Pin->bAdvancedView = false; return; } } for(auto PinIt = Pins.CreateIterator(); PinIt; ++PinIt) { UEdGraphPin* Pin = *PinIt; if(Pin && Pin->bAdvancedView) { Pin->Modify(); Pin->bAdvancedView = false; return; } } }
ERenamePinResult UK2Node::RenameUserDefinedPin(const FString& OldName, const FString& NewName, bool bTest) { UEdGraphPin* Pin = NULL; for (int32 PinIdx=0; PinIdx<Pins.Num(); PinIdx++) { if (OldName == Pins[PinIdx]->PinName) { Pin = Pins[PinIdx]; } else if(NewName == Pins[PinIdx]->PinName) { return ERenamePinResult::ERenamePinResult_NameCollision; } } if(!Pin) { return ERenamePinResult::ERenamePinResult_NoSuchPin; } if(!bTest) { Pin->Modify(); Pin->PinName = NewName; if(!Pin->DefaultTextValue.IsEmpty()) { Pin->GetSchema()->TrySetDefaultText(*Pin, Pin->DefaultTextValue); } if (Pin->SubPins.Num() > 0) { TArray<UEdGraphPin*> PinsToUpdate = Pin->SubPins; while (PinsToUpdate.Num() > 0) { UEdGraphPin* PinToRename = PinsToUpdate.Pop(/*bAllowShrinking=*/ false); if (PinToRename->SubPins.Num() > 0) { PinsToUpdate.Append(PinToRename->SubPins); } PinToRename->Modify(); PinToRename->PinName = NewName + PinToRename->PinName.RightChop(OldName.Len()); PinToRename->PinFriendlyName = FText::FromString(NewName + PinToRename->PinFriendlyName.ToString().RightChop(OldName.Len())); } } } return ERenamePinResult::ERenamePinResult_Success; }
void UMaterialGraphNode_Base::ModifyAndCopyPersistentPinData(UEdGraphPin& TargetPin, const UEdGraphPin& SourcePin) const { if (SourcePin.LinkedTo.Num() > 0) { TargetPin.Modify(); for (int32 LinkIndex = 0; LinkIndex < SourcePin.LinkedTo.Num(); ++LinkIndex) { UEdGraphPin* OtherPin = SourcePin.LinkedTo[LinkIndex]; OtherPin->Modify(); } } TargetPin.CopyPersistentDataFromOldPin(SourcePin); }
void UK2Node_CommutativeAssociativeBinaryOperator::RemoveInputPin(UEdGraphPin* Pin) { if(CanRemovePin(Pin)) { FScopedTransaction Transaction( LOCTEXT("RemovePinTx", "RemovePin") ); Modify(); if (RemovePin(Pin)) { --NumAdditionalInputs; int32 NameIndex = 0; const UEdGraphPin* OutPin = FindOutPin(); const UEdGraphPin* SelfPin = FindSelfPin(); for (int32 PinIndex = 0; PinIndex < Pins.Num(); ++PinIndex) { UEdGraphPin* LocalPin = Pins[PinIndex]; if(LocalPin && (LocalPin != OutPin) && (LocalPin != SelfPin)) { const FString PinName = GetNameForPin(NameIndex); if(PinName != LocalPin->PinName) { LocalPin->Modify(); LocalPin->PinName = PinName; } NameIndex++; } } FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprint()); } } }
void UK2Node_FormatText::PinConnectionListChanged(UEdGraphPin* Pin) { const auto FormatPin = GetFormatPin(); Modify(); // Clear all pins. if(Pin == FormatPin && !FormatPin->DefaultTextValue.IsEmpty()) { PinNames.Empty(); GetSchema()->TrySetDefaultText(*FormatPin, FText::GetEmpty()); for(auto It = Pins.CreateConstIterator(); It; ++It) { UEdGraphPin* CheckPin = *It; if(CheckPin != FormatPin && CheckPin->Direction == EGPD_Input) { CheckPin->Modify(); CheckPin->BreakAllPinLinks(); Pins.Remove(CheckPin); --It; } } FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprint()); } }
void UK2Node_Select::PostReconstructNode() { bReconstructNode = false; const UEdGraphSchema_K2* Schema = Cast<UEdGraphSchema_K2>(GetSchema()); UEdGraphPin* ReturnPin = GetReturnValuePin(); PinConnectionListChanged(ReturnPin); const bool bFillTypeFromReturn = Schema && ReturnPin && (ReturnPin->PinType.PinCategory != Schema->PC_Wildcard); TArray<UEdGraphPin*> OptionPins; GetOptionPins(OptionPins); for (auto It = OptionPins.CreateConstIterator(); It; It++) { UEdGraphPin* Pin = *It; const bool bTypeShouldBeFilled = Schema && Pin && (Pin->PinType.PinCategory == Schema->PC_Wildcard); if (bTypeShouldBeFilled && bFillTypeFromReturn) { Pin->Modify(); Pin->PinType = ReturnPin->PinType; UEdGraphSchema_K2::ValidateExistingConnections(Pin); } PinConnectionListChanged(*It); } //After ReconstructNode we must be sure, that no additional reconstruction is required bReconstructNode = false; }
void USoundCueGraphNode_Base::ReconstructNode() { // Break any links to 'orphan' pins for (int32 PinIndex = 0; PinIndex < Pins.Num(); ++PinIndex) { UEdGraphPin* Pin = Pins[PinIndex]; TArray<class UEdGraphPin*>& LinkedToRef = Pin->LinkedTo; for (int32 LinkIdx=0; LinkIdx < LinkedToRef.Num(); LinkIdx++) { UEdGraphPin* OtherPin = LinkedToRef[LinkIdx]; // If we are linked to a pin that its owner doesn't know about, break that link if (!OtherPin->GetOwningNode()->Pins.Contains(OtherPin)) { Pin->LinkedTo.Remove(OtherPin); } } } // Store the old Input and Output pins TArray<UEdGraphPin*> OldInputPins; GetInputPins(OldInputPins); UEdGraphPin* OldOutputPin = GetOutputPin(); // Move the existing pins to a saved array TArray<UEdGraphPin*> OldPins(Pins); Pins.Empty(); // Recreate the new pins AllocateDefaultPins(); // Get new Input and Output pins TArray<UEdGraphPin*> NewInputPins; GetInputPins(NewInputPins); UEdGraphPin* NewOutputPin = GetOutputPin(); for (int32 PinIndex = 0; PinIndex < OldInputPins.Num(); PinIndex++) { if (PinIndex < NewInputPins.Num()) { NewInputPins[PinIndex]->CopyPersistentDataFromOldPin(*OldInputPins[PinIndex]); } } NewOutputPin->CopyPersistentDataFromOldPin(*OldOutputPin); OldInputPins.Empty(); OldOutputPin = NULL; // Throw away the original pins for (int32 OldPinIndex = 0; OldPinIndex < OldPins.Num(); ++OldPinIndex) { UEdGraphPin* OldPin = OldPins[OldPinIndex]; OldPin->Modify(); OldPin->BreakAllPinLinks(); UEdGraphNode::DestroyPin(OldPin); } OldPins.Empty(); }
void UEdGraphPin::CopyPersistentDataFromOldPin(const UEdGraphPin& SourcePin) { // The name matches already, doesn't get copied here // The PinType, Direction, and bNotConnectable are properties generated from the schema // Only move the default value if it was modified; inherit the new default value otherwise if (SourcePin.DefaultValue != SourcePin.AutogeneratedDefaultValue || SourcePin.DefaultObject != NULL || SourcePin.DefaultTextValue.ToString() != SourcePin.AutogeneratedDefaultValue) { DefaultObject = SourcePin.DefaultObject; DefaultValue = SourcePin.DefaultValue; DefaultTextValue = SourcePin.DefaultTextValue; } // Copy the links for (int32 LinkIndex = 0; LinkIndex < SourcePin.LinkedTo.Num(); ++LinkIndex) { UEdGraphPin* OtherPin = SourcePin.LinkedTo[LinkIndex]; check(NULL != OtherPin); Modify(); OtherPin->Modify(); LinkedTo.Add(OtherPin); // Unlike MakeLinkTo(), we attempt to ensure that the new pin (this) is inserted at the same position as the old pin (source) // in the OtherPin's LinkedTo array. This is necessary to ensure that the node's position in the execution order will remain // unchanged after nodes are reconstructed, because OtherPin may be connected to more than just this node. int32 Index = OtherPin->LinkedTo.Find(const_cast<UEdGraphPin*>(&SourcePin)); if(Index != INDEX_NONE) { OtherPin->LinkedTo.Insert(this, Index); } else { // Fallback to "normal" add, just in case the old pin doesn't exist in the other pin's LinkedTo array for some reason. OtherPin->LinkedTo.Add(this); } } // If the source pin is split, then split the new one, but don't split multiple times, typically splitting is done // by UK2Node::ReallocatePinsDuringReconstruction or FBlueprintEditor::OnSplitStructPin, but there are several code // paths into this, and split state should be persistent: if (SourcePin.SubPins.Num() > 0 && SubPins.Num() == 0) { GetSchema()->SplitPin(this); } #if WITH_EDITORONLY_DATA // Copy advanced visibility property, if it can be changed by user. // Otherwise we don't want to copy this, or we'd be ignoring new metadata that tries to hide old pins. UEdGraphNode* OuterNode = Cast<UEdGraphNode>(GetOuter()); if (OuterNode != nullptr && OuterNode->CanUserEditPinAdvancedViewFlag()) { bAdvancedView = SourcePin.bAdvancedView; } #endif // WITH_EDITORONLY_DATA }
void UMaterialGraphNode_Base::ReplaceNode(UMaterialGraphNode_Base* OldNode) { check(OldNode); check(OldNode != this); // Get Pins from node passed in TArray<UEdGraphPin*> OldInputPins; TArray<UEdGraphPin*> OldOutputPins; OldNode->GetInputPins(OldInputPins); OldNode->GetOutputPins(OldOutputPins); // Get our Input and Output pins TArray<UEdGraphPin*> NewInputPins; TArray<UEdGraphPin*> NewOutputPins; GetInputPins(NewInputPins); GetOutputPins(NewOutputPins); // Copy Inputs from old node for (int32 PinIndex = 0; PinIndex < OldInputPins.Num(); PinIndex++) { if (PinIndex < NewInputPins.Num()) { ModifyAndCopyPersistentPinData(*NewInputPins[PinIndex], *OldInputPins[PinIndex]); } } // Copy Outputs from old node for (int32 PinIndex = 0; PinIndex < OldOutputPins.Num(); PinIndex++) { // If we can't find an equivalent output in this node, just use the first // The user will have to fix up any issues from the mismatch int32 FoundPinIndex = 0; // Try to find an equivalent output in this node for (int32 NewPinIndex = 0; NewPinIndex < NewOutputPins.Num(); NewPinIndex++) { if (OldOutputPins[PinIndex]->PinType == NewOutputPins[NewPinIndex]->PinType) { FoundPinIndex = NewPinIndex; break; } } if (FoundPinIndex < NewOutputPins.Num()) { ModifyAndCopyPersistentPinData(*NewOutputPins[FoundPinIndex], *OldOutputPins[PinIndex]); } } // Break the original pin links for (int32 OldPinIndex = 0; OldPinIndex < OldNode->Pins.Num(); ++OldPinIndex) { UEdGraphPin* OldPin = OldNode->Pins[OldPinIndex]; OldPin->Modify(); OldPin->BreakAllPinLinks(); } }
FReply FKismetVariableDragDropAction::DroppedOnNode(FVector2D ScreenPosition, FVector2D GraphPosition) { UK2Node_Variable* TargetNode = Cast<UK2Node_Variable>(GetHoveredNode()); if (TargetNode && (VariableName != TargetNode->GetVarName())) { const FScopedTransaction Transaction( LOCTEXT("ReplacePinVariable", "Replace Pin Variable") ); UProperty* VariableProperty = GetVariableProperty(); if(CanVariableBeDropped(VariableProperty, *TargetNode->GetGraph())) { const FString OldVarName = TargetNode->GetVarNameString(); const UEdGraphSchema_K2* Schema = Cast<const UEdGraphSchema_K2>(TargetNode->GetSchema()); TArray<class UEdGraphPin*> BadLinks; GetLinksThatWillBreak(TargetNode,VariableProperty,BadLinks); // Change the variable name and context UBlueprint* DropOnBlueprint = FBlueprintEditorUtils::FindBlueprintForGraph(TargetNode->GetGraph()); UEdGraphPin* Pin = TargetNode->FindPin(OldVarName); DropOnBlueprint->Modify(); TargetNode->Modify(); if (Pin != NULL) { Pin->Modify(); } UEdGraphSchema_K2::ConfigureVarNode(TargetNode, VariableName, VariableSource.Get(), DropOnBlueprint); if ((Pin == NULL) || (Pin->LinkedTo.Num() == BadLinks.Num()) || (Schema == NULL)) { TargetNode->GetSchema()->ReconstructNode(*TargetNode); } else { FEdGraphPinType NewPinType; Schema->ConvertPropertyToPinType(VariableProperty,NewPinType); Pin->PinName = VariableName.ToString(); Pin->PinType = NewPinType; //break bad links for(TArray<class UEdGraphPin*>::TIterator OtherPinIt(BadLinks);OtherPinIt;) { Pin->BreakLinkTo(*OtherPinIt); } } return FReply::Handled(); } } return FReply::Unhandled(); }
FReply FDragConnection::DroppedOnNode(FVector2D ScreenPosition, FVector2D GraphPosition) { bool bHandledPinDropOnNode = false; UEdGraphNode* HoveredNode = GetHoveredNode(); if (HoveredNode) { // Gather any source drag pins TArray<UEdGraphPin*> ValidSourcePins; ValidateGraphPinList(/*out*/ ValidSourcePins); if (ValidSourcePins.Num()) { for (UEdGraphPin* SourcePin : ValidSourcePins) { // Check for pin drop support FText ResponseText; if (SourcePin->GetOwningNode() != HoveredNode && SourcePin->GetSchema()->SupportsDropPinOnNode(HoveredNode, SourcePin->PinType, SourcePin->Direction, ResponseText)) { bHandledPinDropOnNode = true; // Find which pin name to use and drop the pin on the node FString PinName = SourcePin->PinFriendlyName.IsEmpty()? SourcePin->PinName : SourcePin->PinFriendlyName.ToString(); const FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "AddInParam", "Add In Parameter" ) ); UEdGraphPin* EdGraphPin = HoveredNode->GetSchema()->DropPinOnNode(GetHoveredNode(), PinName, SourcePin->PinType, SourcePin->Direction); if(EdGraphPin) { SourcePin->Modify(); EdGraphPin->Modify(); SourcePin->GetSchema()->TryCreateConnection(SourcePin, EdGraphPin); } } // If we have not handled the pin drop on node and there is an error message, do not let other actions occur. if(!bHandledPinDropOnNode && !ResponseText.IsEmpty()) { bHandledPinDropOnNode = true; } } } } return bHandledPinDropOnNode? FReply::Handled() : FReply::Unhandled(); }
void UMaterialGraphNode::RecreateAndLinkNode() { // Throw away the original pins for (int32 PinIndex = 0; PinIndex < Pins.Num(); ++PinIndex) { UEdGraphPin* Pin = Pins[PinIndex]; Pin->Modify(); Pin->BreakAllPinLinks(); #if 0 UEdGraphNode::ReturnPinToPool(Pin); #else Pin->Rename(NULL, GetTransientPackage(), REN_None); Pin->RemoveFromRoot(); Pin->MarkPendingKill(); #endif } Pins.Empty(); AllocateDefaultPins(); CastChecked<UMaterialGraph>(GetGraph())->LinkGraphNodesFromMaterial(); }
/** Determine if any pins are connected, if so make all the other pins the same type, if not, make sure pins are switched back to wildcards */ void UK2Node_Select::NotifyPinConnectionListChanged(UEdGraphPin* Pin) { Super::NotifyPinConnectionListChanged(Pin); const UEdGraphSchema_K2* Schema = GetDefault<UEdGraphSchema_K2>(); // If this is the Enum pin we need to set the enum and reconstruct the node if (Pin == GetIndexPin()) { // If the index pin was just linked to another pin if (Pin->LinkedTo.Num() > 0) { UEdGraphPin* LinkPin = Pin->LinkedTo[0]; IndexPinType = LinkPin->PinType; Pin->PinType = IndexPinType; // See if it was an enum pin if (LinkPin->PinType.PinCategory == Schema->PC_Byte && LinkPin->PinType.PinSubCategoryObject != NULL && LinkPin->PinType.PinSubCategoryObject->IsA(UEnum::StaticClass())) { UEnum* EnumPtr = Cast<UEnum>(LinkPin->PinType.PinSubCategoryObject.Get()); SetEnum(EnumPtr); } else { SetEnum(NULL); } Schema->SetPinDefaultValueBasedOnType(Pin); GetGraph()->NotifyGraphChanged(); UBlueprint* Blueprint = GetBlueprint(); if(!Blueprint->bBeingCompiled) { FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint); Blueprint->BroadcastChanged(); } // If the index pin is a boolean, we need to remove all but 2 options if (IndexPinType.PinCategory == Schema->PC_Boolean && NumOptionPins != 2) { NumOptionPins = 2; bReconstructNode = true; } } } else { // Grab references to all option pins and the return pin TArray<UEdGraphPin*> OptionPins; GetOptionPins(OptionPins); UEdGraphPin* ReturnPin = FindPin(Schema->PN_ReturnValue); // See if this pin is one of the wildcard pins bool bIsWildcardPin = (Pin == ReturnPin || OptionPins.Find(Pin) != INDEX_NONE) && Pin->PinType.PinCategory == Schema->PC_Wildcard; // If the pin was one of the wildcards we have to handle it specially if (bIsWildcardPin) { // If the pin is linked, make sure the other wildcard pins match if (Pin->LinkedTo.Num() > 0) { // Set pin type on the pin Pin->PinType = Pin->LinkedTo[0]->PinType; // Make sure the return pin is the same pin type if (ReturnPin != Pin) { ReturnPin->Modify(); ReturnPin->PinType = Pin->PinType; UEdGraphSchema_K2::ValidateExistingConnections(ReturnPin); } // Make sure all options are of the same pin type for (auto It = OptionPins.CreateConstIterator(); It; It++) { UEdGraphPin* OptionPin = (*It); if (*It && *It != Pin) { (*It)->Modify(); (*It)->PinType = Pin->PinType; UEdGraphSchema_K2::ValidateExistingConnections(*It); } } bReconstructNode = true; } } } }
void UNiagaraNodeOutput::ReallocatePins() { Modify(); // Break any links to 'orphan' pins for (int32 PinIndex = 0; PinIndex < Pins.Num(); ++PinIndex) { UEdGraphPin* Pin = Pins[PinIndex]; TArray<class UEdGraphPin*>& LinkedToRef = Pin->LinkedTo; for (int32 LinkIdx = 0; LinkIdx < LinkedToRef.Num(); LinkIdx++) { UEdGraphPin* OtherPin = LinkedToRef[LinkIdx]; // If we are linked to a pin that its owner doesn't know about, break that link if (!OtherPin->GetOwningNode()->Pins.Contains(OtherPin)) { Pin->LinkedTo.Remove(OtherPin); } } } // Store the old Input and Output pins TArray<UEdGraphPin*> OldInputPins; TArray<UEdGraphPin*> OldOutputPins; GetInputPins(OldInputPins); GetOutputPins(OldOutputPins); // Move the existing pins to a saved array TArray<UEdGraphPin*> OldPins(Pins); Pins.Empty(); // Recreate the new pins AllocateDefaultPins(); // Get new Input and Output pins TArray<UEdGraphPin*> NewInputPins; TArray<UEdGraphPin*> NewOutputPins; GetInputPins(NewInputPins); GetOutputPins(NewOutputPins); for (int32 PinIndex = 0; PinIndex < OldInputPins.Num(); PinIndex++) { if (PinIndex < NewInputPins.Num()) { NewInputPins[PinIndex]->CopyPersistentDataFromOldPin(*OldInputPins[PinIndex]); } } for (int32 PinIndex = 0; PinIndex < OldOutputPins.Num(); PinIndex++) { if (PinIndex < NewOutputPins.Num()) { NewOutputPins[PinIndex]->CopyPersistentDataFromOldPin(*OldOutputPins[PinIndex]); } } OldInputPins.Empty(); OldOutputPins.Empty(); // Throw away the original pins for (int32 OldPinIndex = 0; OldPinIndex < OldPins.Num(); ++OldPinIndex) { UEdGraphPin* OldPin = OldPins[OldPinIndex]; OldPin->Modify(); OldPin->BreakAllPinLinks(); #if 0 UEdGraphNode::ReturnPinToPool(OldPin); #else OldPin->Rename(NULL, GetTransientPackage(), REN_None); OldPin->RemoveFromRoot(); OldPin->MarkPendingKill(); #endif } OldPins.Empty(); GetGraph()->NotifyGraphChanged(); }
void FEnumEditorUtils::BroadcastChanges(const UUserDefinedEnum* Enum, const TArray<TPair<FName, int8>>& OldNames, bool bResolveData) { check(NULL != Enum); if (bResolveData) { FArchiveEnumeratorResolver EnumeratorResolver(Enum, OldNames); TArray<UClass*> ClassesToCheck; for (TObjectIterator<UByteProperty> PropertyIter; PropertyIter; ++PropertyIter) { const UByteProperty* ByteProperty = *PropertyIter; if (ByteProperty && (Enum == ByteProperty->GetIntPropertyEnum())) { UClass* OwnerClass = ByteProperty->GetOwnerClass(); if (OwnerClass) { ClassesToCheck.Add(OwnerClass); } } } for (FObjectIterator ObjIter; ObjIter; ++ObjIter) { for (auto ClassIter = ClassesToCheck.CreateConstIterator(); ClassIter; ++ClassIter) { if (ObjIter->IsA(*ClassIter)) { ObjIter->Serialize(EnumeratorResolver); break; } } } } struct FNodeValidatorHelper { static bool IsValid(UK2Node* Node) { return Node && (NULL != Cast<UEdGraph>(Node->GetOuter())) && !Node->HasAnyFlags(RF_Transient | RF_PendingKill); } }; TSet<UBlueprint*> BlueprintsToRefresh; { //CUSTOM NODES DEPENTENT ON ENUM for (TObjectIterator<UK2Node> It(RF_Transient); It; ++It) { UK2Node* Node = *It; INodeDependingOnEnumInterface* NodeDependingOnEnum = Cast<INodeDependingOnEnumInterface>(Node); if (FNodeValidatorHelper::IsValid(Node) && NodeDependingOnEnum && (Enum == NodeDependingOnEnum->GetEnum())) { if (UBlueprint* Blueprint = Node->GetBlueprint()) { if (NodeDependingOnEnum->ShouldBeReconstructedAfterEnumChanged()) { Node->ReconstructNode(); } BlueprintsToRefresh.Add(Blueprint); } } } } for (TObjectIterator<UEdGraphPin> It(RF_Transient); It; ++It) { UEdGraphPin* Pin = *It; if (Pin && (Enum == Pin->PinType.PinSubCategoryObject.Get()) && (EEdGraphPinDirection::EGPD_Input == Pin->Direction)) { UK2Node* Node = Cast<UK2Node>(Pin->GetOuter()); if (FNodeValidatorHelper::IsValid(Node)) { if (UBlueprint* Blueprint = Node->GetBlueprint()) { if (INDEX_NONE == Enum->FindEnumIndex(*Pin->DefaultValue)) { Pin->Modify(); if (Blueprint->BlueprintType == BPTYPE_Interface) { Pin->DefaultValue = Enum->GetEnumName(0); } else { Pin->DefaultValue = FEnumEditorUtilsHelper::InvalidName(); } Node->PinDefaultValueChanged(Pin); BlueprintsToRefresh.Add(Blueprint); } } } } } for (auto It = BlueprintsToRefresh.CreateIterator(); It; ++It) { FBlueprintEditorUtils::MarkBlueprintAsModified(*It); (*It)->BroadcastChanged(); } FEnumEditorManager::Get().PostChange(Enum, EEnumEditorChangeInfo::Changed); }
void UNiagaraNodeInput::ReallocatePins() { const UEdGraphSchema_Niagara* Schema = GetDefault<UEdGraphSchema_Niagara>(); Modify(); // Break any links to 'orphan' pins for (int32 PinIndex = 0; PinIndex < Pins.Num(); ++PinIndex) { UEdGraphPin* Pin = Pins[PinIndex]; TArray<class UEdGraphPin*>& LinkedToRef = Pin->LinkedTo; for (int32 LinkIdx = 0; LinkIdx < LinkedToRef.Num(); LinkIdx++) { UEdGraphPin* OtherPin = LinkedToRef[LinkIdx]; // If we are linked to a pin that its owner doesn't know about, break that link if (!OtherPin->GetOwningNode()->Pins.Contains(OtherPin)) { Pin->LinkedTo.Remove(OtherPin); } } } // Store the old Input and Output pins TArray<UEdGraphPin*> OldInputPins; TArray<UEdGraphPin*> OldOutputPins; GetInputPins(OldInputPins); GetOutputPins(OldOutputPins); // Move the existing pins to a saved array TArray<UEdGraphPin*> OldPins(Pins); Pins.Empty(); switch (Input.Type) { case ENiagaraDataType::Scalar: { CreatePin(EGPD_Output, Schema->PC_Float, TEXT(""), NULL, false, false, Input.Name.ToString()); } break; case ENiagaraDataType::Vector: { CreatePin(EGPD_Output, Schema->PC_Vector, TEXT(""), NULL, false, false, Input.Name.ToString()); } break; case ENiagaraDataType::Matrix: { CreatePin(EGPD_Output, Schema->PC_Matrix, TEXT(""), NULL, false, false, Input.Name.ToString()); } break; case ENiagaraDataType::Curve: { CreatePin(EGPD_Output, Schema->PC_Curve, TEXT(""), NULL, false, false, Input.Name.ToString()); } break; }; // Get new Input and Output pins TArray<UEdGraphPin*> NewInputPins; TArray<UEdGraphPin*> NewOutputPins; GetInputPins(NewInputPins); GetOutputPins(NewOutputPins); for (int32 PinIndex = 0; PinIndex < OldInputPins.Num(); PinIndex++) { if (PinIndex < NewInputPins.Num()) { NewInputPins[PinIndex]->CopyPersistentDataFromOldPin(*OldInputPins[PinIndex]); } } for (int32 PinIndex = 0; PinIndex < OldOutputPins.Num(); PinIndex++) { if (PinIndex < NewOutputPins.Num()) { NewOutputPins[PinIndex]->CopyPersistentDataFromOldPin(*OldOutputPins[PinIndex]); } } OldInputPins.Empty(); OldOutputPins.Empty(); // Throw away the original pins for (int32 OldPinIndex = 0; OldPinIndex < OldPins.Num(); ++OldPinIndex) { UEdGraphPin* OldPin = OldPins[OldPinIndex]; OldPin->Modify(); OldPin->BreakAllPinLinks(); #if 0 UEdGraphNode::ReturnPinToPool(OldPin); #else OldPin->Rename(NULL, GetTransientPackage(), REN_None); OldPin->RemoveFromRoot(); OldPin->MarkPendingKill(); #endif } OldPins.Empty(); GetGraph()->NotifyGraphChanged(); }
void UK2Node::ReconstructNode() { Modify(); UBlueprint* Blueprint = GetBlueprint(); // Break any links to 'orphan' pins for (int32 PinIndex = 0; PinIndex < Pins.Num(); ++PinIndex) { UEdGraphPin* Pin = Pins[PinIndex]; TArray<class UEdGraphPin*> LinkedToCopy = Pin->LinkedTo; for (int32 LinkIdx = 0; LinkIdx < LinkedToCopy.Num(); LinkIdx++) { UEdGraphPin* OtherPin = LinkedToCopy[LinkIdx]; // If we are linked to a pin that its owner doesn't know about, break that link if ((OtherPin == NULL) || !OtherPin->GetOwningNodeUnchecked() || !OtherPin->GetOwningNode()->Pins.Contains(OtherPin)) { Pin->LinkedTo.Remove(OtherPin); } } } // Move the existing pins to a saved array TArray<UEdGraphPin*> OldPins(Pins); Pins.Empty(); // Recreate the new pins ReallocatePinsDuringReconstruction(OldPins); bool bDestroyOldPins = true; if (Pins.Num() == 0) { //keep old pins on callfunction so that graph doesn't get broken up just because function is missing if (IsA(UK2Node_CallFunction::StaticClass()) || IsA(UK2Node_MacroInstance::StaticClass())) { Pins = OldPins; bDestroyOldPins = false; } } else { // Rewire any connection to pins that are matched by name (O(N^2) right now) //@TODO: Can do moderately smart things here if only one pin changes name by looking at it's relative position, etc..., // rather than just failing to map it and breaking the links for (int32 OldPinIndex = 0; OldPinIndex < OldPins.Num(); ++OldPinIndex) { UEdGraphPin* OldPin = OldPins[OldPinIndex]; for (int32 NewPinIndex = 0; NewPinIndex < Pins.Num(); ++NewPinIndex) { UEdGraphPin* NewPin = Pins[NewPinIndex]; const ERedirectType RedirectType = DoPinsMatchForReconstruction(NewPin, NewPinIndex, OldPin, OldPinIndex); if (RedirectType != ERedirectType_None) { ReconstructSinglePin(NewPin, OldPin, RedirectType); break; } } } } if (bDestroyOldPins) { // Throw away the original pins for (int32 OldPinIndex = 0; OldPinIndex < OldPins.Num(); ++OldPinIndex) { UEdGraphPin* OldPin = OldPins[OldPinIndex]; OldPin->Modify(); OldPin->BreakAllPinLinks(); // just in case this pin was set to watch (don't want to save PinWatches with dead pins) Blueprint->PinWatches.Remove(OldPin); #if 0 UEdGraphNode::ReturnPinToPool(OldPin); #else OldPin->Rename(NULL, GetTransientPackage(), (Blueprint->bIsRegeneratingOnLoad ? REN_ForceNoResetLoaders : REN_None)); OldPin->RemoveFromRoot(); OldPin->MarkPendingKill(); #endif } } // Let subclasses do any additional work PostReconstructNode(); GetGraph()->NotifyGraphChanged(); }
void UEdGraphPin::CopyPersistentDataFromOldPin(const UEdGraphPin& SourcePin) { // The name matches already, doesn't get copied here // The PinType, Direction, and bNotConnectable are properties generated from the schema // Only move the default value if it was modified; inherit the new default value otherwise if (SourcePin.DefaultValue != SourcePin.AutogeneratedDefaultValue || SourcePin.DefaultObject != NULL) { DefaultObject = SourcePin.DefaultObject; DefaultValue = SourcePin.DefaultValue; } const bool bTextValueWasModified = (SourcePin.DefaultTextValue.ToString() != SourcePin.AutogeneratedDefaultValue); if (bTextValueWasModified) { DefaultTextValue = SourcePin.DefaultTextValue; } // In K2 schemas the wildcard pins need to have their type copied before we get to pin splitting // TODO: Better less hacky way of this? if (PinType.PinCategory == TEXT("wildcard")) { PinType = SourcePin.PinType; } // Copy the links for (int32 LinkIndex = 0; LinkIndex < SourcePin.LinkedTo.Num(); ++LinkIndex) { UEdGraphPin* OtherPin = SourcePin.LinkedTo[LinkIndex]; check(NULL != OtherPin); Modify(); OtherPin->Modify(); LinkedTo.Add(OtherPin); // Unlike MakeLinkTo(), we attempt to ensure that the new pin (this) is inserted at the same position as the old pin (source) // in the OtherPin's LinkedTo array. This is necessary to ensure that the node's position in the execution order will remain // unchanged after nodes are reconstructed, because OtherPin may be connected to more than just this node. int32 Index = OtherPin->LinkedTo.Find(const_cast<UEdGraphPin*>(&SourcePin)); if(Index != INDEX_NONE) { OtherPin->LinkedTo.Insert(this, Index); } else { // Fallback to "normal" add, just in case the old pin doesn't exist in the other pin's LinkedTo array for some reason. OtherPin->LinkedTo.Add(this); } } // If the source pin is split, then split the new one if (SourcePin.SubPins.Num() > 0) { GetSchema()->SplitPin(this); } #if WITH_EDITORONLY_DATA // Copy advanced visibility property, since it can be changed by user bAdvancedView = SourcePin.bAdvancedView; #endif // WITH_EDITORONLY_DATA }