How to create and populate an Event Graph in C++?

Hello, I am working on a Blueprint generator.
I want to create blueprints based on objects described in files. These descriptions include behaviour, this is why I need to create a BP Event Graph.

In this function, I create an empty Blueprint:

TObjectPtr<UBlueprint> CreateBlueprint(FString BpPath, TSubclassOf<UObject> ParentClass) {
	// Check if there is already an asset at the path's location.
	if (StaticLoadObject(UObject::StaticClass(), nullptr, *BpPath))
		return nullptr;

	// Check that the parent class is blueprintable
	if (!FKismetEditorUtilities::CanCreateBlueprintOfClass(ParentClass))
		return nullptr;

	// Create a package
	TObjectPtr<UPackage> Package = CreatePackage(*BpPath);
	if (!Package.Get())
		return nullptr;

	// Find the Blueprint Class to create
	UClass* BpClass = nullptr;
	UClass* BpGenClass = nullptr;
	FModuleManager::LoadModuleChecked<IKismetCompilerInterface>("KismetCompiler")
		.GetBlueprintTypesForClass(ParentClass, BpClass, BpGenClass);

	// Create the Blueprint
	TObjectPtr<UBlueprint> Blueprint = FKismetEditorUtilities::CreateBlueprint(
		ParentClass,
		Package,
		*FPaths::GetBaseFilename(BpPath),
		BPTYPE_Normal,
		BpClass,
		BpGenClass
	);

	// Add an Event Graph to the Blueprint
	// Add Nodes to the Event Graph
	// Connect the Nodes

	/*
	Example Event Graph:

	[OnTick]--->[AddActorLocalRotation]
			    [Actor = this		  ]
				[Rotation = (0, 1, 0) ]	
	*/

	// Register the Blueprint
	FAssetRegistryModule::AssetCreated(Blueprint);
	Blueprint->MarkPackageDirty();

	return Blueprint;
}

My current goal is to create a dummy Event Graph like the one in the comment.

How can I create the Event Graph, populate it with Nodes (built-in nodes, not custom) and connect them?

Thanks a lot in advance.

Add a graph to a blueprint:

UEdGraph* Graph = FBlueprintEditorUtils::CreateNewGraph(TargetBlueprint, FBlueprintEditorUtils::GenerateUniqueGraphName(TargetBlueprint, "New Graph"), UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass());
FBlueprintEditorUtils::AddUbergraphPage(TargetBlueprint, Graph);

Most nodes in blueprint are CallFunction node (including AddActorLocalRotation). If you click on a node - will be opened the original C++ function in Visual Studio.

UK2Node_CallFunction* CallFuncNode;
FGraphNodeCreator<UK2Node_CallFunction> Creator(*TargetGraph);
CallFuncNode->FunctionReference.SetExternalMember(GET_FUNCTION_NAME_CHECKED(AActor, K2_AddActorLocalRotation), AActor::StaticClass()); 

// The macro is needed to check at the compilation stage that you have specified the class and function name correctly.

Creator.Finalize(); // Necessarily call this

Event nodes (including event tick):

UK2Node_Event* EventNode;
EventNode->EventReference.  // Im not sure, but maybe similar to call function node

Some nodes have functions to quickly get some pins:

GetExecPin(), GetThenPin(), GetReturnValuePin() //etc.

You can connect pins as follows:

NodeReference->GetThenPin()->MakeLinkTo(OtherNode->GetExecPin());
// or:
NodeReference->FindPin(PinName, PinDirection)->MakeLinkTo // etc.
// Pin Direction = EGPD_Input/EGPD_Output

Many pin names are pre-written in the schema_k2, for example:

UEdGraphSchema_K2::PN_Execute // Input pin
UEdGraphSchema_K2::PN_Then // Output Pin

Default values ​​for pins should be set to DefaultValue, DefaultObject, or DefaultTextValue respectively.

I think this information will be enough to start with. :kissing_smiling_eyes:

Thanks for your response.

I did manage to find a way to add a Node to the graph myself too:

TObjectPtr<UEdGraphNode> CreateNode(TObjectPtr<UEdGraph> EventGraph, FName FunctionName, TSubclassOf<UObject> ParentClass, FVector2D Location) {
	UFunction* Function = ParentClass->FindFunctionByName(FunctionName);
	if (!Function) {
		UE_LOG(LogTemp, Warning, TEXT("Function does not exist"));
		return nullptr; // Check if the function exists
	}

	// Create a new function node in the Event Graph
	UEdGraphNode* Node = NewObject<UEdGraphNode>(EventGraph);

	UBlueprintFunctionNodeSpawner* FunctionNodeSpawner = UBlueprintFunctionNodeSpawner::Create(Function);
	if (!FunctionNodeSpawner) return nullptr;
	
	FunctionNodeSpawner->SetFlags(RF_Transactional);
	Node = FunctionNodeSpawner->Invoke(EventGraph, IBlueprintNodeBinder::FBindingSet(), Location);

	return Node;
}

I see our approaches differ. Here are the main differences:

  1. I do not create a graph, an Event Graph is automatically created when creating an empty BP.
  2. I didn’t know you could see the Node’s C++ FName this way, I’ll have to look into that.
  3. You are using FGraphCreator whereas I’m using a UBlueprintFunctionNodeSpawner. Do you know which one is the best/most idiomatic way of doing this?
  4. I hadn’t yet implemented pin connections, I’ll also look into that, thanks.
1 Like

Some nodes require additional settings when creating, this is done by Spawner.
It is also used when the user manually creates nodes.
Creator - takes care of the necessary minimum for the correct creation of the node.

In the source code I came across Creator more often, and for my tasks it always worked.
But if you need more variability or control, then Spawner is what you need.