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.

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.