TLDR; LoadObject<UBlueprint>(nullptr, *AssetPath) works only in PIE. not in standalone game nor packaged game
I have a simple code for loading a Blueprint Actor by providing the asset path String of the BP to LoadObject:
bool UAssetsCreationAndSpawningUtils::CreateBlueprint(FString AssetPath, UBlueprint*& Blueprint)
{
if (AssetPath.IsEmpty()) {
UE_LOG(LogTemp, Error, TEXT("UAssetsCreationAndSpawningUtils::CreateBlueprint: AssetPath is empty"));
return false;
}
// log the asset path
UE_LOG(LogTemp, Warning, TEXT("UAssetsCreationAndSpawningUtils::CreateBlueprint: AssetPath: %s"), *AssetPath);
// Load the Blueprint object from the asset path
UBlueprint* BlueprintIns = LoadObject<UBlueprint>(nullptr, *AssetPath);
// Check if the Blueprint was loaded successfully
if (BlueprintIns && BlueprintIns->GeneratedClass)
{
Blueprint = BlueprintIns;
return true;
}
return false;
}
For AssetPath I tried providing both:
‘’/Game/Characters/Humen/HumanPeasant/BP_HumanPeasant.BP_HumanPeasant"
and
“/Script/Engine.Blueprint’/Game/Characters/Humen/HumanPeasant/BP_HumanPeasant.BP_HumanPeasant’”
When running in PIE the BP is loaded (and spawned into the world later on) successfully.
but when running the game in “Standalone Game” from the editor or when playing as a packaged game, the asset is not found and in the log I get:
"
[2024.10.11-12.45.29:680][200]LogUObjectGlobals: Warning: Failed to find object ‘Blueprint /Game/Characters/Humen/HumanPeasant/BP_HumanPeasant.BP_HumanPeasant’
"
I’ve tried:
Putting an instance of the same BP in the world to make sure the BP is in the cooked game
Checked “cook everything in the project content directory (ignore list of maps below)” in Project Settings → Project → Packaging
Set “Build” to “always” in Project Settings → Project → Packaging (I have no idea what it does)
Put a 5 seconds delay after map/level loaded on “begin play” before trying to load
More “relevant” details:
The function is a static function in a UBlueprintFunctionLibrary and called from another Actor BP after “Event BeginPlay” node
The code is in a module I’ve create and NOT part of the PRIMARY_GAME_MODULE but in another “IMPLEMENT_MODULE” module
The BP I try to spawn extends the ACharacter class. just include 2 Cone primitives and the default SkeletalMeshComponent from ACharacter but doesn’t have an assigned SkeletalMeshAsset
I didn’t try AssetRegistry yet
From my understanding (and ChatGPT…) LoadObject suppose to work outside the editor
UBlueprint objects are not packaged, they are stripped during cook (most of them). Instead of loading Blueprint and accessing Blueprint->GeneratedClass, you can load directly the GeneratedClass. The path is obtained by appending a _C postfix on the UBlueprint path, so in this case /Game/Characters/Humen/HumanPeasant/BP_HumanPeasant.BP_HumanPeasant_C. You can load it as an UClass* (or UBlueprintGeneratedClass* if that matters).
The asset may not be packaged, if it is not referenced by project content. String references are not references (except when using FObjectFinder in constructors…). You can circumvent that by adding folder(s) of assets you load by path into “Additional Asset Directories to Cook” in Packaging settings.
Following the suggestions from @PREDALIEN and @Chatouille:
I came up with the following function to load a Blueprint based asset by providing it with Asset reference path string.
for example: function arg AssetPath = "/Game/Characters/Humen/HumanPeasant/BP_HumanPeasant.BP_HumanPeasant"
bool UAssetsCreationAndSpawningUtils::CreateBlueprintAsset(FString AssetPath, UClass*& Output)
{
if (AssetPath.IsEmpty()) {
UE_LOG(LogTemp, Error, TEXT("UAssetsCreationAndSpawningUtils::CreateBlueprintAsset: AssetPath is empty"));
return false;
}
#if !WITH_EDITOR
if (!AssetPath.EndsWith("_C")) {
// suffix AssetParth with _C and try to load again as generated blueprint class
AssetPath += "_C";
}
#endif
FSoftObjectPath AssSOP(AssetPath);
UObject* LoadedObject = AssSOP.TryLoad();
if (LoadedObject)
{
// Asset was found and loaded
#if WITH_EDITOR
// Cast the loaded object to a Blueprint
UBlueprint* Blueprint = Cast<UBlueprint>(LoadedObject);
if (Blueprint && Blueprint->GeneratedClass)
{
// Get the class generated by the Blueprint
Output = Blueprint->GeneratedClass;
return true;
}
#else
// Convert the Asset to a UClass
UClass* LoadedUClass = Cast<UClass>(LoadedObject);
if (LoadedUClass) {
Output = LoadedUClass;
return true;
}
#endif
}
return false;
}
How to spawn the loaded asset into the world example:
UClass* Asset;
const bool b_AssetCreated = UAssetsCreationAndSpawningUtils::CreateBlueprintAsset(AssetPath, Asset);
if (!b_AssetCreated || !Asset) {
UE_LOG(LogTemp, Error, TEXT("UAssetsCreationAndSpawningUtils::SpawnBlueprintActor: Failed to create blueprint for asset %s"), *AssetPath);
return false;
}
if (!Asset->IsChildOf(AActor::StaticClass())) {
UE_LOG(LogTemp, Error, TEXT("UAssetsCreationAndSpawningUtils::SpawnBlueprintActor: Blueprint %s is not a child of AActor"), *AssetPath);
return false;
}
SpawnedCharacter = World->SpawnActor<AActor>(Asset, Transform);
return true;
Summary:
The class loaded can be UBlueprint or UClass - depending where the game is running.
Blueprint Asset, once compiled for a build (development / shipping / …) is no longer a UBlueprint that you need to fetch it’s class by calling GeneratedClass but the asset itself is the UClass
The Blueprint reference string changes. you’ll need to append _C at the end of the path. so “/Game/Characters/…/BP_HumanPeasant.BP_HumanPeasant” will be “/Game/Characters/…/BP_HumanPeasant.BP_HumanPeasant_C”
When playing in editor (PIE or Standalone Game) it’s a UBlueprint, but when shipped it will just be a UClass. so probably best to use #if WITH_EDITOR preprocessor to branch to the appropriate code and casting.
Using LoadObject as in the original post, might work, but will need to get UClass and not UBlueprint depending of the environemt the game is running - again using #if WITH_EDITOR preprocessor (I didn’t test it cause at this point… I just don’t care.)
The above code was tested on version 5.4.3 on windows in PIE, Standalone Game, Shipping package and Development package.
I hope this will help others that might follow my path of not finding good documantation but needs the help of a number of docs and YT videos, ChatGPT and most importantly - good strangers in UE forums.
I might be wrong, but I expect there should be a simpler way to load a BP based asset safely without silly 'if’s.
prove me right.