void UK2Node_FunctionEntry::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
{
	Super::ExpandNode(CompilerContext, SourceGraph);

	const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema();
	
	UEdGraphPin* OldStartExecPin = nullptr;

	if(Pins[0]->LinkedTo.Num())
	{
		OldStartExecPin = Pins[0]->LinkedTo[0];
	}
	
	UEdGraphPin* LastActiveOutputPin = Pins[0];

	// Only look for FunctionEntry nodes who were duplicated and have a source object
	if ( UK2Node_FunctionEntry* OriginalNode = Cast<UK2Node_FunctionEntry>(CompilerContext.MessageLog.FindSourceObject(this)) )
	{
		check(OriginalNode->GetOuter());

		// Find the associated UFunction
		UFunction* Function = FindField<UFunction>(CompilerContext.Blueprint->SkeletonGeneratedClass, *OriginalNode->GetOuter()->GetName());
		for (TFieldIterator<UProperty> It(Function); It; ++It)
		{
			if (const UProperty* Property = *It)
			{
				for (auto& LocalVar : LocalVariables)
				{
					if (LocalVar.VarName == Property->GetFName() && !LocalVar.DefaultValue.IsEmpty())
					{
						// Add a variable set node for the local variable and hook it up immediately following the entry node or the last added local variable
						UK2Node_VariableSet* VariableSetNode = CompilerContext.SpawnIntermediateNode<UK2Node_VariableSet>(this, SourceGraph);
						VariableSetNode->SetFromProperty(Property, false);
						Schema->ConfigureVarNode(VariableSetNode, LocalVar.VarName, Function, CompilerContext.Blueprint);
						VariableSetNode->AllocateDefaultPins();
						CompilerContext.MessageLog.NotifyIntermediateObjectCreation(VariableSetNode, this);

						if(UEdGraphPin* SetPin = VariableSetNode->FindPin(Property->GetName()))
						{
							if(LocalVar.VarType.bIsArray)
							{
								TSharedPtr<FStructOnScope> StructData = MakeShareable(new FStructOnScope(Function));
								FBlueprintEditorUtils::PropertyValueFromString(Property, LocalVar.DefaultValue, StructData->GetStructMemory());

								// Create a Make Array node to setup the array's defaults
								UK2Node_MakeArray* MakeArray = CompilerContext.SpawnIntermediateNode<UK2Node_MakeArray>(this, SourceGraph);
								MakeArray->AllocateDefaultPins();
								MakeArray->GetOutputPin()->MakeLinkTo(SetPin);
								MakeArray->PostReconstructNode();

								const UArrayProperty* ArrayProperty = Cast<UArrayProperty>(Property);
								check(ArrayProperty);

								FScriptArrayHelper_InContainer ArrayHelper(ArrayProperty, StructData->GetStructMemory());
								FScriptArrayHelper_InContainer DefaultArrayHelper(ArrayProperty, StructData->GetStructMemory());

								uint8* StructDefaults = NULL;
								UStructProperty* StructProperty = dynamic_cast<UStructProperty*>(ArrayProperty->Inner);
								if ( StructProperty != NULL )
								{
									checkSlow(StructProperty->Struct);
									StructDefaults = (uint8*)FMemory::Malloc(StructProperty->Struct->GetStructureSize());
									StructProperty->InitializeValue(StructDefaults);
								}

								// Go through each element in the array to set the default value
								for( int32 ArrayIndex = 0 ; ArrayIndex < ArrayHelper.Num() ; ArrayIndex++ )
								{
									uint8* PropData = ArrayHelper.GetRawPtr(ArrayIndex);

									// Always use struct defaults if the inner is a struct, for symmetry with the import of array inner struct defaults
									uint8* PropDefault = ( StructProperty != NULL ) ? StructDefaults :
										( ( StructData->GetStructMemory() && DefaultArrayHelper.Num() > ArrayIndex ) ? DefaultArrayHelper.GetRawPtr(ArrayIndex) : NULL );

									// Retrieve the element's default value
									FString DefaultValue;
									FBlueprintEditorUtils::PropertyValueToString(ArrayProperty->Inner, PropData, DefaultValue);

									if(ArrayIndex > 0)
									{
										MakeArray->AddInputPin();
									}

									// Add one to the index for the pin to set the default on to skip the output pin
									Schema->TrySetDefaultValue(*MakeArray->Pins[ArrayIndex + 1], DefaultValue);
								}
							}
							else
							{
								// Set the default value
								Schema->TrySetDefaultValue(*SetPin, LocalVar.DefaultValue);
							}
						}

						LastActiveOutputPin->BreakAllPinLinks();
						LastActiveOutputPin->MakeLinkTo(VariableSetNode->Pins[0]);
						LastActiveOutputPin = VariableSetNode->Pins[1];
					}
				}
			}
		}

		// Finally, hook up the last node to the old node the function entry node was connected to
		if(OldStartExecPin)
		{
			LastActiveOutputPin->MakeLinkTo(OldStartExecPin);
		}
	}
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
void UMaterialGraph::LinkGraphNodesFromMaterial()
{
	for (int32 Index = 0; Index < Nodes.Num(); ++Index)
	{
		Nodes[Index]->BreakAllNodeLinks();
	}

	if (RootNode)
	{
		// Use Material Inputs to make GraphNode Connections
		for (int32 Index = 0; Index < MaterialInputs.Num(); ++Index)
		{
			UEdGraphPin* InputPin = RootNode->GetInputPin(Index);
			auto ExpressionInput = MaterialInputs[Index].GetExpressionInput(Material);

			if (ExpressionInput.Expression)
			{
				UMaterialGraphNode* GraphNode = CastChecked<UMaterialGraphNode>(ExpressionInput.Expression->GraphNode);
				InputPin->MakeLinkTo(GraphNode->GetOutputPin(GetValidOutputIndex(&ExpressionInput)));
			}
		}
	}

	for (int32 Index = 0; Index < Material->Expressions.Num(); Index++)
	{
		UMaterialExpression* Expression = Material->Expressions[Index];

		if (Expression)
		{
			const TArray<FExpressionInput*> ExpressionInputs = Expression->GetInputs();
			for (int32 InputIndex = 0; InputIndex < ExpressionInputs.Num(); ++InputIndex)
			{
				UEdGraphPin* InputPin = CastChecked<UMaterialGraphNode>(Expression->GraphNode)->GetInputPin(InputIndex);

				if ( ExpressionInputs[InputIndex]->Expression)
				{
					UMaterialGraphNode* GraphNode = CastChecked<UMaterialGraphNode>(ExpressionInputs[InputIndex]->Expression->GraphNode);
					InputPin->MakeLinkTo(GraphNode->GetOutputPin(GetValidOutputIndex(ExpressionInputs[InputIndex])));
				}
			}
		}
	}

	NotifyGraphChanged();
}
Esempio n. 5
0
void FKCHandler_VariableSet::Transform(FKismetFunctionContext& Context, UEdGraphNode* Node)
{
    // Expands node out to include a (local) call to the RepNotify function if necessary
    UK2Node_VariableSet* SetNotify = Cast<UK2Node_VariableSet>(Node);
    if ((SetNotify != NULL))
    {
        if (SetNotify->ShouldFlushDormancyOnSet())
        {
            // Create CallFuncNode
            UK2Node_CallFunction* CallFuncNode = Node->GetGraph()->CreateBlankNode<UK2Node_CallFunction>();
            CallFuncNode->FunctionReference.SetExternalMember(NAME_FlushNetDormancy, AActor::StaticClass() );
            CallFuncNode->AllocateDefaultPins();

            // Copy self pin
            UEdGraphPin* NewSelfPin = CallFuncNode->FindPinChecked(CompilerContext.GetSchema()->PN_Self);
            UEdGraphPin* OldSelfPin = Node->FindPinChecked(CompilerContext.GetSchema()->PN_Self);
            NewSelfPin->CopyPersistentDataFromOldPin(*OldSelfPin);

            // link new CallFuncNode -> Set Node
            UEdGraphPin* OldExecPin = Node->FindPin(CompilerContext.GetSchema()->PN_Execute);
            check(OldExecPin);

            UEdGraphPin* NewExecPin = CallFuncNode->GetExecPin();
            if (ensure(NewExecPin))
            {
                NewExecPin->CopyPersistentDataFromOldPin(*OldExecPin);
                OldExecPin->BreakAllPinLinks();
                CallFuncNode->GetThenPin()->MakeLinkTo(OldExecPin);
            }
        }

        if (SetNotify->HasLocalRepNotify())
        {
            UK2Node_CallFunction* CallFuncNode = Node->GetGraph()->CreateBlankNode<UK2Node_CallFunction>();
            CallFuncNode->FunctionReference.SetExternalMember(SetNotify->GetRepNotifyName(), SetNotify->GetVariableSourceClass() );
            CallFuncNode->AllocateDefaultPins();

            // Copy self pin
            UEdGraphPin* NewSelfPin = CallFuncNode->FindPinChecked(CompilerContext.GetSchema()->PN_Self);
            UEdGraphPin* OldSelfPin = Node->FindPinChecked(CompilerContext.GetSchema()->PN_Self);
            NewSelfPin->CopyPersistentDataFromOldPin(*OldSelfPin);

            // link Set Node -> new CallFuncNode
            UEdGraphPin* OldThenPin = Node->FindPin(CompilerContext.GetSchema()->PN_Then);
            check(OldThenPin);

            UEdGraphPin* NewThenPin = CallFuncNode->GetThenPin();
            if (ensure(NewThenPin))
            {
                // Link Set Node -> Notify
                NewThenPin->CopyPersistentDataFromOldPin(*OldThenPin);
                OldThenPin->BreakAllPinLinks();
                OldThenPin->MakeLinkTo(CallFuncNode->GetExecPin());
            }
        }
    }
}
UEdGraphNode* FEdGraphSchemaAction_K2AddCallOnActor::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
	UEdGraphNode* CallNode = FEdGraphSchemaAction_K2NewNode::PerformAction(ParentGraph, FromPin, LocalLocation);
	const float FunctionNodeHeightUnsnapped = UEdGraphSchema_K2::EstimateNodeHeight( CallNode );

	// this is the guesstimate of the function node's height, snapped to grid units
	const float FunctionNodeHeight = FMath::GridSnap( FunctionNodeHeightUnsnapped, 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 = (float((LevelActors.Num() > 0) ? LevelActors.Num()-1 : 0) * -NodeLiteralHeight) * 0.5f;
	// The Y location we start placing nodes from
	const float ReferencedNodesPlacementYLocation = FunctionNodeMidY + StartYOffset;

	// Now we need to create the actor literal to wire up
	for ( int32 ActorIndex = 0; ActorIndex < LevelActors.Num(); ActorIndex++ )
	{
		AActor* LevelActor = LevelActors[ActorIndex];

		if(LevelActor != NULL)
		{
			UK2Node_Literal* LiteralNode =  NewObject<UK2Node_Literal>(ParentGraph);
			ParentGraph->AddNode(LiteralNode, false, bSelectNewNode);
			LiteralNode->SetFlags(RF_Transactional);

			LiteralNode->SetObjectRef(LevelActor);
			LiteralNode->AllocateDefaultPins();
			LiteralNode->NodePosX = LocalLocation.X - FunctionNodeLiteralReferencesXOffset;

			// this is the current offset down from the Y start location to place the next node at
			float CurrentNodeOffset = NodeLiteralHeight * float(ActorIndex);
			LiteralNode->NodePosY = ReferencedNodesPlacementYLocation + CurrentNodeOffset;

			LiteralNode->SnapToGrid(SNAP_GRID);

			// Connect the literal out to the self of the call
			UEdGraphPin* LiteralOutput = LiteralNode->GetValuePin();
			UEdGraphPin* CallSelfInput = CallNode->FindPin(K2Schema->PN_Self);
			if(LiteralOutput != NULL && CallSelfInput != NULL)
			{
				LiteralOutput->MakeLinkTo(CallSelfInput);
			}
		}
	}

	return CallNode;
}
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);
}
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;
}
Esempio n. 9
0
bool UK2Node_DynamicCast::ReconnectPureExecPins(TArray<UEdGraphPin*>& OldPins)
{
	if (bIsPureCast)
	{
		// look for an old exec pin
		const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
		UEdGraphPin* PinExec = nullptr;
		for (UEdGraphPin* Pin : OldPins)
		{
			if (Pin->PinName == K2Schema->PN_Execute)
			{
				PinExec = Pin;
				break;
			}
		}
		if (PinExec)
		{
			// look for old then pin
			UEdGraphPin* PinThen = nullptr;
			for (UEdGraphPin* Pin : OldPins)
			{
				if (Pin->PinName == K2Schema->PN_Then)
				{
					PinThen = Pin;
					break;
				}
			}
			if (PinThen)
			{
				// reconnect all incoming links to old exec pin to the far end of the old then pin.
				if (PinThen->LinkedTo.Num() > 0)
				{
					UEdGraphPin* PinThenLinked = PinThen->LinkedTo[0];
					while (PinExec->LinkedTo.Num() > 0)
					{
						UEdGraphPin* PinExecLinked = PinExec->LinkedTo[0];
						PinExecLinked->BreakLinkTo(PinExec);
						PinExecLinked->MakeLinkTo(PinThenLinked);
					}
					return true;
				}
			}
		}
	}
	return false;
}
void USoundClassGraph::RefreshGraphLinks()
{
	Modify();

	for (int32 NodeIndex = 0; NodeIndex < Nodes.Num(); NodeIndex++)
	{
		USoundClassGraphNode* Node = CastChecked<USoundClassGraphNode>(Nodes[NodeIndex]);

		if (!Node->CheckRepresentsSoundClass())
		{
			UEdGraphPin* ChildPin = Node->GetChildPin();

			Node->Modify();

			ChildPin->BreakAllPinLinks();

			for (int32 ChildIndex = 0; ChildIndex < Node->SoundClass->ChildClasses.Num(); ChildIndex++)
			{
				USoundClass* ChildClass = Node->SoundClass->ChildClasses[ChildIndex];

				if (ChildClass)
				{
					USoundClassGraphNode* ChildNode = FindExistingNode(ChildClass);

					if (!ChildNode)
					{
						// New Child not yet represented on graph
						ConstructNodes(ChildClass, Node->NodePosX+400, Node->NodePosY);
						ChildNode = FindExistingNode(ChildClass);
					}

					ChildPin->MakeLinkTo(ChildNode->GetParentPin());
				}
			}

			Node->PostEditChange();
		}
	}

	NotifyGraphChanged();
}
UObject* UNiagaraScriptFactoryNew::FactoryCreateNew(UClass* Class,UObject* InParent,FName Name,EObjectFlags Flags,UObject* Context,FFeedbackContext* Warn)
{
	check(Class->IsChildOf(UNiagaraScript::StaticClass()));

	// First allocate runtime script 
	UNiagaraScript* NewScript = ConstructObject<UNiagaraScript>(Class, InParent, Name, Flags);
	if(NewScript != NULL)
	{
		// Then allocate editor-only 'source' object
		UNiagaraScriptSource* Source = ConstructObject<UNiagaraScriptSource>(UNiagaraScriptSource::StaticClass(), NewScript, NAME_None, RF_Transactional);
		if(Source)
		{
			// Create 'update graph'
			UNiagaraGraph* CreatedGraph  = ConstructObject<UNiagaraGraph>(UNiagaraGraph::StaticClass(), Source, NAME_None, RF_Transactional);
			Source->UpdateGraph = CreatedGraph;

			FGraphNodeCreator<UNiagaraNodeOutputUpdate> OutputNodeCreator(*CreatedGraph);
			UNiagaraNodeOutputUpdate* OutputNode = OutputNodeCreator.CreateNode();
			OutputNodeCreator.Finalize();

			FGraphNodeCreator<UNiagaraNodeGetAttr> TimeNodeCreator(*CreatedGraph);
			UNiagaraNodeGetAttr* DeltaTimeNode = TimeNodeCreator.CreateNode();
			DeltaTimeNode->AttrName = FName(TEXT("DeltaTime"));
			TimeNodeCreator.Finalize();

			UEdGraphPin* DeltaTimePin = DeltaTimeNode->FindPinChecked(DeltaTimeNode->AttrName.ToString());

			TArray<FName> OutputNames;
			Source->GetUpdateOutputs(OutputNames);

			// Simple Euler integration.
			for(int32 i=0; i<3; i++)
			{
				FGraphNodeCreator<UNiagaraNodeGetAttr> PosNodeCreator(*CreatedGraph);
				UNiagaraNodeGetAttr* PosAttrNode = PosNodeCreator.CreateNode();
				PosAttrNode->AttrName = OutputNames[i];
				PosNodeCreator.Finalize();

				FGraphNodeCreator<UNiagaraNodeGetAttr> VelNodeCreator(*CreatedGraph);
				UNiagaraNodeGetAttr* VelAttrNode = VelNodeCreator.CreateNode();
				VelAttrNode->AttrName = OutputNames[i+3];
				VelNodeCreator.Finalize();


				UEdGraphPin* PosAttrOutputPin = PosAttrNode->FindPinChecked(OutputNames[i].ToString());
				UEdGraphPin* VelAttrOutputPin = VelAttrNode->FindPinChecked(OutputNames[i+3].ToString());
				UEdGraphPin* OutputPin = OutputNode->FindPinChecked(OutputNames[i].ToString());

				UNiagaraNodeOp* MulNode = NULL;
				{
					FGraphNodeCreator<UNiagaraNodeOp> NodeCreator(*CreatedGraph);
					MulNode = NodeCreator.CreateNode();
					MulNode->OpIndex = VectorVM::EOp::mul;
					NodeCreator.Finalize();

					UEdGraphPin* APin = MulNode->FindPinChecked(TEXT("A"));
					UEdGraphPin* BPin = MulNode->FindPinChecked(TEXT("B"));

					APin->MakeLinkTo(VelAttrOutputPin);
					BPin->MakeLinkTo(DeltaTimePin);
				}

				{
					FGraphNodeCreator<UNiagaraNodeOp> NodeCreator(*CreatedGraph);
					UNiagaraNodeOp* AddNode = NodeCreator.CreateNode();
					AddNode->OpIndex = VectorVM::EOp::add;
					NodeCreator.Finalize();

					UEdGraphPin* APin = AddNode->FindPinChecked(TEXT("A"));
					UEdGraphPin* BPin = AddNode->FindPinChecked(TEXT("B"));
					UEdGraphPin* AddResultPin = AddNode->FindPinChecked(TEXT("Result"));
					UEdGraphPin* MulResultPin = MulNode->FindPinChecked(TEXT("Result"));

					APin->MakeLinkTo(PosAttrOutputPin);
					BPin->MakeLinkTo(MulResultPin);
					OutputPin->MakeLinkTo(AddResultPin);
				}
			}

			// Update relative time.
			{
				FGraphNodeCreator<UNiagaraNodeGetAttr> RelTimeNodeCreator(*Source->UpdateGraph);
				UNiagaraNodeGetAttr* RelTimeAttrNode = RelTimeNodeCreator.CreateNode();
				RelTimeAttrNode->AttrName = FName(TEXT("RelativeTime"));
				RelTimeNodeCreator.Finalize();

				FGraphNodeCreator<UNiagaraNodeOp> MadNodeCreator(*Source->UpdateGraph);
				UNiagaraNodeOp* MadNode = MadNodeCreator.CreateNode();
				MadNode->OpIndex = VectorVM::EOp::mad;
				MadNodeCreator.Finalize();

				MadNode->FindPinChecked(TEXT("A"))->MakeLinkTo(DeltaTimePin);
				MadNode->FindPinChecked(TEXT("B"))->DefaultValue = TEXT("0.2");
				MadNode->FindPinChecked(TEXT("C"))->MakeLinkTo(RelTimeAttrNode->FindPinChecked(TEXT("RelativeTime")));

				OutputNode->FindPinChecked(TEXT("RelativeTime"))->MakeLinkTo(MadNode->FindPinChecked(TEXT("Result")));
			}

			// Set pointer in script to source
			NewScript->Source = Source;

			FNiagaraEditorModule& NiagaraEditorModule = FModuleManager::Get().LoadModuleChecked<FNiagaraEditorModule>(TEXT("NiagaraEditor"));
			NiagaraEditorModule.CompileScript(NewScript);
		}
	}

	return NewScript;
}
Esempio n. 12
0
void UK2Node_Message::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
{
	Super::ExpandNode(CompilerContext, SourceGraph);

	const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema();

	UEdGraphPin* ExecPin = Schema->FindExecutionPin(*this, EGPD_Input);
	const bool bExecPinConnected = ExecPin && (ExecPin->LinkedTo.Num() > 0);
	UEdGraphPin* ThenPin = Schema->FindExecutionPin(*this, EGPD_Output);
	const bool bThenPinConnected = ThenPin && (ThenPin->LinkedTo.Num() > 0);

	// Skip ourselves if our exec isn't wired up
	if (bExecPinConnected)
	{
		// Make sure our interface is valid
		if (FunctionReference.GetMemberParentClass(this) == NULL)
		{
			CompilerContext.MessageLog.Error(*FString::Printf(*LOCTEXT("MessageNodeInvalid_Error", "Message node @@ has an invalid interface.").ToString()), this);
			return;
		}

		UFunction* MessageNodeFunction = GetTargetFunction();
		if (MessageNodeFunction == NULL)
		{
			//@TODO: Why do this here in teh compiler, it's already done on AllocateDefaultPins() during on-load node reconstruction
			MessageNodeFunction = Cast<UFunction>(UK2Node::FindRemappedField(FunctionReference.GetMemberParentClass(this), FunctionReference.GetMemberName()));
		}

		if (MessageNodeFunction == NULL)
		{
			CompilerContext.MessageLog.Error(*FString::Printf(*LOCTEXT("MessageNodeInvalidFunction_Error", "Unable to find function with name %s for Message node @@.").ToString(), *(FunctionReference.GetMemberName().ToString())), this);
			return;
		}

		// Check to make sure we have a target
		UEdGraphPin* MessageSelfPin = Schema->FindSelfPin(*this, EGPD_Input);
		if( !MessageSelfPin || MessageSelfPin->LinkedTo.Num() == 0 )
		{
			CompilerContext.MessageLog.Error(*FString::Printf(*LOCTEXT("MessageNodeSelfPin_Error", "Message node @@ must have a valid target or reference to self.").ToString()), this);
			return;
		}

		// First, create an internal cast-to-interface node
		UK2Node_DynamicCast* CastToInterfaceNode = CompilerContext.SpawnIntermediateNode<UK2Node_DynamicCast>(this, SourceGraph);
		CastToInterfaceNode->TargetType = MessageNodeFunction->GetOuterUClass();
		CastToInterfaceNode->SetPurity(false);
		CastToInterfaceNode->AllocateDefaultPins();

		UEdGraphPin* CastToInterfaceResultPin = CastToInterfaceNode->GetCastResultPin();
		if( !CastToInterfaceResultPin )
		{
			CompilerContext.MessageLog.Error(*LOCTEXT("InvalidInterfaceClass_Error", "Node @@ has an invalid target interface class").ToString(), this);
			return;
		}

		CastToInterfaceResultPin->PinType.PinSubCategoryObject = *CastToInterfaceNode->TargetType;

		if (ExecPin != nullptr)
		{
			UEdGraphPin* CastExecInput = CastToInterfaceNode->GetExecPin();
			check(CastExecInput != nullptr);

			// Wire up the connections
			CompilerContext.MovePinLinksToIntermediate(*ExecPin, *CastExecInput);
		}

		UEdGraphPin* CastToInterfaceSourceObjectPin = CastToInterfaceNode->GetCastSourcePin();
		CompilerContext.MovePinLinksToIntermediate(*MessageSelfPin, *CastToInterfaceSourceObjectPin);

		// Next, create the function call node
		UK2Node_CallFunction* FunctionCallNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
		FunctionCallNode->bIsInterfaceCall = true;
		FunctionCallNode->FunctionReference = FunctionReference;
		FunctionCallNode->AllocateDefaultPins();

		UEdGraphPin* CastToInterfaceValidPin = CastToInterfaceNode->GetValidCastPin();
		check(CastToInterfaceValidPin != nullptr);

		UEdGraphPin* LastOutCastFaildPin   = CastToInterfaceNode->GetInvalidCastPin();
		check(LastOutCastFaildPin != nullptr);
		UEdGraphPin* LastOutCastSuccessPin = CastToInterfaceValidPin;
		// Wire up the connections
		if (UEdGraphPin* CallFunctionExecPin = Schema->FindExecutionPin(*FunctionCallNode, EGPD_Input))
		{
			CastToInterfaceValidPin->MakeLinkTo(CallFunctionExecPin);
			LastOutCastSuccessPin = Schema->FindExecutionPin(*FunctionCallNode, EGPD_Output);
		}
		
		// Self pin
		UEdGraphPin* FunctionCallSelfPin = Schema->FindSelfPin(*FunctionCallNode, EGPD_Input);
		CastToInterfaceResultPin->MakeLinkTo(FunctionCallSelfPin);

		UFunction* ArrayClearFunction = UKismetArrayLibrary::StaticClass()->FindFunctionByName(FName(TEXT("Array_Clear")));
		check(ArrayClearFunction);

		bool const bIsPureFunc = Super::IsNodePure();
		// Variable pins - Try to associate variable inputs to the message node with the variable inputs and outputs to the call function node
		for( int32 i = 0; i < Pins.Num(); i++ )
		{
			UEdGraphPin* CurrentPin = Pins[i];
			if( CurrentPin && (CurrentPin->PinType.PinCategory != Schema->PC_Exec) && (CurrentPin->PinName != Schema->PN_Self) )
			{
				// Try to find a match for the pin on the function call node
				UEdGraphPin* FunctionCallPin = FunctionCallNode->FindPin(CurrentPin->PinName);
				if( FunctionCallPin )
				{
					// Move pin links if the pin is connected...
					CompilerContext.MovePinLinksToIntermediate(*CurrentPin, *FunctionCallPin);

					// when cast fails all return values must be cleared.
					if (EEdGraphPinDirection::EGPD_Output == CurrentPin->Direction)
					{
						UEdGraphPin* VarOutPin = FunctionCallPin;
						if (bIsPureFunc)
						{
							// since we cannot directly use the output from the
							// function call node (since it is pure, and invoking
							// it with a null target would cause an error), we 
							// have to use a temporary variable in it's place...
							UK2Node_TemporaryVariable* TempVar = CompilerContext.SpawnIntermediateNode<UK2Node_TemporaryVariable>(this, SourceGraph);
							TempVar->VariableType = CurrentPin->PinType;
							TempVar->AllocateDefaultPins();

							VarOutPin = TempVar->GetVariablePin();
							// nodes using the function's outputs directly, now
							// use this TempVar node instead
							CompilerContext.MovePinLinksToIntermediate(*FunctionCallPin, *VarOutPin);

							// on a successful cast, the temp var is filled with
							// the function's value, on a failed cast, the var 
							// is filled with a default value (DefaultValueNode, 
							// below)... this is the node for the success case:
							UK2Node_AssignmentStatement* AssignTempVar = CompilerContext.SpawnIntermediateNode<UK2Node_AssignmentStatement>(this, SourceGraph);
							AssignTempVar->AllocateDefaultPins();
							
							// assign the output from the pure function node to
							// the TempVar (either way, this message node is 
							// returning the TempVar's value, so on a successful 
							// cast we want it to have the function's result)
							UEdGraphPin* ValueInPin = AssignTempVar->GetValuePin();
							Schema->TryCreateConnection(FunctionCallPin, ValueInPin);
							AssignTempVar->PinConnectionListChanged(ValueInPin);

							UEdGraphPin* VarInPin = AssignTempVar->GetVariablePin();
							Schema->TryCreateConnection(VarOutPin, VarInPin);
							AssignTempVar->PinConnectionListChanged(VarInPin);
							// fold this AssignTempVar node into the cast's 
							// success execution chain
							Schema->TryCreateConnection(AssignTempVar->GetExecPin(), LastOutCastSuccessPin);
							LastOutCastSuccessPin = AssignTempVar->GetThenPin();
						}

						UK2Node* DefaultValueNode = NULL;
						UEdGraphPin* DefaultValueThenPin = NULL;
						if (CurrentPin->PinType.bIsArray)
						{
							UK2Node_CallArrayFunction* ClearArray = CompilerContext.SpawnIntermediateNode<UK2Node_CallArrayFunction>(this, SourceGraph);
							DefaultValueNode = ClearArray;
							ClearArray->SetFromFunction(ArrayClearFunction);
							ClearArray->AllocateDefaultPins();

							UEdGraphPin* ArrayPin = ClearArray->GetTargetArrayPin();
							check(ArrayPin);
							Schema->TryCreateConnection(ArrayPin, VarOutPin);
							ClearArray->PinConnectionListChanged(ArrayPin);

							DefaultValueThenPin = ClearArray->GetThenPin();
						} 
						else
						{
							UK2Node_AssignmentStatement* AssignDefaultValue = CompilerContext.SpawnIntermediateNode<UK2Node_AssignmentStatement>(this, SourceGraph);
							DefaultValueNode = AssignDefaultValue;
							AssignDefaultValue->AllocateDefaultPins();

							Schema->TryCreateConnection(AssignDefaultValue->GetVariablePin(), VarOutPin);
							AssignDefaultValue->PinConnectionListChanged(AssignDefaultValue->GetVariablePin());
							Schema->SetPinDefaultValueBasedOnType(AssignDefaultValue->GetValuePin());

							DefaultValueThenPin = AssignDefaultValue->GetThenPin();
						}

						UEdGraphPin* DefaultValueExecPin = DefaultValueNode->GetExecPin();
						check(DefaultValueExecPin);
						Schema->TryCreateConnection(DefaultValueExecPin, LastOutCastFaildPin);
						LastOutCastFaildPin = DefaultValueThenPin;
						check(LastOutCastFaildPin);
					}
				}
				else
				{
					UE_LOG(LogK2Compiler, Log, TEXT("%s"), *LOCTEXT("NoPinConnectionFound_Error", "Unable to find connection for pin!  Check AllocateDefaultPins() for consistency!").ToString());
				}
			}
		}

		if( bThenPinConnected )
		{
			check(LastOutCastFaildPin != nullptr);
			// Failure case for the cast runs straight through to the exit
			CompilerContext.CopyPinLinksToIntermediate(*ThenPin, *LastOutCastFaildPin);

			check(LastOutCastSuccessPin != nullptr);
			// Copy all links from the invalid cast case above to the call function node
			CompilerContext.MovePinLinksToIntermediate(*ThenPin, *LastOutCastSuccessPin);
		}
	}

	// Break all connections to the original node, so it will be pruned
	BreakAllNodeLinks();
}
void UK2Node_SpawnActorFromClass::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
{
	Super::ExpandNode(CompilerContext, SourceGraph);

	static FName BeginSpawningBlueprintFuncName = GET_FUNCTION_NAME_CHECKED(UGameplayStatics, BeginSpawningActorFromClass);
	static FString ActorClassParamName = FString(TEXT("ActorClass"));
	static FString WorldContextParamName = FString(TEXT("WorldContextObject"));

	static FName FinishSpawningFuncName = GET_FUNCTION_NAME_CHECKED(UGameplayStatics, FinishSpawningActor);
	static FString ActorParamName = FString(TEXT("Actor"));
	static FString TransformParamName = FString(TEXT("SpawnTransform"));
	static FString NoCollisionFailParamName = FString(TEXT("bNoCollisionFail"));
	static FString OwnerParamName = FString(TEXT("Owner"));

	static FString ObjectParamName = FString(TEXT("Object"));
	static FString ValueParamName = FString(TEXT("Value"));
	static FString PropertyNameParamName = FString(TEXT("PropertyName"));

	UK2Node_SpawnActorFromClass* SpawnNode = this;
	UEdGraphPin* SpawnNodeExec = SpawnNode->GetExecPin();
	UEdGraphPin* SpawnNodeTransform = SpawnNode->GetSpawnTransformPin();
	UEdGraphPin* SpawnNodeNoCollisionFail = GetNoCollisionFailPin();
	UEdGraphPin* SpawnWorldContextPin = SpawnNode->GetWorldContextPin();
	UEdGraphPin* SpawnClassPin = SpawnNode->GetClassPin();
	UEdGraphPin* SpawnNodeOwnerPin = SpawnNode->GetOwnerPin();
	UEdGraphPin* SpawnNodeThen = SpawnNode->GetThenPin();
	UEdGraphPin* SpawnNodeResult = SpawnNode->GetResultPin();

	UClass* SpawnClass = (SpawnClassPin != NULL) ? Cast<UClass>(SpawnClassPin->DefaultObject) : NULL;
	if((0 == SpawnClassPin->LinkedTo.Num()) && (NULL == SpawnClass))
	{
		CompilerContext.MessageLog.Error(*LOCTEXT("SpawnActorNodeMissingClass_Error", "Spawn node @@ must have a class specified.").ToString(), SpawnNode);
		// we break exec links so this is the only error we get, don't want the SpawnActor node being considered and giving 'unexpected node' type warnings
		SpawnNode->BreakAllNodeLinks();
		return;
	}

	//////////////////////////////////////////////////////////////////////////
	// create 'begin spawn' call node
	UK2Node_CallFunction* CallBeginSpawnNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(SpawnNode, SourceGraph);
	CallBeginSpawnNode->FunctionReference.SetExternalMember(BeginSpawningBlueprintFuncName, UGameplayStatics::StaticClass());
	CallBeginSpawnNode->AllocateDefaultPins();

	UEdGraphPin* CallBeginExec = CallBeginSpawnNode->GetExecPin();
	UEdGraphPin* CallBeginWorldContextPin = CallBeginSpawnNode->FindPinChecked(WorldContextParamName);
	UEdGraphPin* CallBeginActorClassPin = CallBeginSpawnNode->FindPinChecked(ActorClassParamName);
	UEdGraphPin* CallBeginTransform = CallBeginSpawnNode->FindPinChecked(TransformParamName);
	UEdGraphPin* CallBeginNoCollisionFail = CallBeginSpawnNode->FindPinChecked(NoCollisionFailParamName);
	UEdGraphPin* CallBeginOwnerPin = CallBeginSpawnNode->FindPinChecked(FK2Node_SpawnActorFromClassHelper::OwnerPinName);
	UEdGraphPin* CallBeginResult = CallBeginSpawnNode->GetReturnValuePin();	

	// Move 'exec' connection from spawn node to 'begin spawn'
	CompilerContext.MovePinLinksToIntermediate(*SpawnNodeExec, *CallBeginExec);

	if(SpawnClassPin->LinkedTo.Num() > 0)
	{
		// Copy the 'blueprint' connection from the spawn node to 'begin spawn'
		CompilerContext.MovePinLinksToIntermediate(*SpawnClassPin, *CallBeginActorClassPin);
	}
	else
	{
		// Copy blueprint literal onto begin spawn call 
		CallBeginActorClassPin->DefaultObject = SpawnClass;
	}

	// Copy the world context connection from the spawn node to 'begin spawn' if necessary
	if (SpawnWorldContextPin)
	{
		CompilerContext.MovePinLinksToIntermediate(*SpawnWorldContextPin, *CallBeginWorldContextPin);
	}

	if (SpawnNodeOwnerPin != nullptr)
	{
		CompilerContext.MovePinLinksToIntermediate(*SpawnNodeOwnerPin, *CallBeginOwnerPin);
	}

	// Copy the 'transform' connection from the spawn node to 'begin spawn'
	CompilerContext.MovePinLinksToIntermediate(*SpawnNodeTransform, *CallBeginTransform);

	// Copy the 'bNoCollisionFail' connection from the spawn node to 'begin spawn'
	CompilerContext.MovePinLinksToIntermediate(*SpawnNodeNoCollisionFail, *CallBeginNoCollisionFail);

	//////////////////////////////////////////////////////////////////////////
	// create 'finish spawn' call node
	UK2Node_CallFunction* CallFinishSpawnNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(SpawnNode, SourceGraph);
	CallFinishSpawnNode->FunctionReference.SetExternalMember(FinishSpawningFuncName, UGameplayStatics::StaticClass());
	CallFinishSpawnNode->AllocateDefaultPins();

	UEdGraphPin* CallFinishExec = CallFinishSpawnNode->GetExecPin();
	UEdGraphPin* CallFinishThen = CallFinishSpawnNode->GetThenPin();
	UEdGraphPin* CallFinishActor = CallFinishSpawnNode->FindPinChecked(ActorParamName);
	UEdGraphPin* CallFinishTransform = CallFinishSpawnNode->FindPinChecked(TransformParamName);
	UEdGraphPin* CallFinishResult = CallFinishSpawnNode->GetReturnValuePin();

	// Move 'then' connection from spawn node to 'finish spawn'
	CompilerContext.MovePinLinksToIntermediate(*SpawnNodeThen, *CallFinishThen);

	// Copy transform connection
	CompilerContext.CopyPinLinksToIntermediate(*CallBeginTransform, *CallFinishTransform);

	// Connect output actor from 'begin' to 'finish'
	CallBeginResult->MakeLinkTo(CallFinishActor);

	// Move result connection from spawn node to 'finish spawn'
	CallFinishResult->PinType = SpawnNodeResult->PinType; // Copy type so it uses the right actor subclass
	CompilerContext.MovePinLinksToIntermediate(*SpawnNodeResult, *CallFinishResult);

	//////////////////////////////////////////////////////////////////////////
	// create 'set var' nodes

	// Get 'result' pin from 'begin spawn', this is the actual actor we want to set properties on
	UEdGraphPin* LastThen = FKismetCompilerUtilities::GenerateAssignmentNodes(CompilerContext, SourceGraph, CallBeginSpawnNode, SpawnNode, CallBeginResult, GetClassToSpawn() );

	// Make exec connection between 'then' on last node and 'finish'
	LastThen->MakeLinkTo(CallFinishExec);

	// Break any links to the expanded node
	SpawnNode->BreakAllNodeLinks();
}
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();
	}
}
Esempio n. 15
0
void UK2Node_SpawnActor::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
{
	Super::ExpandNode(CompilerContext, SourceGraph);

	if (CompilerContext.bIsFullCompile)
	{
		static FName BeginSpawningBlueprintFuncName = GET_FUNCTION_NAME_CHECKED(UGameplayStatics, BeginSpawningActorFromBlueprint);
		static FString BlueprintParamName = FString(TEXT("Blueprint"));
		static FString WorldContextParamName = FString(TEXT("WorldContextObject"));

		static FName FinishSpawningFuncName = GET_FUNCTION_NAME_CHECKED(UGameplayStatics, FinishSpawningActor);
		static FString ActorParamName = FString(TEXT("Actor"));
		static FString TransformParamName = FString(TEXT("SpawnTransform"));
		static FString NoCollisionFailParamName = FString(TEXT("bNoCollisionFail"));

		static FString ObjectParamName = FString(TEXT("Object"));
		static FString ValueParamName = FString(TEXT("Value"));
		static FString PropertyNameParamName = FString(TEXT("PropertyName"));

		const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema();

		UEdGraphPin* SpawnNodeExec = GetExecPin();
		UEdGraphPin* SpawnNodeTransform = GetSpawnTransformPin();
		UEdGraphPin* SpawnNodeNoCollisionFail = GetNoCollisionFailPin();
		UEdGraphPin* SpawnWorldContextPin = GetWorldContextPin();
		UEdGraphPin* SpawnBlueprintPin = GetBlueprintPin();
		UEdGraphPin* SpawnNodeThen = GetThenPin();
		UEdGraphPin* SpawnNodeResult = GetResultPin();

		UBlueprint* SpawnBlueprint = NULL;
		if(SpawnBlueprintPin != NULL)
		{
			SpawnBlueprint = Cast<UBlueprint>(SpawnBlueprintPin->DefaultObject);
		}

		if(0 == SpawnBlueprintPin->LinkedTo.Num())	
		{
			if(NULL == SpawnBlueprint)
			{
				CompilerContext.MessageLog.Error(*LOCTEXT("SpawnActorNodeMissingBlueprint_Error", "Spawn node @@ must have a blueprint specified.").ToString(), this);
				// we break exec links so this is the only error we get, don't want the SpawnActor node being considered and giving 'unexpected node' type warnings
				BreakAllNodeLinks();
				return;
			}

			// check if default blueprint is based on Actor
			const UClass* GeneratedClass = SpawnBlueprint->GeneratedClass;
			bool bInvalidBase = GeneratedClass && !GeneratedClass->IsChildOf(AActor::StaticClass());

			const UClass* SkeletonGeneratedClass = Cast<UClass>(SpawnBlueprint->SkeletonGeneratedClass);
			bInvalidBase |= SkeletonGeneratedClass && !SkeletonGeneratedClass->IsChildOf(AActor::StaticClass());

			if(bInvalidBase)
			{
				CompilerContext.MessageLog.Error(*LOCTEXT("SpawnActorNodeInvalidBlueprint_Error", "Spawn node @@ must have a blueprint based on Actor specified.").ToString(), this);
				// we break exec links so this is the only error we get, don't want the SpawnActor node being considered and giving 'unexpected node' type warnings
				BreakAllNodeLinks();
				return;
			}
		}

		//////////////////////////////////////////////////////////////////////////
		// create 'begin spawn' call node
		UK2Node_CallFunction* CallBeginSpawnNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
		CallBeginSpawnNode->FunctionReference.SetExternalMember(BeginSpawningBlueprintFuncName, UGameplayStatics::StaticClass());
		CallBeginSpawnNode->AllocateDefaultPins();

		UEdGraphPin* CallBeginExec = CallBeginSpawnNode->GetExecPin();
		UEdGraphPin* CallBeginWorldContextPin = CallBeginSpawnNode->FindPinChecked(WorldContextParamName);
		UEdGraphPin* CallBeginBlueprintPin = CallBeginSpawnNode->FindPinChecked(BlueprintParamName);
		UEdGraphPin* CallBeginTransform = CallBeginSpawnNode->FindPinChecked(TransformParamName);
		UEdGraphPin* CallBeginNoCollisionFail = CallBeginSpawnNode->FindPinChecked(NoCollisionFailParamName);
		UEdGraphPin* CallBeginResult = CallBeginSpawnNode->GetReturnValuePin();

		// Move 'exec' connection from spawn node to 'begin spawn'
		CompilerContext.MovePinLinksToIntermediate(*SpawnNodeExec, *CallBeginExec);

		if(SpawnBlueprintPin->LinkedTo.Num() > 0)
		{
			// Copy the 'blueprint' connection from the spawn node to 'begin spawn'
			CompilerContext.MovePinLinksToIntermediate(*SpawnBlueprintPin, *CallBeginBlueprintPin);
		}
		else
		{
			// Copy blueprint literal onto begin spawn call 
			CallBeginBlueprintPin->DefaultObject = SpawnBlueprint;
		}

		// Copy the world context connection from the spawn node to 'begin spawn' if necessary
		if (SpawnWorldContextPin)
		{
			CompilerContext.MovePinLinksToIntermediate(*SpawnWorldContextPin, *CallBeginWorldContextPin);
		}

		// Copy the 'transform' connection from the spawn node to 'begin spawn'
		CompilerContext.MovePinLinksToIntermediate(*SpawnNodeTransform, *CallBeginTransform);
		
		// Copy the 'bNoCollisionFail' connection from the spawn node to 'begin spawn'
		CompilerContext.MovePinLinksToIntermediate(*SpawnNodeNoCollisionFail, *CallBeginNoCollisionFail);

		//////////////////////////////////////////////////////////////////////////
		// create 'finish spawn' call node
		UK2Node_CallFunction* CallFinishSpawnNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
		CallFinishSpawnNode->FunctionReference.SetExternalMember(FinishSpawningFuncName, UGameplayStatics::StaticClass());
		CallFinishSpawnNode->AllocateDefaultPins();

		UEdGraphPin* CallFinishExec = CallFinishSpawnNode->GetExecPin();
		UEdGraphPin* CallFinishThen = CallFinishSpawnNode->GetThenPin();
		UEdGraphPin* CallFinishActor = CallFinishSpawnNode->FindPinChecked(ActorParamName);
		UEdGraphPin* CallFinishTransform = CallFinishSpawnNode->FindPinChecked(TransformParamName);
		UEdGraphPin* CallFinishResult = CallFinishSpawnNode->GetReturnValuePin();

		// Move 'then' connection from spawn node to 'finish spawn'
		CompilerContext.MovePinLinksToIntermediate(*SpawnNodeThen, *CallFinishThen);
			
		// Copy transform connection
		CompilerContext.CopyPinLinksToIntermediate(*CallBeginTransform, *CallFinishTransform);
		
		// Connect output actor from 'begin' to 'finish'
		CallBeginResult->MakeLinkTo(CallFinishActor);

		// Move result connection from spawn node to 'finish spawn'
		CallFinishResult->PinType = SpawnNodeResult->PinType; // Copy type so it uses the right actor subclass
		CompilerContext.MovePinLinksToIntermediate(*SpawnNodeResult, *CallFinishResult);

		//////////////////////////////////////////////////////////////////////////
		// create 'set var' nodes

		// Get 'result' pin from 'begin spawn', this is the actual actor we want to set properties on
		UK2Node_CallFunction* LastNode = CallBeginSpawnNode;

		// Create 'set var by name' nodes and hook them up
		for(int32 PinIdx=0; PinIdx < Pins.Num(); PinIdx++)
		{
			// Only create 'set param by name' node if this pin is linked to something
			UEdGraphPin* SpawnVarPin = Pins[PinIdx];
			if(SpawnVarPin->LinkedTo.Num() > 0)
			{
				UFunction* SetByNameFunction = Schema->FindSetVariableByNameFunction(SpawnVarPin->PinType);
				if(SetByNameFunction)
				{
					UK2Node_CallFunction* SetVarNode = NULL;
					if(SpawnVarPin->PinType.bIsArray)
					{
						SetVarNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallArrayFunction>(this, SourceGraph);
					}
					else
					{
						SetVarNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
					}
					SetVarNode->SetFromFunction(SetByNameFunction);
					SetVarNode->AllocateDefaultPins();

					// Connect this node into the exec chain
					UEdGraphPin* LastThen = LastNode->GetThenPin();
					UEdGraphPin* SetVarExec = SetVarNode->GetExecPin();
					LastThen->MakeLinkTo(SetVarExec);

					// Connect the new actor to the 'object' pin
					UEdGraphPin* ObjectPin = SetVarNode->FindPinChecked(ObjectParamName);
					CallBeginResult->MakeLinkTo(ObjectPin);

					// Fill in literal for 'property name' pin - name of pin is property name
					UEdGraphPin* PropertyNamePin = SetVarNode->FindPinChecked(PropertyNameParamName);
					PropertyNamePin->DefaultValue = SpawnVarPin->PinName;

					// Move connection from the variable pin on the spawn node to the 'value' pin
					UEdGraphPin* ValuePin = SetVarNode->FindPinChecked(ValueParamName);
					CompilerContext.MovePinLinksToIntermediate(*SpawnVarPin, *ValuePin);
					if(SpawnVarPin->PinType.bIsArray)
					{
						SetVarNode->PinConnectionListChanged(ValuePin);
					}

					// Update 'last node in sequence' var
					LastNode = SetVarNode;
				}
			}
		}

		// Make exec connection between 'then' on last node and 'finish'
		UEdGraphPin* LastThen = LastNode->GetThenPin();
		LastThen->MakeLinkTo(CallFinishExec);

		// Break any links to the expanded node
		BreakAllNodeLinks();
	}
}
void UK2Node_LiveEditObject::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
{
	Super::ExpandNode(CompilerContext, SourceGraph);

	const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema();

	UEdGraphPin *SourceExecPin = GetExecPin();
	UEdGraphPin *SourceThenPin = GetThenPin();
	UEdGraphPin *SourceBlueprintPin = GetBlueprintPin();
	UEdGraphPin *SourceBaseClassPin = GetBaseClassPin();
	UEdGraphPin *SourceDescriptionPin = GetDescriptionPin();
	UEdGraphPin *SourcePermittedBindingsPin = GetPermittedBindingsPin();
	UEdGraphPin *SourceOnMidiInputPin = GetOnMidiInputPin();

	UEdGraphPin *SourceVariablePin = GetVariablePin();
	if(NULL == SourceVariablePin)
	{
		CompilerContext.MessageLog.Error(*LOCTEXT("LiveEditObjectNodeMissingBlueprint_Error", "LiveEdit node @@ must have a blueprint specified and a variable selected to tune.").ToString(), this);
		// we break exec links so this is the only error we get, don't want the SpawnActor node being considered and giving 'unexpected node' type warnings
		BreakAllNodeLinks();
		return;
	}

	UClass* SpawnClass = GetClassToSpawn();
	if(NULL == SpawnClass)
	{
		CompilerContext.MessageLog.Error(*LOCTEXT("LiveEditObjectNodeMissingBaseClass_Error", "LiveEdit node @@ must have a Base Class specified.").ToString(), this);
		// we break exec links so this is the only error we get, don't want the SpawnActor node being considered and giving 'unexpected node' type warnings
		BreakAllNodeLinks();
		return;
	}

	if ( SourcePermittedBindingsPin->LinkedTo.Num() == 0 )
	{
		CompilerContext.MessageLog.Error(*LOCTEXT("LiveEditObjectNodeMissingBinding_Error", "LiveEdit node @@ must specify Permitted Bindings.").ToString(), this);
		// we break exec links so this is the only error we get, don't want the SpawnActor node being considered and giving 'unexpected node' type warnings
		BreakAllNodeLinks();
		return;
	}

	//sanity check the VariablePin value
	{
		UProperty *Property = UK2Node_LiveEditObjectStatics::GetPropertyByName( SpawnClass, *SourceVariablePin->DefaultValue );
		if ( Property == NULL || !Property->IsA(UNumericProperty::StaticClass()) )
		{
			CompilerContext.MessageLog.Error(*LOCTEXT("LiveEditObjectNodeInvalidVariable_Error", "LiveEdit node @@ must have a valid variable selected.").ToString(), this);
			// we break exec links so this is the only error we get, don't want the SpawnActor node being considered and giving 'unexpected node' type warnings
			BreakAllNodeLinks();
			return;
		}
	}

	//hooks to pins that are generated after a BaseClass is set
	UEdGraphPin *DeltaMultPin = GetDeltaMultPin();
	UEdGraphPin *ShouldClampPin = GetShouldClampPin();
	UEdGraphPin *ClampMinPin = GetClampMinPin();
	UEdGraphPin *ClampMaxPin = GetClampMaxPin();

	UK2Node_Self *SelfNode  = CompilerContext.SpawnIntermediateNode<UK2Node_Self>(this,SourceGraph);
	SelfNode->AllocateDefaultPins();
	UEdGraphPin *SelfNodeThenPin = SelfNode->FindPinChecked(Schema->PN_Self);

	FString EventNameGuid = GetEventName();
		
	//Create the registration part of the LiveEditor binding process
	{
		UK2Node_CallFunction *RegisterForMIDINode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph);
		RegisterForMIDINode->FunctionReference.SetExternalMember( TEXT("RegisterForLiveEditEvent"), ULiveEditorKismetLibrary::StaticClass() );
		RegisterForMIDINode->AllocateDefaultPins();

		UEdGraphPin *ExecPin = RegisterForMIDINode->GetExecPin();
		CompilerContext.MovePinLinksToIntermediate(*SourceExecPin, *ExecPin);

		UEdGraphPin *ThenPin = RegisterForMIDINode->GetThenPin();
		CompilerContext.MovePinLinksToIntermediate(*SourceThenPin, *ThenPin);

		UEdGraphPin *TargetPin = RegisterForMIDINode->FindPinChecked( FString(TEXT("Target")) );
		TargetPin->MakeLinkTo(SelfNodeThenPin);

		UEdGraphPin *EventNamePin = RegisterForMIDINode->FindPinChecked( FString(TEXT("EventName")) );
		EventNamePin->DefaultValue = EventNameGuid;
		
		UEdGraphPin *DescriptionPin = RegisterForMIDINode->FindPinChecked( FString(TEXT("Description")) );
		CompilerContext.CopyPinLinksToIntermediate( *SourceDescriptionPin, *DescriptionPin);

		UEdGraphPin *PermittedBindingsPin = RegisterForMIDINode->FindPinChecked( FString(TEXT("PermittedBindings")) );
		CompilerContext.CopyPinLinksToIntermediate( *SourcePermittedBindingsPin, *PermittedBindingsPin);
	}

	//Create the event handling part of the LiveEditor binding process
	{
		//
		//the event itself
		//
		UFunction *EventMIDISignature = GetEventMIDISignature();
		UK2Node_Event* EventNode = CompilerContext.SpawnIntermediateNode<UK2Node_Event>(this, SourceGraph);
		check(EventNode);
		EventNode->EventSignatureClass = Cast<UClass>(EventMIDISignature->GetOuter());
		EventNode->EventSignatureName = EventMIDISignature->GetFName();
		EventNode->CustomFunctionName = *EventNameGuid;
		EventNode->bInternalEvent = true;
		EventNode->AllocateDefaultPins();

		// Cache these out because we'll connect the sequence to it
		UEdGraphPin *EventThenPin = EventNode->FindPinChecked( Schema->PN_Then );
		UEdGraphPin *EventDeltaPin = EventNode->FindPinChecked( FString(TEXT("Delta")) );
		UEdGraphPin *EventMidiValuePin = EventNode->FindPinChecked( FString(TEXT("MidiValue")) );
		UEdGraphPin *EventControlTypePin = EventNode->FindPinChecked( FString(TEXT("ControlType")) );


		//
		// Check if Blueprint is NULL
		//
		UEdGraphPin *CompareBlueprintToNullBranchThenPin = NULL;
		{
			UK2Node_CallFunction *CompareBlueprintToNullNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph);
			CompareBlueprintToNullNode->FunctionReference.SetExternalMember( TEXT("NotEqual_ObjectObject"), UKismetMathLibrary::StaticClass() );
			CompareBlueprintToNullNode->AllocateDefaultPins();

			//Set A Pin to the Blueprint Pin
			UEdGraphPin *CompareBlueprintToNullAPin = CompareBlueprintToNullNode->FindPinChecked( FString(TEXT("A")) );
			CompilerContext.CopyPinLinksToIntermediate( *SourceBlueprintPin, *CompareBlueprintToNullAPin);

			// hook for Compare Blueprint to NULL result
			UEdGraphPin *CompareBlueprintToNullResultPin = CompareBlueprintToNullNode->GetReturnValuePin();

			// Create the BRANCH that will drive the comparison
			UK2Node_IfThenElse* CompareBlueprintToNullBranchNode = CompilerContext.SpawnIntermediateNode<UK2Node_IfThenElse>(this, SourceGraph);
			CompareBlueprintToNullBranchNode->AllocateDefaultPins();

			//hook up the condition
			CompareBlueprintToNullResultPin->MakeLinkTo( CompareBlueprintToNullBranchNode->GetConditionPin() );

			//hook event to the branck input
			EventThenPin->MakeLinkTo( CompareBlueprintToNullBranchNode->GetExecPin() );

			//cache ot the THEN pin for later linkup
			CompareBlueprintToNullBranchThenPin = CompareBlueprintToNullBranchNode->GetThenPin();
		}

		//
		// Get Class Default Object
		//
		UK2Node_CallFunction *GetClassDefaultObjectNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph);
		GetClassDefaultObjectNode->FunctionReference.SetExternalMember( TEXT("GetBlueprintClassDefaultObject"), ULiveEditorKismetLibrary::StaticClass() );
		GetClassDefaultObjectNode->AllocateDefaultPins();

		UEdGraphPin *GetClassDefaultObjectBlueprintPin = GetClassDefaultObjectNode->FindPinChecked( TEXT("Blueprint") );
		CompilerContext.CopyPinLinksToIntermediate( *SourceBlueprintPin, *GetClassDefaultObjectBlueprintPin);

		//hook for later -> the pointer to the ClassDefaultObject of our BlueprintPin
		UEdGraphPin *GetClassDefaultObjectResultPin = GetClassDefaultObjectNode->GetReturnValuePin();


		//
		// Compare to BaseClass to make sure that the target Blueprint IsA(BaseClass)
		//
		UEdGraphPin *ClassIsChildOfBranchThenPin = NULL;
		{
			//
			//we need to get the class of the Blueprint pin
			UK2Node_CallFunction *GetClassNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph);
			GetClassNode->FunctionReference.SetExternalMember( TEXT("GetObjectClass"), UGameplayStatics::StaticClass() );
			GetClassNode->AllocateDefaultPins();

			//Pin in the GetClassDefaultObjectResultPin to the Object Parameter of the GetObjectClass FUNCTION
			//we want to make sure that the Class of the DEFAULT_OBJECT IsA( BaseClass )
			UEdGraphPin *GetClassObjectPin = GetClassNode->FindPinChecked( FString(TEXT("Object")) );
			GetClassDefaultObjectResultPin->MakeLinkTo( GetClassObjectPin );

			//hook for the Class result
			UEdGraphPin *GetClassReturnValuePin = GetClassNode->GetReturnValuePin();

			//
			//the ClassIsChildOf FUNCTION
			UK2Node_CallFunction *ClassIsChildOfNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph);
			ClassIsChildOfNode->FunctionReference.SetExternalMember( TEXT("ClassIsChildOf"), UKismetMathLibrary::StaticClass() );
			ClassIsChildOfNode->AllocateDefaultPins();

			//hook up the test pin
			UEdGraphPin *ClassIsChildOfTestPin = ClassIsChildOfNode->FindPinChecked( FString(TEXT("TestClass")) );
			GetClassReturnValuePin->MakeLinkTo( ClassIsChildOfTestPin );

			//copy our BaseClass Pin into the ClassIsChildOf Parameter
			UEdGraphPin *ClassIsChildOfParentPin = ClassIsChildOfNode->FindPinChecked( FString(TEXT("ParentClass")) );
			CompilerContext.CopyPinLinksToIntermediate( *SourceBaseClassPin, *ClassIsChildOfParentPin);

			//hook for return value
			UEdGraphPin *ClassIsChildOfResultPin = ClassIsChildOfNode->GetReturnValuePin();

			//
			// Create the BRANCH that will drive the comparison
			UK2Node_IfThenElse* ClassIsChildOfBranchNode = CompilerContext.SpawnIntermediateNode<UK2Node_IfThenElse>(this, SourceGraph);
			ClassIsChildOfBranchNode->AllocateDefaultPins();

			//hook up the previous branch to this one
			check( CompareBlueprintToNullBranchThenPin != NULL );
			CompareBlueprintToNullBranchThenPin->MakeLinkTo( ClassIsChildOfBranchNode->GetExecPin() );

			//hook up our condition
			ClassIsChildOfResultPin->MakeLinkTo( ClassIsChildOfBranchNode->GetConditionPin() );

			//cache ot the THEN pin for later linkup
			ClassIsChildOfBranchThenPin = ClassIsChildOfBranchNode->GetThenPin();
		}


		//
		//The set variable function (to set LiveEdited new value)
		//
		UK2Node_CallFunction *ModifyVarNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph);
		ModifyVarNode->FunctionReference.SetExternalMember( TEXT("ModifyPropertyByName"), ULiveEditorKismetLibrary::StaticClass() );
		ModifyVarNode->AllocateDefaultPins();

		// Make link from the event to the Set variable node
		UEdGraphPin *ModifyVarExecPin = ModifyVarNode->GetExecPin();
		ClassIsChildOfBranchThenPin->MakeLinkTo( ModifyVarExecPin );

		//link up the Target Pin
		UEdGraphPin *ModifyVarNodeTargetPin = ModifyVarNode->FindPinChecked( TEXT("Target") );
		GetClassDefaultObjectResultPin->MakeLinkTo( ModifyVarNodeTargetPin );

		//link up the PropertyName Pin
		UEdGraphPin *ModifyVarNodePropertyNamePin = ModifyVarNode->FindPinChecked( TEXT("PropertyName") );
		ModifyVarNodePropertyNamePin->DefaultValue = SourceVariablePin->DefaultValue;

		//link up the MIDI Value Pin
		UEdGraphPin *ModifyVarNodeMidiValuePin = ModifyVarNode->FindPinChecked( TEXT("MidiValue") );
		EventMidiValuePin->MakeLinkTo(ModifyVarNodeMidiValuePin);

		//link up the ControlType Pin
		UEdGraphPin *ModifyVarNodeControlTypePin = ModifyVarNode->FindPinChecked( TEXT("ControlType") );
		EventControlTypePin->MakeLinkTo(ModifyVarNodeControlTypePin);

		//hook for the Delta Pin
		UEdGraphPin *ModifyVarNodeDeltaPin = ModifyVarNode->FindPinChecked( TEXT("Delta") );

		//Clamping
		if ( ShouldClampPin->DefaultValue == FString(TEXT("true")) )
		{
			UEdGraphPin *ModifyVarNodeShouldClampPin = ModifyVarNode->FindPinChecked( TEXT("bShouldClamp") );
			CompilerContext.CopyPinLinksToIntermediate( *ShouldClampPin, *ModifyVarNodeShouldClampPin);

			check( ClampMinPin != NULL );
			UEdGraphPin *ModifyVarNodeClampMinPin = ModifyVarNode->FindPinChecked( TEXT("ClampMin") );
			CompilerContext.CopyPinLinksToIntermediate( *ClampMinPin, *ModifyVarNodeClampMinPin);

			check( ClampMaxPin != NULL );
			UEdGraphPin *ModifyVarNodeClampMaxPin = ModifyVarNode->FindPinChecked( TEXT("ClampMax") );
			CompilerContext.CopyPinLinksToIntermediate( *ClampMaxPin, *ModifyVarNodeClampMaxPin);
		}

		//hook for ModifyVar THEN
		UEdGraphPin *ModifyVarNodeThenPin = ModifyVarNode->GetThenPin();

		//
		// The Multiply Delta * DeltaMult function
		//
		UK2Node_CallFunction *MultiplyNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph);
		MultiplyNode->FunctionReference.SetExternalMember( TEXT("Multiply_FloatFloat"), UKismetMathLibrary::StaticClass() );
		MultiplyNode->AllocateDefaultPins();

		//cache this out. it will be linked to from the output of the (int)Delta -> (float)Delta Conversion function
		UEdGraphPin *MultiplyNodeFirstPin = MultiplyNode->FindPinChecked( FString(TEXT("A")) );

		// 2nd input to the Add function comes from the Current variable value
		UEdGraphPin *MultiplyNodeSecondPin = MultiplyNode->FindPinChecked( FString(TEXT("B")) );
		CompilerContext.CopyPinLinksToIntermediate( *DeltaMultPin, *MultiplyNodeSecondPin);

		UEdGraphPin *MultiplyNodeReturnValuePin = MultiplyNode->GetReturnValuePin();
		MultiplyNodeReturnValuePin->MakeLinkTo( ModifyVarNodeDeltaPin );

		//
		// The Convert function to go from (int)Delta to ULiveEditorKismetLibrary::ModifyPropertyByName(... float Delta ...)
		//
		FName ConvertFunctionName;
		bool success = Schema->SearchForAutocastFunction( EventDeltaPin, MultiplyNodeFirstPin, ConvertFunctionName );
		check( success );
		UK2Node_CallFunction *ConvertDeltaNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph);
		ConvertDeltaNode->FunctionReference.SetExternalMember( ConvertFunctionName, UKismetMathLibrary::StaticClass() );
		ConvertDeltaNode->AllocateDefaultPins();

		FName PinName;
		success = UK2Node_LiveEditObjectStatics::SearchForConvertPinName( Schema, EventDeltaPin, PinName );
		check( success );
		UEdGraphPin *ConvertDeltaInputPin = ConvertDeltaNode->FindPinChecked( PinName.ToString() );
		EventDeltaPin->MakeLinkTo( ConvertDeltaInputPin );

		UEdGraphPin *ConvertDeltaOutputPin = ConvertDeltaNode->GetReturnValuePin();
		ConvertDeltaOutputPin->MakeLinkTo( MultiplyNodeFirstPin );

		//
		// TODO - markDirty
		//

		//
		// send out the object value updates
		//
		UK2Node_CallFunction *ReplicationNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph);
		ReplicationNode->FunctionReference.SetExternalMember( TEXT("ReplicateChangesToChildren"), ULiveEditorKismetLibrary::StaticClass() );
		ReplicationNode->AllocateDefaultPins();

		UEdGraphPin *ReplicationNodeVarNamePin = ReplicationNode->FindPinChecked( TEXT("PropertyName") );
		ReplicationNodeVarNamePin->DefaultValue = SourceVariablePin->DefaultValue;

		UEdGraphPin *ReplicationNodeArchetypePin = ReplicationNode->FindPinChecked( FString(TEXT("Archetype")) );
		GetClassDefaultObjectResultPin->MakeLinkTo( ReplicationNodeArchetypePin );

		UEdGraphPin *ReplicationNodeExecPin = ReplicationNode->GetExecPin();
		ModifyVarNodeThenPin->MakeLinkTo( ReplicationNodeExecPin );

		UEdGraphPin *ReplicationNodeThenPin = ReplicationNode->FindPinChecked( FString(TEXT("then")) );

		//
		// Finally, activate our OnMidiInput pin
		//
		CompilerContext.CopyPinLinksToIntermediate( *SourceOnMidiInputPin, *ReplicationNodeThenPin);
			
	}

	// Break any links to the expanded node
	BreakAllNodeLinks();
}
void UEnvironmentQueryGraph::SpawnMissingNodes()
{
	UEnvQuery* QueryOwner = Cast<UEnvQuery>(GetOuter());
	if (QueryOwner == nullptr)
	{
		return;
	}

	TSet<UEnvQueryTest*> ExistingTests;
	TSet<UEnvQueryOption*> ExistingNodes;
	TArray<UEnvQueryOption*> OptionsCopy = QueryOwner->GetOptions();

	UAIGraphNode* MyRootNode = nullptr;
	for (int32 Idx = 0; Idx < Nodes.Num(); Idx++)
	{
		UEnvironmentQueryGraphNode* MyNode = Cast<UEnvironmentQueryGraphNode>(Nodes[Idx]);
		UEnvQueryOption* OptionInstance = MyNode ? Cast<UEnvQueryOption>(MyNode->NodeInstance) : nullptr;
		if (OptionInstance && OptionInstance->Generator)
		{
			ExistingNodes.Add(OptionInstance);

			ExistingTests.Empty(ExistingTests.Num());
			for (int32 SubIdx = 0; SubIdx < MyNode->SubNodes.Num(); SubIdx++)
			{
				UEnvironmentQueryGraphNode* MySubNode = Cast<UEnvironmentQueryGraphNode>(MyNode->SubNodes[SubIdx]);
				UEnvQueryTest* TestInstance = MySubNode ? Cast<UEnvQueryTest>(MySubNode->NodeInstance) : nullptr;
				if (TestInstance)
				{
					ExistingTests.Add(TestInstance);
				}
				else
				{
					MyNode->RemoveSubNode(MySubNode);
					SubIdx--;
				}
			}

			SpawnMissingSubNodes(OptionInstance, ExistingTests, MyNode);
		}

		UEnvironmentQueryGraphNode_Root* RootNode = Cast<UEnvironmentQueryGraphNode_Root>(Nodes[Idx]);
		if (RootNode)
		{
			MyRootNode = RootNode;
		}
	}

	UEdGraphPin* RootOutPin = MyRootNode ? FindGraphNodePin(MyRootNode, EGPD_Output) : nullptr;
	ExistingTests.Empty(0);

	for (int32 Idx = 0; Idx < OptionsCopy.Num(); Idx++)
	{
		UEnvQueryOption* OptionInstance = OptionsCopy[Idx];
		if (ExistingNodes.Contains(OptionInstance) || OptionInstance == nullptr || OptionInstance->Generator == nullptr)
		{
			continue;
		}

		FGraphNodeCreator<UEnvironmentQueryGraphNode_Option> NodeBuilder(*this);
		UEnvironmentQueryGraphNode_Option* MyNode = NodeBuilder.CreateNode();
		UAIGraphNode::UpdateNodeClassDataFrom(OptionInstance->Generator->GetClass(), MyNode->ClassData);
		MyNode->ErrorMessage = MyNode->ClassData.GetDeprecatedMessage();
		NodeBuilder.Finalize();

		if (MyRootNode)
		{
			MyNode->NodePosX = MyRootNode->NodePosX + (Idx * 300);
			MyNode->NodePosY = MyRootNode->NodePosY + 100;
		}

		MyNode->NodeInstance = OptionInstance;
		SpawnMissingSubNodes(OptionInstance, ExistingTests, MyNode);

		UEdGraphPin* SpawnedInPin = FindGraphNodePin(MyNode, EGPD_Input);
		if (RootOutPin && SpawnedInPin)
		{
			RootOutPin->MakeLinkTo(SpawnedInPin);
		}
	}
}
void UGameplayTagsK2Node_LiteralGameplayTag::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
{
	Super::ExpandNode(CompilerContext, SourceGraph);

	const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema();

	// Get The input and output pins to our node
	UEdGraphPin* TagInPin = FindPin(TEXT("TagIn"));
	UEdGraphPin* TagOutPin = FindPinChecked(Schema->PN_ReturnValue);

	// Create a Make Struct
	UK2Node_MakeStruct* MakeStructNode = SourceGraph->CreateBlankNode<UK2Node_MakeStruct>();
	MakeStructNode->StructType = FGameplayTagContainer::StaticStruct();
	MakeStructNode->AllocateDefaultPins();

	// Create a Make Array
	UK2Node_MakeArray* MakeArrayNode = SourceGraph->CreateBlankNode<UK2Node_MakeArray>();
	MakeArrayNode->AllocateDefaultPins();
		
	// Connect the output of our MakeArray to the Input of our MakeStruct so it sets the Array Type
	UEdGraphPin* InPin = MakeStructNode->FindPin( TEXT("GameplayTags") );
	if( InPin )
	{
		InPin->MakeLinkTo( MakeArrayNode->GetOutputPin() );
	}

	// Add the FName Values to the MakeArray input pins
	UEdGraphPin* ArrayInputPin = NULL;
	FString TagString = TagInPin->GetDefaultAsString();

	if( TagString.StartsWith( TEXT("(") ) && TagString.EndsWith( TEXT(")") ) )
	{
		TagString = TagString.LeftChop(1);
		TagString = TagString.RightChop(1);
		TagString.Split("=", NULL, &TagString);
		TagString = TagString.LeftChop(1);
		TagString = TagString.RightChop(1);

		FString ReadTag;
		FString Remainder;
		int32 MakeIndex = 0;
		while( TagString.Split( TEXT(","), &ReadTag, &Remainder ) ) 
		{
			TagString = Remainder;

			ArrayInputPin = MakeArrayNode->FindPin( FString::Printf( TEXT("[%d]"), MakeIndex ) );
			ArrayInputPin->PinType.PinCategory = TEXT("struct");
			ArrayInputPin->PinType.PinSubCategoryObject = FGameplayTag::StaticStruct();
			ArrayInputPin->DefaultValue = ReadTag;

			MakeIndex++;
			MakeArrayNode->AddInputPin();
		}
		if( Remainder.IsEmpty() )
		{
			Remainder = TagString;
		}
		if( !Remainder.IsEmpty() )
		{
			ArrayInputPin = MakeArrayNode->FindPin( FString::Printf( TEXT("[%d]"), MakeIndex ) );
			ArrayInputPin->PinType.PinCategory = TEXT("struct");
			ArrayInputPin->PinType.PinSubCategoryObject = FGameplayTag::StaticStruct();
			ArrayInputPin->DefaultValue = Remainder;

			MakeArrayNode->PostReconstructNode();
		}
		else
		{
			MakeArrayNode->RemoveInputPin(MakeArrayNode->FindPin(TEXT("[0]")));
			MakeArrayNode->PostReconstructNode();
		}
	}
	else
	{
		MakeArrayNode->RemoveInputPin(MakeArrayNode->FindPin(TEXT("[0]")));
		MakeArrayNode->PostReconstructNode();
	}

	// Move the Output of the MakeArray to the Output of our node
	UEdGraphPin* OutPin = MakeStructNode->FindPin( MakeStructNode->StructType->GetName() );
	if( OutPin && TagOutPin )
	{
		OutPin->PinType = TagOutPin->PinType; // Copy type so it uses the right actor subclass
		CompilerContext.MovePinLinksToIntermediate(*TagOutPin, *OutPin);
	}

	// Break any links to the expanded node
	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();
	}
}
	static void ResolveCircularDependencyDiffs(UBlueprint const* const BlueprintIn, TArray<FDiffSingleResult>& DiffsInOut)
	{
		UEdGraphSchema_K2 const* K2Schema = GetDefault<UEdGraphSchema_K2>();

		typedef TArray<FDiffSingleResult>::TIterator TDiffIt;
		TMap<UEdGraphPin*, TDiffIt> PinLinkDiffsForRepair;

		for (auto DiffIt(DiffsInOut.CreateIterator()); DiffIt; ++DiffIt)
		{
			// as far as we know, pin link diffs are the only ones that would be
			// affected by circular references pointing to an unloaded class 
			// 
			// NOTE: we only handle PIN_LINKEDTO_NUM_INC over PIN_LINKEDTO_NUM_DEC,
			//       this assumes that the diff was performed in a specific 
			//       order (the reloaded blueprint first).
			if (DiffIt->Diff != EDiffType::PIN_LINKEDTO_NUM_INC)
			{
				continue;
			}

			check(DiffIt->Pin1 != nullptr);
			check(DiffIt->Pin2 != nullptr);
			UEdGraphPin* MalformedPin = DiffIt->Pin1;
			
			FEdGraphPinType const& PinType = MalformedPin->PinType;
			// only object pins would reference the unloaded blueprint
			if (!PinType.PinSubCategoryObject.IsValid() || ((PinType.PinCategory != K2Schema->PC_Object) && 
				(PinType.PinCategory != K2Schema->PSC_Self) && (PinType.PinCategory != K2Schema->PC_Interface)))
			{
				continue;
			}

			UStruct const* PinObjType = Cast<UStruct>(PinType.PinSubCategoryObject.Get());
			// only pins that match the blueprint class would have been affected 
			// by the unload (assumes an FArchiveReplaceObjectRef() has since been 
			// ran to fix-up any references to the unloaded class... meaning the 
			// malformed pins now have the proper reference)
			if (!PinObjType->IsChildOf(BlueprintIn->GeneratedClass))
			{
				continue;
			}

			UEdGraphPin* LegitPin = DiffIt->Pin2;
			// make sure we interpreted which pin is which correctly
			check(LegitPin->LinkedTo.Num() > MalformedPin->LinkedTo.Num());

			for (UEdGraphPin* LinkedPin : LegitPin->LinkedTo)
			{
				// pin linked-to-count diffs always come in pairs (one for the
				// input pin, another for the output)... we use this to know 
				// which pins we should attempt to link again
				TDiffIt const* CorrespendingDiff = PinLinkDiffsForRepair.Find(LinkedPin);
				// we don't have the full pair yet, we'll have to wait till we have the other one
				if (CorrespendingDiff == nullptr)
				{
					continue;
				}

				UEdGraphPin* OtherMalformedPin = (*CorrespendingDiff)->Pin1;
				if (K2Schema->ArePinsCompatible(MalformedPin, OtherMalformedPin, BlueprintIn->GeneratedClass))
				{
					MalformedPin->MakeLinkTo(OtherMalformedPin);
				}
				// else pin types still aren't compatible (even after running 
				// FArchiveReplaceObjectRef), meaning this diff isn't fully resolvable
			}

			// track diffs that are in possible need of repair (so we know which  
			// two pins should attempt to relink)
			PinLinkDiffsForRepair.Add(LegitPin, DiffIt);
		}

		// remove any resolved diffs that no longer are valid (iterating backwards
		// so we can remove array items and not have to offset the index)
		for (int32 DiffIndex = DiffsInOut.Num()-1; DiffIndex >= 0; --DiffIndex)
		{
			FDiffSingleResult const& Diff = DiffsInOut[DiffIndex];
			if ((Diff.Diff == EDiffType::PIN_LINKEDTO_NUM_INC) || (Diff.Diff == EDiffType::PIN_LINKEDTO_NUM_DEC))
			{
				check(Diff.Pin1 && Diff.Pin2);
				// if this diff has been resolved (it's no longer valid)
				if (Diff.Pin1->LinkedTo.Num() == Diff.Pin2->LinkedTo.Num())
				{
					DiffsInOut.RemoveAt(DiffIndex);
				}
			}
		}
	}
Esempio n. 21
0
void UK2Node_FormatText::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
{
	Super::ExpandNode(CompilerContext, SourceGraph);

	/**
		At the end of this, the UK2Node_FormatText will not be a part of the Blueprint, it merely handles connecting
		the other nodes into the Blueprint.
	*/

	const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema();

	// Create a "Make Array" node to compile the list of arguments into an array for the Format function being called
	UK2Node_MakeArray* MakeArrayNode = CompilerContext.SpawnIntermediateNode<UK2Node_MakeArray>(this, SourceGraph); //SourceGraph->CreateBlankNode<UK2Node_MakeArray>();
	MakeArrayNode->AllocateDefaultPins();
	CompilerContext.MessageLog.NotifyIntermediateObjectCreation(MakeArrayNode, this);

	UEdGraphPin* ArrayOut = MakeArrayNode->GetOutputPin();

	// This is the node that does all the Format work.
	UK2Node_CallFunction* CallFunction = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
	CallFunction->SetFromFunction(UKismetTextLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UKismetTextLibrary, Format)));
	CallFunction->AllocateDefaultPins();
	CompilerContext.MessageLog.NotifyIntermediateObjectCreation(CallFunction, this);

	// Connect the output of the "Make Array" pin to the function's "InArgs" pin
	ArrayOut->MakeLinkTo(CallFunction->FindPin(TEXT("InArgs")));

	// This will set the "Make Array" node's type, only works if one pin is connected.
	MakeArrayNode->PinConnectionListChanged(ArrayOut);

	// For each argument, we will need to add in a "Make Struct" node.
	for(int32 ArgIdx = 0; ArgIdx < PinNames.Num(); ++ArgIdx)
	{
		UEdGraphPin* ArgumentPin = FindArgumentPin(PinNames[ArgIdx]);

		// Spawn a "Make Struct" node to create the struct needed for formatting the text.
		UK2Node_MakeStruct* PinMakeStruct = CompilerContext.SpawnIntermediateNode<UK2Node_MakeStruct>(this, SourceGraph);
		PinMakeStruct->StructType = FFormatTextArgument::StaticStruct();
		PinMakeStruct->AllocateDefaultPins();

		// Set the struct's "ArgumentName" pin literal to be the argument pin's name.
		PinMakeStruct->GetSchema()->TrySetDefaultText(*PinMakeStruct->FindPin("ArgumentName"), FText::AsCultureInvariant(ArgumentPin->PinName));

		// Move the connection of the argument pin to the struct's "TextValue" pin, this will move the literal value if present.
		CompilerContext.MovePinLinksToIntermediate(*ArgumentPin, *PinMakeStruct->FindPin("TextValue"));

		// The "Make Array" node already has one pin available, so don't create one for ArgIdx == 0
		if(ArgIdx > 0)
		{
			MakeArrayNode->AddInputPin();
		}

		// Find the input pin on the "Make Array" node by index.
		FString PinName = FString::Printf(TEXT("[%d]"), ArgIdx);
		UEdGraphPin* InputPin = MakeArrayNode->FindPin(PinName);

		// Find the output for the pin's "Make Struct" node and link it to the corresponding pin on the "Make Array" node.
		FindOutputStructPinChecked(PinMakeStruct)->MakeLinkTo(InputPin);

	}

	// Move connection of FormatText's "Result" pin to the call function's return value pin.
	CompilerContext.MovePinLinksToIntermediate(*FindPin(TEXT("Result")), *CallFunction->GetReturnValuePin());
	// Move connection of FormatText's "Format" pin to the call function's "InPattern" pin
	CompilerContext.MovePinLinksToIntermediate(*GetFormatPin(), *CallFunction->FindPin(TEXT("InPattern")));

	BreakAllNodeLinks();
}