Creating and editing Blueprint from C++

Hello,
I am working on a plugin who import a file and create the corresponding actor completely setup and ready to use in UE.
The file is correctly readed but I am stuck on the creation of the Actor : I created a C++ class derivated from AActor. I can instantiate it from C++ but I am unable to save this instance as an Asset on the Content Browser. From the UI I can create a Blueprint derivated from this C++ class but I am unable to find how to do the same thing from code.

There is a way to save this ready to use instance on the Content Browser ?
Thanks in advance.

First create a package for your new asset (blueprint), then use FKismetEditorUtilities::CreateBlueprint to create a blueprint based on your parent class.

UPackage* Package = CreatePackage("/Game/Blueprints/BP_MyClass");

// Create and init a new Blueprint
UBlueprint* Blueprint = FKismetEditorUtilities::CreateBlueprint(ParentClass, Package, "BP_MyClass", BPTYPE_Normal, UBlueprint::StaticClass(), UBlueprintGeneratedClass::StaticClass());

if (Blueprint)
{
	// Notify the asset registry
	FAssetRegistryModule::AssetCreated(Blueprint);

	// Mark the package dirty...
	Package->MarkPackageDirty();
}

Hello,

I can create a blueprint derivated from my C++ class but I would like now to tune the properties values to make the BP ready to use for the user. I have this for now:

FName BluePrintName = FName(ObjectTools::SanitizeObjectName("A_MyBPActor");
FString AssetPath = InParent->GetName() + "/" + BluePrintName.ToString();
UPackage* BluePrintPackage = MyUtilsClass::PreparePackage(BluePrintName.ToString(), AssetPath);

// Create and init a new blank Blueprint
UBlueprint* Blueprint = FKismetEditorUtilities::CreateBlueprint(AMyActor::StaticClass(), BluePrintPackage, BluePrintName, BPTYPE_Normal, UBlueprint::StaticClass(), UBlueprintGeneratedClass::StaticClass());

if (Blueprint) {

	// HERE I WOULD LIKE TO EDIT ACTOR PROPERTIES

	// Save the Asset init
	FCompilerResultsLog LogResults; // We don't really care of the logs here.
	FKismetEditorUtilities::CompileBlueprint(Blueprint, EBlueprintCompileOptions::None, &LogResults);

	// Notify the asset registry
	FAssetRegistryModule::AssetCreated(Blueprint);

	// Mark the package dirty...
	BluePrintPackage->MarkPackageDirty();
}

I found this who seems to be interesting but it fails trying to get the value because it is a blueprint instance and not AMyActor instance : Edit Blueprint Variable in C++

Default values are stored in the Class Default Object (CDO).

After creating blueprint, you can get the UClass (which should be a BlueprintGeneratedClass if that matters) via Blueprint->GeneratedClass.

Then you can get the CDO via Class->GetDefaultObject().

So here is an example :

UClass* Class = Blueprint->GeneratedClass;
AMyActor* CDO = Class->GetDefaultObject<AMyActor>();

// For c++ properties you can edit them directly
CDO->SomeCppProperty = 42.f;

// If you are generating new BP properties, you'll have to modify them through reflection
UProperty* SomeBpProp = Class->FindPropertyByName("SomeBpProp");
*SomeBpProp->ContainerPtrToValuePtr<float>(CDO) = 42.f;

Whether you need to compile before accessing it, or after modifying it, I have no idea, you’ll have to figure it out through trial and error.

2 Likes

I already tried to edit the CDO some days ago but my edits wasn’t restored after a reboot of Unreal. I finally found why: I forgotten to compile the blueprint after my edits :man_facepalming:.
Finally the complete working code is:

FName BluePrintName = FName(ObjectTools::SanitizeObjectName("A_MyBPActor");
FString AssetPath = InParent->GetName() + "/" + BluePrintName.ToString();
UPackage* BluePrintPackage = MyUtilsClass::PreparePackage(BluePrintName.ToString(), AssetPath);

// Create and init a new blank Blueprint
UBlueprint* Blueprint = FKismetEditorUtilities::CreateBlueprint(AMyActor::StaticClass(), BluePrintPackage, BluePrintName, BPTYPE_Normal, UBlueprint::StaticClass(), UBlueprintGeneratedClass::StaticClass());

if (Blueprint) {

	// Editing the BluePrint
	AMyActor* BlueprintValues = Blueprint->GeneratedClass.Get()->GetDefaultObject<AMyActor>();
	BlueprintValues->bSomeProperty = true;

	// Compile the changes
	FCompilerResultsLog LogResults; // We don't really care of the logs here.
	FKismetEditorUtilities::CompileBlueprint(Blueprint, EBlueprintCompileOptions::None, &LogResults);

	// Notify the asset registry
	FAssetRegistryModule::AssetCreated(Blueprint);

	// Mark the package dirty...
	BluePrintPackage->MarkPackageDirty();
}

Thanks a lot !

2 Likes

Thank you d-gardes!!

Your solution works flawless, tested 05/07/2023, I’ll share my code here to add another example. In my case i used an UObject derived class instead of an AActor, keep in mind that when deriving directly from UObject we need to mark the UClass of that object as BlueprintType and Blueprintable.

UCLASS(BlueprintType,Blueprintable)

My adition:

void MyUObjectDerivedBlueprintMaker::CreateChildBlueprint()
{
	FString FolderPath = TEXT("/Game/DesiredFolder/");
	UPackage* FolderPackage = CreatePackage( *FolderPath);
	FString FileName = TEXT("BlueprintName");
	FString PackageName = FolderPath + FileName;

	UObjectDerived* NewBlueprint = FKismetEditorUtilities::CreateBlueprint(
		UObjectDerived::StaticClass(),
		FolderPackage,
		*FileName,
		BPTYPE_Normal,
		UBlueprint::StaticClass(),
		UBlueprintGeneratedClass::StaticClass()
	);

	if (NewBlueprint)
	{

		// Editing the BluePrint
		UObjectDerived* UObjectDefaultValues = NewBlueprint->GeneratedClass.Get()->GetDefaultObject<UObjectDerived>();
		UObjectDefaultValues->bSomeVariable = true;

		// Compile the changes
		FCompilerResultsLog LogResults;
		FKismetEditorUtilities::CompileBlueprint(NewBlueprint, EBlueprintCompileOptions::None, &LogResults);

		// Notify the asset registry
		FAssetRegistryModule::AssetCreated(NewBlueprint);

		// Mark the package dirty...
		FolderPackage->MarkPackageDirty();
	}
}

I also used an UEditorUtilityWidget derived as a generator, once again thank you for the answer!

1 Like