Create Blueprint Asset in C++
Following code is possible to use in UBlueprintFunctionLibrary
inherited class.
The code below is an analogy of manual creation of assets in the Unreal Engine editor by clicking right mouse button in Content Drawer
and selecting an asset to create.
Based on set Parent Class
parameter, there's possible to create any type of Blueprint asset (such as Actor
, Static mesh Actor
, Character
, Widget
, ChildBlueprint of another Blueprint
...) with the C++ code right in the editor.
/**
* Editor Only - Will not work in packaged build.
*
* Create a blueprint asset
*
* @param BlueprintPath Path of the blueprint: "/Game/Folder/MyBp"
* @param bOutSuccess If the action was a success or not
* @param OutInfoMsg More information about the action's result
*
* @return The created blueprint
*/
UFUNCTION(BlueprintCallable, Category = "Alex Quevillon | Create Blueprint")
static UBlueprint* CreateBlueprint(FString BlueprintPath, TSubclassOf<UObject> ParentClass, bool& bOutSuccess, FString& OutInfoMsg);
#include "AssetRegistry/AssetRegistryModule.h" // AssetRegistry
#include "Kismet2/KismetEditorUtilities.h"// UnrealEd (Editor Only)
#include "KismetCompilerModule.h" // KismetCompiler (Editor Only)
UBlueprint* UExampleClass::CreateBlueprint(FString BlueprintPath, TSubclassOf<UObject> ParentClass, bool& bOutSuccess, FString& OutInfoMsg)
{
// Make sure an asset doesn't already exist with that path
if (StaticLoadObject(UObject::StaticClass(), nullptr, *BlueprintPath) != nullptr)
{
bOutSuccess = false;
OutInfoMsg = FString::Printf(TEXT("Create Blueprint Failed - An asset already exists at that location. '%s'"), *BlueprintPath);
return nullptr;
}
// Make sure the parent class is valid
if (!FKismetEditorUtilities::CanCreateBlueprintOfClass(ParentClass))
{
bOutSuccess = false;
OutInfoMsg = FString::Printf(TEXT("Create Blueprint Failed - Parent class is not blueprintable. '%s'"), *BlueprintPath);
return nullptr;
}
// Create asset package
UPackage* Package = CreatePackage(*BlueprintPath);
if (Package == nullptr)
{
bOutSuccess = false;
OutInfoMsg = FString::Printf(TEXT("Create Blueprint Failed - Failed to create the asset package. Make sure the path is valid. '%s'"), *BlueprintPath);
return nullptr;
}
// Find the blueprint classes to create
UClass* BpClass = nullptr;
UClass* BpGenClass = nullptr;
FModuleManager::LoadModuleChecked<IKismetCompilerInterface>("KismetCompiler").GetBlueprintTypesForClass(ParentClass, BpClass, BpGenClass);
// Create asset
UBlueprint* Blueprint = FKismetEditorUtilities::CreateBlueprint(ParentClass, Package, *FPaths::GetBaseFilename(BlueprintPath), BPTYPE_Normal, BpClass, BpGenClass);
// Register asset
FAssetRegistryModule::AssetCreated(Blueprint);
Blueprint->MarkPackageDirty();
// Return the asset
bOutSuccess = true;
OutInfoMsg = FString::Printf(TEXT("Create Blueprint Succeeded - '%s'"), *BlueprintPath);
return Blueprint;
}
PrivateDependencyModuleNames.AddRange
(
new string[]
{
// Default Modules
"Core",
"CoreUObject",
"Engine",
// New Modules
"AssetRegistry",
// New Modules - Editor Only
"UnrealEd",
"KismetCompiler",
}
);
Compile Blueprint asset with C++
/**
* Editor Only - Will not work in packaged build.
*
* Compile a blueprint asset
*
* @param BlueprintPath Path of the blueprint: "/Game/Folder/MyBp"
* @param OutInfoMsg More information about the action's result
* @param return If the action was a success or not
*/
UFUNCTION(BlueprintCallable, Category = "Alex Quevillon | Compile Blueprint")
static void CompileBlueprint(FString BlueprintPath, FString& OutInfoMsg);
#include "Kismet2/KismetEditorUtilities.h" // UnrealEd (Editor Only)
#include "Kismet2/CompilerResultsLog.h" // UnrealEd (Editor Only)
bool UExampleClass::CompileBlueprint(FString BlueprintPath, FString& OutInfoMsg)
{
// Load blueprint asset
UBlueprint* Blueprint = Cast<UBlueprint>(StaticLoadObject(UBlueprint::StaticClass(), nullptr, *BlueprintPath));
if (Blueprint == nullptr)
{
OutInfoMsg = FString::Printf(TEXT("Compile Blueprint Failed - Path doesn't lead to a valid Blueprint. '%s'"), *BlueprintPath);
return false;
}
// Compile blueprint
FCompilerResultsLog Result;
FKismetEditorUtilities::CompileBlueprint(Blueprint, EBlueprintCompileOptions::SkipSave, &Result);
// Format the result
FString Logs = Result.Messages.Num() > Result.NumWarnings + Result.NumErrors ? "\n--- Logs ---" : "";
FString Warnings = Result.NumWarnings > 0 ? "\n--- Warnings ---" : "";
FString Errors = Result.NumErrors > 0 ? "\n--- Errors ---" : "";
for (TSharedRef<FTokenizedMessage> Message : Result.Messages)
{
switch (Message.Get().GetSeverity())
{
default:
case EMessageSeverity::Type::Info:
Logs += "\n" + Message.Get().ToText().ToString();
break;
case EMessageSeverity::Type::Warning:
case EMessageSeverity::Type::PerformanceWarning:
Warnings += "\n" + Message.Get().ToText().ToString();
break;
case EMessageSeverity::Type::Error:
Errors += "\n" + Message.Get().ToText().ToString();
break;
}
}
// Return the result
bool bSuccess = Result.NumErrors == 0;
FString SucceededOrFailed = bSuccess ? "Succeeded" : "Failed";
FString Messages = Logs + Warnings + Errors;
OutInfoMsg = FString::Printf(TEXT("Compile Blueprint %s - '%s' %s"), *SucceededOrFailed, *BlueprintPath, *Messages);
return bSuccess;
}
PrivateDependencyModuleNames.AddRange
(
new string[]
{
// Default Modules
"Core",
"CoreUObject",
"Engine",
// New Modules - Editor Only
"UnrealEd",
}
);
Spawn Actor to any Blueprint
AddNodeToBlueprint
defined below will be used by functions adding various kind of actors into any blueprint based on its BlueprintPath
.
This way of adding any Actor
to any Blueprint comes in handy if we need to extend 1 or more Bluperint actors from one place - e.g. during automatization process. If we code a C++ class, from which a blueprint asset is inherited, adding actors to blueprint is easy to do through the common way.
Add a component node to a blueprint asset (Help function)
/**
* Editor Only - Will not work in packaged build.
*
* Add a component node to a blueprint asset
*
* @param BlueprintPath Path of the blueprint: "/Game/Folder/MyBp"
* @param ComponentTemplate The component to use as a template when creating the node
* @param ParentNodeName The name of the desired parent node
* @param bOutSuccess If the action was a success or not
* @param OutInfoMsg More information about the action's result
*
* @return The node that was created
*/
UFUNCTION(BlueprintCallable, Category = "Add Components To Blueprint")
static class USCS_Node* AddNodeToBlueprint(FString BlueprintPath, class USceneComponent* ComponentTemplate, FString ParentNodeName, bool& bOutSuccess, FString& OutInfoMsg);
#include "Engine/SCS_Node.h" // Engine
#include "Kismet2/BlueprintEditorUtils.h" // UnrealEd (Editor Only)
USCS_Node* UExampleClass::AddNodeToBlueprint(FString BlueprintPath, USceneComponent* ComponentTemplate, FString ParentNodeName, bool& bOutSuccess, FString& OutInfoMsg)
{
// Load blueprint asset
UBlueprint* Blueprint = Cast<UBlueprint>(StaticLoadObject(UBlueprint::StaticClass(), nullptr, *BlueprintPath));
if (Blueprint == nullptr)
{
bOutSuccess = false;
OutInfoMsg = FString::Printf(TEXT("Add Node To Blueprint Failed - Path doesn't lead to a valid Blueprint. '%s'"), *BlueprintPath);
return nullptr;
}
// Create new node in blueprint asset
USCS_Node* NewNode = Blueprint->SimpleConstructionScript->CreateNode(ComponentTemplate->GetClass(), *ComponentTemplate->GetName());
// Parent node
USCS_Node* ParentNode = Blueprint->SimpleConstructionScript->FindSCSNode(*ParentNodeName);
if (ParentNode != nullptr) {
ParentNode->AddChildNode(NewNode);
} else {
TArray<USCS_Node*> AllNodes = Blueprint->SimpleConstructionScript->GetAllNodes();
// If there are no nodes in the blueprint or if the root node is still the default node
if (AllNodes.Num() == 0 || AllNodes[0] == Blueprint->SimpleConstructionScript->GetDefaultSceneRootNode()) {
// Use this component as root node
Blueprint->SimpleConstructionScript->AddNode(NewNode);
} else {
// Use the first node as parent (root node)
AllNodes[0]->AddChildNode(NewNode);
}
}
// Copy component's settings onto node
UEditorEngine::CopyPropertiesForUnrelatedObjects(ComponentTemplate, NewNode->ComponentTemplate);
// Notify the engine we modified the blueprint components
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(Blueprint);
// Return new node
bOutSuccess = true;
OutInfoMsg = FString::Printf(TEXT("Add Node To Blueprint Succeeded - '%s'"), *BlueprintPath);
return NewNode;
}
PrivateDependencyModuleNames.AddRange
(
new string[]
{
// Default Modules
"Core",
"CoreUObject",
"Engine",
// New Modules - Editor Only
"UnrealEd",
}
);
-
Add a scene component to a blueprint asset
.h/** * Editor Only - Will not work in packaged build. * * Add a scene component to a blueprint asset * * @param BlueprintPath Path of the blueprint: "/Game/Folder/MyBp" * @param bOutSuccess If the action was a success or not * @param OutInfoMsg More information about the action's result * * @return The node that was created */ UFUNCTION(BlueprintCallable, Category = "Add Components To Blueprint") static class USCS_Node* AddSceneComponentToBlueprint(FString BlueprintPath, bool& bOutSuccess, FString& OutInfoMsg);
.cpp#include "Engine/SCS_Node.h" // Engine #include "Kismet2/BlueprintEditorUtils.h" // UnrealEd (Editor Only) USCS_Node* UExampleClass::AddSceneComponentToBlueprint(FString BlueprintPath, bool& bOutSuccess, FString& OutInfoMsg) { // Create component USceneComponent* Component = NewObject<USceneComponent>(GetTransientPackage(), "My_Scene_Component_Name", RF_Transient); Component->SetRelativeLocation(FVector(0.0f, 0.0f, 100.0f)); Component->SetRelativeRotation(FRotator(0.0f, 0.0f, 0.0f)); Component->SetRelativeScale3D(FVector(1.0f, 1.0f, 1.0f)); Component->SetMobility(EComponentMobility::Type::Static); Component->SetHiddenInGame(true, false); Component->ComponentTags.Add("My Tag"); // Create node in blueprint USCS_Node* NewNode = AddNodeToBlueprint(BlueprintPath, Component, "None", bOutSuccess, OutInfoMsg); return NewNode; }
.Build.csPrivateDependencyModuleNames.AddRange ( new string[] { // Default Modules "Core", "CoreUObject", "Engine", // New Modules - Editor Only "UnrealEd", } );
-
Add a point light component to a blueprint asset
.h/** * Editor Only - Will not work in packaged build. * * Add a point light component to a blueprint asset * * @param BlueprintPath Path of the blueprint: "/Game/Folder/MyBp" * @param bOutSuccess If the action was a success or not * @param OutInfoMsg More information about the action's result * * @return The node that was created */ UFUNCTION(BlueprintCallable, Category = "Add Components To Blueprint") static class USCS_Node* AddPointLightComponentToBlueprint(FString BlueprintPath, bool& bOutSuccess, FString& OutInfoMsg);
.cpp#include "Engine/SCS_Node.h" // Engine #include "Kismet2/BlueprintEditorUtils.h" // UnrealEd (Editor Only) #include "Components/PointLightComponent.h" // Engine USCS_Node* UExampleClass::AddPointLightComponentToBlueprint(FString BlueprintPath, bool& bOutSuccess, FString& OutInfoMsg) { // Create component UPointLightComponent* Component = NewObject<UPointLightComponent>(GetTransientPackage(), "My_Point_Light_Component_Name", RF_Transient); Component->SetRelativeLocation(FVector(100.0f, 0.0f, 0.0f)); Component->ComponentTags.Add("My Tag"); Component->SetLightColor(FLinearColor::Blue); Component->SetIntensity(5000.0f); Component->SetSourceRadius(FMath::RandRange(100.0f, 500.0f)); Component->SetAttenuationRadius(FMath::RandRange(1000.0f, 5000.0f)); // Create node in blueprint USCS_Node* NewNode = AddNodeToBlueprint(BlueprintPath, Component, "My_Scene_Component_Name", bOutSuccess, OutInfoMsg); return NewNode; }
.Build.csPrivateDependencyModuleNames.AddRange ( new string[] { // Default Modules "Core", "CoreUObject", "Engine", // New Modules - Editor Only "UnrealEd", } );
-
Add a camera component to a blueprint asset
.h/** * Editor Only - Will not work in packaged build. * * Add a camera component to a blueprint asset * * @param BlueprintPath Path of the blueprint: "/Game/Folder/MyBp" * @param bOutSuccess If the action was a success or not * @param OutInfoMsg More information about the action's result * * @return The node that was created */ UFUNCTION(BlueprintCallable, Category = "Add Components To Blueprint") static class USCS_Node* AddCameraComponentToBlueprint(FString BlueprintPath, bool& bOutSuccess, FString& OutInfoMsg);
.cpp#include "Engine/SCS_Node.h" // Engine #include "Kismet2/BlueprintEditorUtils.h" // UnrealEd (Editor Only) #include "Camera/CameraComponent.h" // Engine USCS_Node* UExampleClass::AddCameraComponentToBlueprint(FString BlueprintPath, bool& bOutSuccess, FString& OutInfoMsg) { // Create component UCameraComponent* Component = NewObject<UCameraComponent>(GetTransientPackage(), "My_Camera_Component_Name", RF_Transient); Component->SetFieldOfView(66.0f); Component->SetConstraintAspectRatio(true); Component->SetAspectRatio(2.22f); Component->bLockToHmd = false; // Create node in blueprint USCS_Node* NewNode = AddNodeToBlueprint(BlueprintPath, Component, "My_Point_Light_Component_Name", bOutSuccess, OutInfoMsg); return NewNode; }
.Build.csPrivateDependencyModuleNames.AddRange ( new string[] { // Default Modules "Core", "CoreUObject", "Engine", // New Modules - Editor Only "UnrealEd", } );