UEdGraphPin* UK2Node_Tunnel::CreatePinFromUserDefinition(const TSharedPtr<FUserPinInfo> NewPinInfo)
{
	// Create the new pin
	EEdGraphPinDirection Direction = bCanHaveInputs ? EGPD_Input : EGPD_Output;

	// Let the user pick the pin direction if legal
	if ( (bCanHaveInputs && NewPinInfo->DesiredPinDirection == EGPD_Input) || (bCanHaveOutputs && NewPinInfo->DesiredPinDirection == EGPD_Output) )
	{
		Direction = NewPinInfo->DesiredPinDirection;
	}

	UEdGraphPin* Result = CreatePin(Direction, NewPinInfo->PinType, NewPinInfo->PinName);
	Result->DefaultValue = Result->AutogeneratedDefaultValue = NewPinInfo->PinDefaultValue;

	// Make sure it mirrors onto the associated node
	UEdGraphNode* TargetNode = ((InputSinkNode != NULL) ? InputSinkNode : OutputSourceNode);
	if (Cast<UK2Node_Composite>(TargetNode) != NULL || Cast<UK2Node_MacroInstance>(TargetNode) != NULL)
	{
		UEdGraphPin* HasPinAlready = TargetNode->FindPin(Result->PinName);
		if (HasPinAlready == NULL)
		{
			TargetNode->CreatePin(UEdGraphPin::GetComplementaryDirection(Direction), NewPinInfo->PinType, NewPinInfo->PinName);
		}
	}
	else if (UK2Node_Tunnel* TunnelNode = Cast<UK2Node_Tunnel>(TargetNode))
	{
		TunnelNode->CreateUserDefinedPin(NewPinInfo->PinName, NewPinInfo->PinType, (Direction == EGPD_Input)? EGPD_Output : EGPD_Input);
	}

	//@TODO: Automatically update loaded macro instances when this node is changed too

	return Result;
}
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;
}
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;
}
예제 #4
0
TSharedPtr<SGraphPin> SGraphPanel::FGraphPinHandle::FindInGraphPanel(const SGraphPanel& InPanel) const
{
	// First off, find the node
	TSharedPtr<SGraphNode> GraphNode = InPanel.GetNodeWidgetFromGuid(NodeGuid);
	if (GraphNode.IsValid())
	{
		UEdGraphNode* Node = GraphNode->GetNodeObj();
		UEdGraphPin* Pin = Node->FindPin(PinName);

		if (Pin)
		{
			return GraphNode->FindWidgetForPin(Pin);
		}
	}

	return TSharedPtr<SGraphPin>();
}
	static bool CreateMap(UEdGraphNode& KeyNode, UEdGraphNode& ValueNode, EEdGraphPinDirection KeyPinDirection, UEdGraphSchema_K2* Schema, TMap<UEdGraphPin*, UEdGraphPin*>& OutMap)
	{
		check(Schema);
		for (auto InnerInputPin : KeyNode.Pins)
		{
			if (!InnerInputPin || InnerInputPin->Direction != KeyPinDirection)
			{
				return false;
			}

			auto OuterInputPin = ValueNode.FindPin(InnerInputPin->PinName);
			if (!OuterInputPin
				|| !Schema->ArePinsCompatible(InnerInputPin, OuterInputPin, nullptr, false))
			{
				return false;
			}
			OutMap.Add(InnerInputPin, OuterInputPin);
		}
		return true;
	}
예제 #6
0
void UK2Node::AutowireNewNode(UEdGraphPin* FromPin)
{
	const UEdGraphSchema_K2* K2Schema = CastChecked<UEdGraphSchema_K2>(GetSchema());
	
	// Do some auto-connection
	if (FromPin != NULL)
	{
		TSet<UEdGraphNode*> NodeList;

		// sometimes we don't always find an ideal connection, but we want to exhaust 
		// all our options first... this stores a secondary less-ideal pin to connect to, if nothing better was found
		UEdGraphPin* BackupConnection = NULL;
		// If not dragging an exec pin, auto-connect from dragged pin to first compatible pin on the new node
		for (int32 i=0; i<Pins.Num(); i++)
		{
			UEdGraphPin* Pin = Pins[i];
			check(Pin);

			ECanCreateConnectionResponse ConnectResponse = K2Schema->CanCreateConnection(FromPin, Pin).Response;
			if (ConnectResponse == ECanCreateConnectionResponse::CONNECT_RESPONSE_MAKE)
			{
				if (K2Schema->TryCreateConnection(FromPin, Pin))
				{
					NodeList.Add(FromPin->GetOwningNode());
					NodeList.Add(this);
				}

				// null out the backup connection (so we don't attempt to make it 
				// once we exit the loop... we successfully made this connection!)
				BackupConnection = NULL;
				break;
			}
			else if((FromPin->PinType.PinCategory == K2Schema->PC_Exec) && (ConnectResponse == ECanCreateConnectionResponse::CONNECT_RESPONSE_BREAK_OTHERS_A))
			{
				InsertNewNode(FromPin, Pin, NodeList);

				// null out the backup connection (so we don't attempt to make it 
				// once we exit the loop... we successfully made this connection!)
				BackupConnection = NULL;
				break;
			}
			else if ((BackupConnection == NULL) && (ConnectResponse == ECanCreateConnectionResponse::CONNECT_RESPONSE_MAKE_WITH_CONVERSION_NODE))
			{
				// save this off, in-case we don't make any connection at all
				BackupConnection = Pin;
			}
		}

		// if we didn't find an ideal connection, then lets connect this pin to 
		// the BackupConnection (something, like a connection that requires a conversion node, etc.)
		if ((BackupConnection != NULL) && K2Schema->TryCreateConnection(FromPin, BackupConnection))
		{
			NodeList.Add(FromPin->GetOwningNode());
			NodeList.Add(this);
		}

		// If we were not dragging an exec pin, but it was an output pin, try and connect the Then and Execute pins
		if ((FromPin->PinType.PinCategory != K2Schema->PC_Exec  && FromPin->Direction == EGPD_Output))
		{
			UEdGraphNode* FromPinNode = FromPin->GetOwningNode();
			UEdGraphPin* FromThenPin = FromPinNode->FindPin(K2Schema->PN_Then);

			UEdGraphPin* ToExecutePin = FindPin(K2Schema->PN_Execute);

			if ((FromThenPin != NULL) && (FromThenPin->LinkedTo.Num() == 0) && (ToExecutePin != NULL) && K2Schema->ArePinsCompatible(FromThenPin, ToExecutePin, NULL))
			{
				if (K2Schema->TryCreateConnection(FromThenPin, ToExecutePin))
				{
					NodeList.Add(FromPinNode);
					NodeList.Add(this);
				}
			}
		}

		// Send all nodes that received a new pin connection a notification
		for (auto It = NodeList.CreateConstIterator(); It; ++It)
		{
			UEdGraphNode* Node = (*It);
			Node->NodeConnectionListChanged();
		}
	}
}