void UK2Node_SwitchString::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) { bool bIsDirty = false; FName PropertyName = (PropertyChangedEvent.Property != NULL) ? PropertyChangedEvent.Property->GetFName() : NAME_None; if (PropertyName == TEXT("PinNames")) { bIsDirty = true; } else if (PropertyName == TEXT("bIsCaseSensitive")) { FunctionName = (bIsCaseSensitive == true) ? TEXT("NotEqual_StrStr") : TEXT("NotEqual_StriStri"); FunctionClass = UKismetStringLibrary::StaticClass(); bIsDirty = true; } if (bIsDirty) { ReconstructNode(); GetGraph()->NotifyGraphChanged(); } Super::PostEditChangeProperty(PropertyChangedEvent); }
void UK2Node_Select::RemoveOptionPinToNode() { // Increment the pin count NumOptionPins--; // We will let the AllocateDefaultPins call handle the actual subtraction via ReconstructNode ReconstructNode(); }
void UK2Node_Switch::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) { FName PropertyName = (PropertyChangedEvent.Property != NULL) ? PropertyChangedEvent.Property->GetFName() : NAME_None; if (PropertyName == TEXT("bHasDefaultPin")) { // Signal to the reconstruction logic that the default pin value has changed bHasDefaultPinValueChanged = true; if (!bHasDefaultPin) { UEdGraphPin* DefaultPin = GetDefaultPin(); if (DefaultPin) { const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); K2Schema->BreakPinLinks(*DefaultPin, true); } } ReconstructNode(); // Clear the default pin value change flag bHasDefaultPinValueChanged = false; } Super::PostEditChangeProperty(PropertyChangedEvent); }
void UK2Node_GetClassDefaults::OnBlueprintClassModified(UBlueprint* TargetBlueprint) { check(TargetBlueprint); UBlueprint* OwnerBlueprint = FBlueprintEditorUtils::FindBlueprintForNode(this); //GetBlueprint() will crash, when the node is transient, etc if (OwnerBlueprint) { // The Blueprint that contains this node may have finished // regenerating (see bHasBeenRegenerated), but we still may be // in the midst of unwinding a cyclic load (dependent Blueprints); // this lambda could be triggered during the targeted // Blueprint's regeneration - meaning we really haven't completed // the load process. In this situation, we cannot "reset loaders" // because it is not likely that all of the package's objects // have been post-loaded (meaning an assert will most likely // fire from ReconstructNode). To guard against this, we flip this // Blueprint's bIsRegeneratingOnLoad (like in // UBlueprintGeneratedClass::ConditionalRecompileClass), which // we use throughout Blueprints to keep us from reseting loaders // on object Rename() const bool bOldIsRegeneratingVal = OwnerBlueprint->bIsRegeneratingOnLoad; OwnerBlueprint->bIsRegeneratingOnLoad = bOldIsRegeneratingVal || TargetBlueprint->bIsRegeneratingOnLoad; ReconstructNode(); OwnerBlueprint->bIsRegeneratingOnLoad = bOldIsRegeneratingVal; } }
void UAnimGraphNode_BlendListByEnum::RemovePinFromBlendList(UEdGraphPin* Pin) { int32 RawArrayIndex = 0; bool bIsPosePin = false; bool bIsTimePin = false; GetPinInformation(Pin->PinName, /*out*/ RawArrayIndex, /*out*/ bIsPosePin, /*out*/ bIsTimePin); const int32 ExposedEnumIndex = (bIsPosePin || bIsTimePin) ? (RawArrayIndex - 1) : INDEX_NONE; if (ExposedEnumIndex != INDEX_NONE) { FScopedTransaction Transaction( LOCTEXT("RemovePin", "RemovePin") ); Modify(); // Record it as no longer exposed VisibleEnumEntries.RemoveAt(ExposedEnumIndex); // Remove the pose from the node UProperty* AssociatedProperty; int32 ArrayIndex; GetPinAssociatedProperty(GetFNodeType(), Pin, /*out*/ AssociatedProperty, /*out*/ ArrayIndex); ensure(ArrayIndex == (ExposedEnumIndex + 1)); // setting up removed pins info RemovedPinArrayIndex = ArrayIndex; Node.RemovePose(ArrayIndex); ReconstructNode(); //@TODO: Just want to invalidate the visual representation currently FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprint()); } }
void UK2Node_SetFieldsInStruct::RemoveFieldPins(const UEdGraphPin* Pin, EPinsToRemove Selection) { if (ShowCustomPinActions(Pin, false) && (Pin->GetOwningNodeUnchecked() == this)) { // Pretend that the action was done on the hidden parent pin if the pin is split while (Pin->ParentPin != nullptr) { Pin = Pin->ParentPin; } const bool bHideSelected = (Selection == EPinsToRemove::GivenPin); const bool bHideNotSelected = (Selection == EPinsToRemove::AllOtherPins); bool bWasChanged = false; for (FOptionalPinFromProperty& OptionalProperty : ShowPinForProperties) { const bool bSelected = (Pin->PinName == OptionalProperty.PropertyName.ToString()); const bool bHide = (bSelected && bHideSelected) || (!bSelected && bHideNotSelected); if (OptionalProperty.bShowPin && bHide) { bWasChanged = true; OptionalProperty.bShowPin = false; } } if (bWasChanged) { ReconstructNode(); } } }
void UK2Node_FormatText::SetArgumentName(int32 InIndex, FText InName) { PinNames[InIndex] = InName; ReconstructNode(); FBlueprintEditorUtils::MarkBlueprintAsModified(GetBlueprint()); }
void UAnimGraphNode_LayeredBoneBlend::AddPinToBlendByFilter() { FScopedTransaction Transaction( NSLOCTEXT("A3Nodes", "AddPinToBlend", "AddPinToBlendByFilter") ); Modify(); Node.AddPose(); ReconstructNode(); FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprint()); }
void UAnimGraphNode_BlendListByInt::AddPinToBlendList() { FScopedTransaction Transaction( NSLOCTEXT("A3Nodes", "AddBlendListPin", "AddBlendListPin") ); Modify(); Node.AddPose(); ReconstructNode(); FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprint()); }
void UK2Node_SwitchInteger::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) { FName PropertyName = (PropertyChangedEvent.Property != NULL) ? PropertyChangedEvent.Property->GetFName() : NAME_None; if (PropertyName == TEXT("StartIndex")) { ReconstructNode(); } Super::PostEditChangeProperty(PropertyChangedEvent); }
void UK2Node_FormatText::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) { FName PropertyName = (PropertyChangedEvent.Property != NULL) ? PropertyChangedEvent.Property->GetFName() : NAME_None; if (PropertyName == TEXT("PinNames")) { ReconstructNode(); GetGraph()->NotifyGraphChanged(); } Super::PostEditChangeProperty(PropertyChangedEvent); }
void UAnimGraphNode_BlendListBase::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) { FName PropertyName = (PropertyChangedEvent.Property != NULL) ? PropertyChangedEvent.Property->GetFName() : NAME_None; if ((PropertyName == TEXT("Node"))) { ReconstructNode(); } Super::PostEditChangeProperty(PropertyChangedEvent); }
void UK2Node_FormatText::SwapArguments(int32 InIndexA, int32 InIndexB) { check(InIndexA < PinNames.Num()); check(InIndexB < PinNames.Num()); PinNames.Swap(InIndexA, InIndexB); ReconstructNode(); GetGraph()->NotifyGraphChanged(); FBlueprintEditorUtils::MarkBlueprintAsModified(GetBlueprint()); }
void UK2Node_CustomEvent::AutowireNewNode(UEdGraphPin* FromPin) { Super::AutowireNewNode(FromPin); if (auto DelegateOutPin = FindPin(DelegateOutputName)) { if (DelegateOutPin->LinkedTo.Num()) { ReconstructNode(); } } }
void UK2Node_DynamicCast::SetPurity(bool bNewPurity) { if (bNewPurity != bIsPureCast) { bIsPureCast = bNewPurity; bool const bHasBeenConstructed = (Pins.Num() > 0); if (bHasBeenConstructed) { ReconstructNode(); } } }
void UK2Node_VariableGet::SetPurity(bool bNewPurity) { if (bNewPurity != bIsPureGet) { bIsPureGet = bNewPurity; bool const bHasBeenConstructed = (Pins.Num() > 0); if (bHasBeenConstructed) { ReconstructNode(); } } }
void UGameplayTagsK2Node_MultiCompareBase::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) { // If the number of pins is changed mark the node as dirty and reconstruct const FName PropertyName = (PropertyChangedEvent.Property ? PropertyChangedEvent.Property->GetFName() : NAME_None); if (PropertyName == GET_MEMBER_NAME_CHECKED(UGameplayTagsK2Node_MultiCompareBase, NumberOfPins)) { if (NumberOfPins < 0) { NumberOfPins = 1; } ReconstructNode(); GetGraph()->NotifyGraphChanged(); } Super::PostEditChangeProperty(PropertyChangedEvent); }
void UK2Node_MacroInstance::NodeConnectionListChanged() { Super::NodeConnectionListChanged(); if (bReconstructNode) { ReconstructNode(); UBlueprint* const Blueprint = GetBlueprint(); if (Blueprint && !Blueprint->bBeingCompiled) { FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint); Blueprint->BroadcastChanged(); } } }
void UAnimGraphNode_BlendListByEnum::ExposeEnumElementAsPin(FName EnumElementName) { if (!VisibleEnumEntries.Contains(EnumElementName)) { FScopedTransaction Transaction( LOCTEXT("ExposeElement", "ExposeElement") ); Modify(); VisibleEnumEntries.Add(EnumElementName); Node.AddPose(); ReconstructNode(); FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprint()); } }
void UK2Node_SwitchName::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) { bool bIsDirty = false; FName PropertyName = (PropertyChangedEvent.Property != NULL) ? PropertyChangedEvent.Property->GetFName() : NAME_None; if (PropertyName == TEXT("PinNames")) { bIsDirty = true; } if (bIsDirty) { ReconstructNode(); GetGraph()->NotifyGraphChanged(); } Super::PostEditChangeProperty(PropertyChangedEvent); }
void UVaRest_BreakJson::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) { bool bIsDirty = false; FName PropertyName = (PropertyChangedEvent.Property != NULL) ? PropertyChangedEvent.Property->GetFName() : NAME_None; if (true || PropertyName == TEXT("Outputs")) { bIsDirty = true; } if (bIsDirty) { ReconstructNode(); GetGraph()->NotifyGraphChanged(); } Super::PostEditChangeProperty(PropertyChangedEvent); }
void UK2Node_Select::AddOptionPinToNode() { const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); // Increment the pin count NumOptionPins++; // We guarantee at least 2 options by default and since we just increased the count // to more than 2, we need to make sure we're now dealing with an index for selection // instead of the default boolean check if (IndexPinType.PinCategory == K2Schema->PC_Boolean) { IndexPinType.PinCategory = K2Schema->PC_Int; GetIndexPin()->BreakAllPinLinks(); } // We will let the AllocateDefaultPins call handle the actual addition via ReconstructNode ReconstructNode(); }
void UK2Node_SetFieldsInStruct::RestoreAllPins() { bool bWasChanged = false; for (FOptionalPinFromProperty& OptionalProperty : ShowPinForProperties) { if (!OptionalProperty.bShowPin) { bWasChanged = true; OptionalProperty.bShowPin = true; } } if (bWasChanged) { ReconstructNode(); } }
void UAnimGraphNode_LayeredBoneBlend::RemovePinFromBlendByFilter(UEdGraphPin* Pin) { FScopedTransaction Transaction( NSLOCTEXT("A3Nodes", "RemovePinFromBlend", "RemovePinFromBlendByFilter") ); Modify(); UProperty* AssociatedProperty; int32 ArrayIndex; GetPinAssociatedProperty(GetFNodeType(), Pin, /*out*/ AssociatedProperty, /*out*/ ArrayIndex); if (ArrayIndex != INDEX_NONE) { //@TODO: ANIMREFACTOR: Need to handle moving pins below up correctly // setting up removed pins info RemovedPinArrayIndex = ArrayIndex; Node.RemovePose(ArrayIndex); ReconstructNode(); FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprint()); } }
void UK2Node_FunctionResult::SyncWithPrimaryResultNode() { UK2Node_FunctionResult* PrimaryNode = nullptr; TArray<UK2Node_FunctionResult*> AllResultNodes = GetAllResultNodes(); for (auto ResultNode : AllResultNodes) { if (ResultNode && (this != ResultNode)) { PrimaryNode = ResultNode; break; } } if (PrimaryNode) { TArray< TSharedPtr<FUserPinInfo> > UDPinsCopy = UserDefinedPins; for (auto UDPin : UDPinsCopy) { RemoveUserDefinedPin(UDPin); } UserDefinedPins.Empty(); SignatureClass = PrimaryNode->SignatureClass; SignatureName = PrimaryNode->SignatureName; bIsEditable = PrimaryNode->bIsEditable; for (auto UDPin : PrimaryNode->UserDefinedPins) { if (UDPin.IsValid()) { TSharedPtr<FUserPinInfo> NewPinInfo = MakeShareable(new FUserPinInfo()); NewPinInfo->PinName = UDPin->PinName; NewPinInfo->PinType = UDPin->PinType; NewPinInfo->DesiredPinDirection = UDPin->DesiredPinDirection; UserDefinedPins.Add(NewPinInfo); } } ReconstructNode(); } }
void UAnimGraphNode_BlendListByInt::RemovePinFromBlendList(UEdGraphPin* Pin) { FScopedTransaction Transaction( NSLOCTEXT("A3Nodes", "RemoveBlendListPin", "RemoveBlendListPin") ); Modify(); UProperty* AssociatedProperty; int32 ArrayIndex; GetPinAssociatedProperty(GetFNodeType(), Pin, /*out*/ AssociatedProperty, /*out*/ ArrayIndex); if (ArrayIndex != INDEX_NONE) { //@TODO: ANIMREFACTOR: Need to handle moving pins below up correctly // setting up removed pins info RemovedPinArrayIndex = ArrayIndex; Node.RemovePose(ArrayIndex); // removes the selected pin and related properties in reconstructNode() // @TODO: Considering passing "RemovedPinArrayIndex" to ReconstructNode as the argument ReconstructNode(); FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprint()); } }
void UK2Node_FunctionResult::SyncWithEntryNode() { bool bWasSignatureMismatched = false; if (UEdGraph* Graph = GetGraph()) { for (UEdGraphNode* Node : Graph->Nodes) { if (UK2Node_FunctionEntry* EntryNode = Cast<UK2Node_FunctionEntry>(Node)) { bWasSignatureMismatched = (EntryNode->SignatureClass != SignatureClass) || (EntryNode->SignatureName != SignatureName) || (!EntryNode->bIsEditable && UserDefinedPins.Num() > 0); // If the entry is editable, so is the result bIsEditable = EntryNode->bIsEditable; SignatureClass = EntryNode->SignatureClass; SignatureName = EntryNode->SignatureName; break; } } } if (bWasSignatureMismatched) { // to handle pasting of a result node from one function into another; // if the new function is not editable (like for one that is overidden), // then we shouldn't have userdefined pins if (!bIsEditable) { // iterate backwards so we can remove items from the list as we go for (int32 UserPinIndex = UserDefinedPins.Num() - 1; UserPinIndex >= 0; --UserPinIndex) { RemoveUserDefinedPin(UserDefinedPins[UserPinIndex]); } } ReconstructNode(); } }
void UK2Node_Select::PinTypeChanged(UEdGraphPin* Pin) { const UEdGraphSchema_K2* Schema = GetDefault<UEdGraphSchema_K2>(); if (Pin == GetIndexPin()) { if (IndexPinType != Pin->PinType) { IndexPinType = Pin->PinType; if (IndexPinType.PinSubCategoryObject.IsValid()) { SetEnum(Cast<UEnum>(IndexPinType.PinSubCategoryObject.Get())); } else if (Enum) { SetEnum(NULL); } // Remove all but two options if we switched to a bool index if (IndexPinType.PinCategory == Schema->PC_Boolean) { if (NumOptionPins > 2) { NumOptionPins = 2; bReconstructNode = true; } } // Reset the default value Schema->SetPinDefaultValueBasedOnType(Pin); } } else { // Set the return value UEdGraphPin* ReturnPin = GetReturnValuePin(); if (ReturnPin->PinType != Pin->PinType) { ReturnPin->PinType = Pin->PinType; Schema->SetPinDefaultValueBasedOnType(ReturnPin); } // Set the options TArray<UEdGraphPin*> OptionPins; GetOptionPins(OptionPins); for (auto It = OptionPins.CreateConstIterator(); It; It++) { UEdGraphPin* OptionPin = (*It); if (OptionPin->PinType != Pin->PinType || OptionPin == Pin) { OptionPin->PinType = Pin->PinType; Schema->SetPinDefaultValueBasedOnType(OptionPin); } } } // Reconstruct the node since the options could change if (bReconstructNode) { ReconstructNode(); } // Let the graph know to refresh GetGraph()->NotifyGraphChanged(); UBlueprint* Blueprint = GetBlueprint(); if(!Blueprint->bBeingCompiled) { FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint); Blueprint->BroadcastChanged(); } }
void UAnimGraphNode_TwoBoneIK::CustomizeDetails(class IDetailLayoutBuilder& DetailBuilder) { // initialize just once if (!TwoBoneIKDelegate.IsValid()) { TwoBoneIKDelegate = MakeShareable(new FTwoBoneIKDelegate()); } EBoneControlSpace Space = Node.EffectorLocationSpace; const FString TakeRotationPropName = FString::Printf(TEXT("Node.%s"), GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_TwoBoneIK, bTakeRotationFromEffectorSpace)); const FString MaintainEffectorPropName = FString::Printf(TEXT("Node.%s"), GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_TwoBoneIK, bMaintainEffectorRelRot)); const FString EffectorBoneName = FString::Printf(TEXT("Node.%s"), GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_TwoBoneIK, EffectorSpaceBoneName)); const FString EffectorLocationPropName = FString::Printf(TEXT("Node.%s"), GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_TwoBoneIK, EffectorLocation)); if (Space == BCS_BoneSpace || Space == BCS_ParentBoneSpace) { IDetailCategoryBuilder& IKCategory = DetailBuilder.EditCategory("IK"); IDetailCategoryBuilder& EffectorCategory = DetailBuilder.EditCategory("EndEffector"); TSharedPtr<IPropertyHandle> PropertyHandle; PropertyHandle = DetailBuilder.GetProperty(*TakeRotationPropName, GetClass()); EffectorCategory.AddProperty(PropertyHandle); PropertyHandle = DetailBuilder.GetProperty(*MaintainEffectorPropName, GetClass()); EffectorCategory.AddProperty(PropertyHandle); PropertyHandle = DetailBuilder.GetProperty(*EffectorBoneName, GetClass()); EffectorCategory.AddProperty(PropertyHandle); } else // hide all properties in EndEffector category { TSharedPtr<IPropertyHandle> PropertyHandle = DetailBuilder.GetProperty(*EffectorLocationPropName, GetClass()); DetailBuilder.HideProperty(PropertyHandle); PropertyHandle = DetailBuilder.GetProperty(*TakeRotationPropName, GetClass()); DetailBuilder.HideProperty(PropertyHandle); PropertyHandle = DetailBuilder.GetProperty(*MaintainEffectorPropName, GetClass()); DetailBuilder.HideProperty(PropertyHandle); PropertyHandle = DetailBuilder.GetProperty(*EffectorBoneName, GetClass()); DetailBuilder.HideProperty(PropertyHandle); } Space = Node.JointTargetLocationSpace; bool bPinVisibilityChanged = false; const FString JointTargetSpaceBoneName = FString::Printf(TEXT("Node.%s"), GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_TwoBoneIK, JointTargetSpaceBoneName)); const FString JointTargetLocation = FString::Printf(TEXT("Node.%s"), GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_TwoBoneIK, JointTargetLocation)); if (Space == BCS_BoneSpace || Space == BCS_ParentBoneSpace) { IDetailCategoryBuilder& IKCategory = DetailBuilder.EditCategory("IK"); IDetailCategoryBuilder& EffectorCategory = DetailBuilder.EditCategory("JointTarget"); TSharedPtr<IPropertyHandle> PropertyHandle; PropertyHandle = DetailBuilder.GetProperty(*JointTargetSpaceBoneName, GetClass()); EffectorCategory.AddProperty(PropertyHandle); bPinVisibilityChanged = SetPinsVisibility(true); } else // hide all properties in JointTarget category except for JointTargetLocationSpace { TSharedPtr<IPropertyHandle> PropertyHandle = DetailBuilder.GetProperty(*JointTargetLocation, GetClass()); DetailBuilder.HideProperty(PropertyHandle); PropertyHandle = DetailBuilder.GetProperty(*JointTargetSpaceBoneName, GetClass()); DetailBuilder.HideProperty(PropertyHandle); bPinVisibilityChanged = SetPinsVisibility(false); } const FString EffectorLocationSpace = FString::Printf(TEXT("Node.%s"), GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_TwoBoneIK, EffectorLocationSpace)); const FString JointTargetLocationSpace = FString::Printf(TEXT("Node.%s"), GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_TwoBoneIK, JointTargetLocationSpace)); // refresh UIs when bone space is changed TSharedRef<IPropertyHandle> EffectorLocHandle = DetailBuilder.GetProperty(*EffectorLocationSpace, GetClass()); if (EffectorLocHandle->IsValidHandle()) { FSimpleDelegate UpdateEffectorSpaceDelegate = FSimpleDelegate::CreateSP(TwoBoneIKDelegate.Get(), &FTwoBoneIKDelegate::UpdateLocationSpace, &DetailBuilder); EffectorLocHandle->SetOnPropertyValueChanged(UpdateEffectorSpaceDelegate); } TSharedRef<IPropertyHandle> JointTragetLocHandle = DetailBuilder.GetProperty(*JointTargetLocationSpace, GetClass()); if (JointTragetLocHandle->IsValidHandle()) { FSimpleDelegate UpdateJointSpaceDelegate = FSimpleDelegate::CreateSP(TwoBoneIKDelegate.Get(), &FTwoBoneIKDelegate::UpdateLocationSpace, &DetailBuilder); JointTragetLocHandle->SetOnPropertyValueChanged(UpdateJointSpaceDelegate); } // reconstruct node for showing/hiding Pins if (bPinVisibilityChanged) { ReconstructNode(); } }
void UK2Node_FunctionResult::SyncWithPrimaryResultNode() { UK2Node_FunctionResult* PrimaryNode = nullptr; TArray<UK2Node_FunctionResult*> AllResultNodes = GetAllResultNodes(); for (auto ResultNode : AllResultNodes) { if (ResultNode && (this != ResultNode)) { PrimaryNode = ResultNode; break; } } if (PrimaryNode) { SignatureClass = PrimaryNode->SignatureClass; SignatureName = PrimaryNode->SignatureName; bIsEditable = PrimaryNode->bIsEditable; // Temporary array that will contain our list of Old Pins that are no longer part of the return signature TArray< TSharedPtr<FUserPinInfo> > OldPins = UserDefinedPins; // Temporary array that will contain our list of Signature Pins that need to be added TArray< TSharedPtr<FUserPinInfo> > SignaturePins = PrimaryNode->UserDefinedPins; for (int OldIndex = OldPins.Num() - 1; OldIndex >= 0; --OldIndex) { TSharedPtr<FUserPinInfo> OldPin = OldPins[OldIndex]; if (!OldPin.IsValid()) { OldPins.RemoveAt(OldIndex); } else { for (int SignatureIndex = SignaturePins.Num() - 1; SignatureIndex >= 0; --SignatureIndex) { TSharedPtr<FUserPinInfo> SignaturePin = SignaturePins[SignatureIndex]; if (!SignaturePin.IsValid()) { SignaturePins.RemoveAt(SignatureIndex); } else if (OldPin->PinName == SignaturePin->PinName && OldPin->PinType == SignaturePin->PinType && OldPin->DesiredPinDirection == SignaturePin->DesiredPinDirection) { // We have a match between our Signature pins and our Old Pins, // so we can leave the old pin as is by removing it from both temporary lists. OldPins.RemoveAt(OldIndex); SignaturePins.RemoveAt(SignatureIndex); break; } } } } // Remove old pins that are not part of the primary node signature for (TSharedPtr<FUserPinInfo> OldPinToRemove : OldPins) { RemoveUserDefinedPin(OldPinToRemove); } // Add pins that don't exist yet but are part of the primary node signature for (TSharedPtr<FUserPinInfo> SignaturePinToAdd : SignaturePins) { TSharedPtr<FUserPinInfo> NewPinInfo = MakeShareable(new FUserPinInfo()); NewPinInfo->PinName = SignaturePinToAdd->PinName; NewPinInfo->PinType = SignaturePinToAdd->PinType; NewPinInfo->DesiredPinDirection = SignaturePinToAdd->DesiredPinDirection; UserDefinedPins.Add(NewPinInfo); } ReconstructNode(); } }