UEdGraphNode* FEdGraphSchemaAction_K2AddCallOnVariable::PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, bool bSelectNewNode/* = true*/) { const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); // Snap the node placement location to the grid, ensures calculations later match up better FVector2D LocalLocation; LocalLocation.X = FMath::GridSnap( Location.X, SNAP_GRID ); LocalLocation.Y = FMath::GridSnap( Location.Y, SNAP_GRID ); // First use the base functionality to spawn the 'call function' node FVector2D TempLocation = LocalLocation; UEdGraphNode* CallNode = FEdGraphSchemaAction_K2NewNode::PerformAction(ParentGraph, FromPin, TempLocation, bSelectNewNode); // this is the guesstimate of the function node's height, snapped to grid units const float FunctionNodeHeight = FMath::GridSnap( TempLocation.Y - LocalLocation.Y, SNAP_GRID ); // this is roughly the middle of the function node height const float FunctionNodeMidY = LocalLocation.Y + FunctionNodeHeight * 0.5f; // this is the offset up from the mid point at which we start placing nodes const float StartYOffset = -NodeLiteralHeight * 0.5f; // The Y location we start placing nodes from const float ReferencedNodesPlacementYLocation = FunctionNodeMidY + StartYOffset; // Now we need to create the variable literal to wire up if(VariableName != NAME_None) { UK2Node_VariableGet* GetVarNode = NewObject<UK2Node_VariableGet>(ParentGraph); ParentGraph->AddNode(GetVarNode, false, bSelectNewNode); GetVarNode->SetFlags(RF_Transactional); GetVarNode->VariableReference.SetSelfMember(VariableName); GetVarNode->AllocateDefaultPins(); GetVarNode->NodePosX = LocalLocation.X - FunctionNodeLiteralReferencesXOffset; GetVarNode->NodePosY = ReferencedNodesPlacementYLocation; GetVarNode->SnapToGrid(SNAP_GRID); // Connect the literal out to the self of the call UEdGraphPin* LiteralOutput = GetVarNode->GetValuePin(); UEdGraphPin* CallSelfInput = CallNode->FindPin(K2Schema->PN_Self); if(LiteralOutput != NULL && CallSelfInput != NULL) { LiteralOutput->MakeLinkTo(CallSelfInput); } } return CallNode; }
void UK2Node_Timeline::ExpandForPin(UEdGraphPin* TimelinePin, const FName PropertyName, FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { if (TimelinePin && TimelinePin->LinkedTo.Num() > 0) { UK2Node_VariableGet* GetVarNode = CompilerContext.SpawnIntermediateNode<UK2Node_VariableGet>(this, SourceGraph); GetVarNode->VariableReference.SetSelfMember(PropertyName); GetVarNode->AllocateDefaultPins(); UEdGraphPin* ValuePin = GetVarNode->GetValuePin(); if (NULL != ValuePin) { CompilerContext.MovePinLinksToIntermediate(*TimelinePin, *ValuePin); } else { CompilerContext.MessageLog.Error(*LOCTEXT("ExpandForPin_Error", "ExpandForPin error, no property found for @@").ToString(), TimelinePin); } } }
void FScriptBlueprintCompiler::CreateScriptDefinedFunction(FScriptField& Field) { check(ContextProperty); UScriptBlueprint* Blueprint = ScriptBlueprint(); const FString FunctionName = Field.Name.ToString(); // Create Blueprint Graph which consists of 3 nodes: 'Entry', 'Get Script Context' and 'Call Function' // @todo: once we figure out how to get parameter lists for functions we can add suport for that here UEdGraph* ScriptFunctionGraph = NewObject<UEdGraph>(Blueprint, *FString::Printf(TEXT("%s_Graph"), *FunctionName)); ScriptFunctionGraph->Schema = UEdGraphSchema_K2::StaticClass(); ScriptFunctionGraph->SetFlags(RF_Transient); FKismetFunctionContext* FunctionContext = CreateFunctionContext(); FunctionContext->SourceGraph = ScriptFunctionGraph; FunctionContext->bCreateDebugData = false; UK2Node_FunctionEntry* EntryNode = SpawnIntermediateNode<UK2Node_FunctionEntry>(NULL, ScriptFunctionGraph); EntryNode->CustomGeneratedFunctionName = Field.Name; EntryNode->AllocateDefaultPins(); UK2Node_VariableGet* GetVariableNode = SpawnIntermediateNode<UK2Node_VariableGet>(NULL, ScriptFunctionGraph); GetVariableNode->VariableReference.SetSelfMember(ContextProperty->GetFName()); GetVariableNode->AllocateDefaultPins(); UK2Node_CallFunction* CallFunctionNode = SpawnIntermediateNode<UK2Node_CallFunction>(NULL, ScriptFunctionGraph); CallFunctionNode->FunctionReference.SetExternalMember(TEXT("CallScriptFunction"), ContextProperty->PropertyClass); CallFunctionNode->AllocateDefaultPins(); UEdGraphPin* FunctionNamePin = CallFunctionNode->FindPinChecked(TEXT("FunctionName")); FunctionNamePin->DefaultValue = FunctionName; // Link nodes together UEdGraphPin* ExecPin = Schema->FindExecutionPin(*EntryNode, EGPD_Output); UEdGraphPin* GetVariableOutPin = GetVariableNode->FindPinChecked(ContextProperty->GetName()); UEdGraphPin* CallFunctionPin = Schema->FindExecutionPin(*CallFunctionNode, EGPD_Input); UEdGraphPin* FunctionTargetPin = CallFunctionNode->FindPinChecked(TEXT("self")); ExecPin->MakeLinkTo(CallFunctionPin); GetVariableOutPin->MakeLinkTo(FunctionTargetPin); }
void UK2Node_VariableGet::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { Super::ExpandNode(CompilerContext, SourceGraph); // Do not attempt to expand the node when not a pure get nor when there is no property. Normal compilation error detection will detect the missing property. if (!bIsPureGet && GetPropertyForVariable() != nullptr) { const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); UEdGraphPin* ValuePin = GetValuePin(); // Impure Get nodes convert into three nodes: // 1. A pure Get node // 2. An IsValid node // 3. A Branch node (only impure part // Create the impure Get node UK2Node_VariableGet* VariableGetNode = CompilerContext.SpawnIntermediateNode<UK2Node_VariableGet>(this, SourceGraph); VariableGetNode->VariableReference = VariableReference; VariableGetNode->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(VariableGetNode, this); // Move pin links from Get node we are expanding, to the new pure one we've created CompilerContext.MovePinLinksToIntermediate(*ValuePin, *VariableGetNode->GetValuePin()); if (!VariableReference.IsLocalScope()) { CompilerContext.MovePinLinksToIntermediate(*FindPin(Schema->PN_Self), *VariableGetNode->FindPin(Schema->PN_Self)); } // Create the IsValid node UK2Node_CallFunction* IsValidFunction = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); // Based on if the type is an "Object" or a "Class" changes which function to use if (ValuePin->PinType.PinCategory == UObject::StaticClass()->GetName()) { IsValidFunction->SetFromFunction(UKismetSystemLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UKismetSystemLibrary, IsValid))); } else if (ValuePin->PinType.PinCategory == UClass::StaticClass()->GetName()) { IsValidFunction->SetFromFunction(UKismetSystemLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UKismetSystemLibrary, IsValidClass))); } IsValidFunction->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(IsValidFunction, this); // Connect the value pin from the new Get node to the IsValid UEdGraphPin* ObjectPin = IsValidFunction->Pins[1]; check(ObjectPin->Direction == EGPD_Input); ObjectPin->MakeLinkTo(VariableGetNode->GetValuePin()); // Create the Branch node UK2Node_IfThenElse* BranchNode = CompilerContext.SpawnIntermediateNode<UK2Node_IfThenElse>(this, SourceGraph); BranchNode->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(BranchNode, this); // Connect the bool output pin from IsValid node to the Branch node UEdGraphPin* BoolPin = IsValidFunction->Pins[2]; check(BoolPin->Direction == EGPD_Output); BoolPin->MakeLinkTo(BranchNode->GetConditionPin()); // Connect the Branch node to the input of the impure Get node CompilerContext.MovePinLinksToIntermediate(*GetExecPin(), *BranchNode->GetExecPin()); // Move the two Branch pins to the Branch node CompilerContext.MovePinLinksToIntermediate(*FindPin(Schema->PN_Then), *BranchNode->FindPin(Schema->PN_Then)); CompilerContext.MovePinLinksToIntermediate(*FindPin(Schema->PN_Else), *BranchNode->FindPin(Schema->PN_Else)); BreakAllNodeLinks(); } }
void UK2Node_CallFunctionOnMember::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { // This skips UK2Node_CallFunction::ExpandNode. Instead it spawns a new CallFunction node and does hookup that this is interested in, // and then that CallFunction node will get its own Expansion to handle the parent portions UK2Node::ExpandNode(CompilerContext, SourceGraph); if (CompilerContext.bIsFullCompile) { const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); UFunction* Function = GetTargetFunction(); // Create real 'call function' node. UK2Node_CallFunction* CallFuncNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); CallFuncNode->SetFromFunction(Function); CallFuncNode->AllocateDefaultPins(); UEdGraphPin* CallFuncSelfPin = Schema->FindSelfPin(*CallFuncNode, EGPD_Input); // Now because you can wire multiple variables to a self pin, need to iterate over each one and create a 'get var' node for each UEdGraphPin* SelfPin = Schema->FindSelfPin(*this, EGPD_Input); if(SelfPin != NULL) { if (SelfPin->LinkedTo.Num() == 0) { UK2Node_VariableGet* GetVarNode = CompilerContext.SpawnIntermediateNode<UK2Node_VariableGet>(this, SourceGraph); GetVarNode->VariableReference.SetSelfMember(MemberVariableToCallOn.GetMemberName()); GetVarNode->AllocateDefaultPins(); if (UEdGraphPin* ValuePin = GetVarNode->GetValuePin()) { ValuePin->MakeLinkTo(CallFuncSelfPin); } } else { for (int32 TargetIdx = 0; TargetIdx < SelfPin->LinkedTo.Num(); TargetIdx++) { UEdGraphPin* SourcePin = SelfPin->LinkedTo[TargetIdx]; if (SourcePin != NULL) { // Create 'get var' node to get the member UK2Node_VariableGet* GetVarNode = CompilerContext.SpawnIntermediateNode<UK2Node_VariableGet>(this, SourceGraph); GetVarNode->VariableReference = MemberVariableToCallOn; GetVarNode->AllocateDefaultPins(); UEdGraphPin* VarNodeSelfPin = Schema->FindSelfPin(*GetVarNode, EGPD_Input); if (VarNodeSelfPin != NULL) { VarNodeSelfPin->MakeLinkTo(SourcePin); UEdGraphPin* ValuePin = GetVarNode->GetValuePin(); ValuePin->MakeLinkTo(CallFuncSelfPin); } else { // Failed to find the member to call on for this expansion, so warn about it CompilerContext.MessageLog.Warning(*LOCTEXT("CallFunctionOnInvalidMember_Warning", "Function node @@ called on invalid target member.").ToString(), this); } } } } } // Now move the rest of the connections (including exec connections...) for(int32 SrcPinIdx=0; SrcPinIdx<Pins.Num(); SrcPinIdx++) { UEdGraphPin* SrcPin = Pins[SrcPinIdx]; if(SrcPin != NULL && SrcPin != SelfPin) // check its not the self pin { UEdGraphPin* DestPin = CallFuncNode->FindPin(SrcPin->PinName); if(DestPin != NULL) { CompilerContext.MovePinLinksToIntermediate(*SrcPin, *DestPin); // Source node is assumed to be owner... } } } // Finally, break any remaining links on the 'call func on member' node BreakAllNodeLinks(); } }