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 { RewireOldPinsToNewPins(OldPins, Pins); } if (bDestroyOldPins) { DestroyPinList(OldPins); } // Let subclasses do any additional work PostReconstructNode(); GetGraph()->NotifyGraphChanged(); }
FBlueprintCompiledStatement* FKCHandler_MathExpression::GenerateFunctionRPN(UEdGraphNode* CurrentNode, FKismetFunctionContext& Context, UK2Node_MathExpression& MENode, FBPTerminal* ResultTerm, TMap<UEdGraphPin*, UEdGraphPin*>& InnerToOuterInput) { UK2Node_CallFunction* CallFunctionNode = Cast<UK2Node_CallFunction>(CurrentNode); UFunction* Function = CallFunctionNode ? CallFunctionNode->GetTargetFunction() : nullptr; if (!CanBeCalledByMathExpression(Function)) { CompilerContext.MessageLog.Error(*FString::Printf(*LOCTEXT("WrongFunction_Error", "Function '%s' cannot be called inside Math Expression @@ - @@").ToString(), *GetNameSafe(Function)), CallFunctionNode, &MENode); return nullptr; } FBlueprintCompiledStatement* NewDetachedStatement = new FBlueprintCompiledStatement(); FBlueprintCompiledStatement& Statement = *NewDetachedStatement; Statement.FunctionToCall = Function; Statement.FunctionContext = nullptr; Statement.Type = KCST_CallFunction; Statement.LHS = ResultTerm; // required only for the first node check(CallFunctionNode); TArray<FBPTerminal*> RHSTerms; for (TFieldIterator<UProperty> It(Function); It && (It->PropertyFlags & CPF_Parm); ++It) { UProperty* Property = *It; if (Property && !Property->HasAnyPropertyFlags(CPF_ReturnParm | CPF_OutParm)) { UEdGraphPin* PinToTry = nullptr; { UEdGraphPin* PinMatch = CallFunctionNode->FindPin(Property->GetName()); const bool bGoodPin = PinMatch && FKismetCompilerUtilities::IsTypeCompatibleWithProperty(PinMatch, Property, CompilerContext.MessageLog, CompilerContext.GetSchema(), Context.NewClass); PinToTry = bGoodPin ? FEdGraphUtilities::GetNetFromPin(PinMatch) : nullptr; } FBPTerminal* RHSTerm = nullptr; { UEdGraphPin** OuterInputPtr = PinToTry ? InnerToOuterInput.Find(PinToTry) : nullptr; UEdGraphPin* OuterInputNet = (OuterInputPtr && *OuterInputPtr) ? FEdGraphUtilities::GetNetFromPin(*OuterInputPtr) : nullptr; FBPTerminal** OuterTerm = OuterInputNet ? Context.NetMap.Find(OuterInputNet) : nullptr; // Input is an outer term if (OuterTerm && *OuterTerm) { RHSTerm = *OuterTerm; } } if (!RHSTerm) { FBPTerminal** Term = PinToTry ? Context.NetMap.Find(PinToTry) : nullptr; const bool bValidTerm = Term && *Term; // Input is a literal term // Input is a variable if (bValidTerm && ((*Term)->bIsLiteral || (*Term)->AssociatedVarProperty)) { RHSTerm = *Term; } // Input is an InlineGeneratedParameter else if (bValidTerm) { ensure(!(*Term)->InlineGeneratedParameter); UEdGraphNode* SourceNode = PinToTry ? PinToTry->GetOwningNodeUnchecked() : nullptr; FBlueprintCompiledStatement* InlineGeneratedParameterStatement = GenerateFunctionRPN(SourceNode, Context, MENode, nullptr, InnerToOuterInput); if (InlineGeneratedParameterStatement) { Context.AllGeneratedStatements.Add(InlineGeneratedParameterStatement); RHSTerm = *Term; RHSTerm->InlineGeneratedParameter = InlineGeneratedParameterStatement; } } } if (RHSTerm) { RHSTerms.Add(RHSTerm); } else { CompilerContext.MessageLog.Error(*FString::Printf(*LOCTEXT("FindPinParameter_Error", "Could not find a pin for the parameter %s of %s on @@").ToString(), *GetNameSafe(Property), *GetNameSafe(Function)), CallFunctionNode); } } } Statement.RHS = RHSTerms; return &Statement; }
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(); }