How do I load a blueprint in C++?

There are a lot of similar question, I know, but almost all of them revert to having to select the blueprint in the editor as a property of the C++ class. This is not going to work for me. I am trying to write a factory class that allows me to spawn actors by ID at runtime, essentially procedurally generated.

I have tried using a ConstructorHelpers:FObjectFinder but this doesn’t work. But then calling StaticLoadObject() doesn’t work either.

Here is my current code. It is a bit more verbose than usual to allow me to explore what is happening.

UObject *obj_ptr = StaticLoadObject(UObject::StaticClass(), NULL, TEXT("/Blueprint'/Game/Props/LitTorch.LitTorch'"));

The resulting pointer is null. I get this error: LogUObjectGlobals: Warning: Failed to find object ‘Object /Game/Props/SM_LitTorch.SM_LitTorch’

I also tried using the string Blueprint'/Game/Props/LitTorch' but then got an error at compile time about not being able to find the package.

This is the common advice because it’s the best practice for configuring these types of content references. Constructor helpers are bad for real projects and have many, many, many downsides and zero upsides. They are used in the templates for reasons that aren’t applicable to “real” projects.

It is also significantly less error prone (as you’re finding with the paths) to select them using the Editor UI and allows non-coders to configure things.

A half step if you just want a place to create an association between IDs and blueprints would be a UDeveloperSettings class that would automatically have it’s properties show up in the Project Settings of the Editor.

However, if I were building this sort of system I would do this (I’m going to throw a lot of engine names around so you have search terms or can ask specific questions):

  1. Create a primary data asset type to represent a piece of content (let’s say, UPCG_PDA). This would have a reference to the blueprint to spawn (as a soft reference), maybe an ID (though this plan wouldn’t require it) and any additional simple meta data about the actor you might use for deciding to spawn it (size, type, etc)
  2. At some point (main menu, game start, etc) you’d load all the instances of UPCG_PDA’s that exist in your content. This shouldn’t be a problem since the blueprint would be a soft reference and the data asset itself would be very small.
  3. After loading them, you could preprocess them to create a mapping by ID or types or whatever you want in order to look them up.
  4. At some point you load the blueprint from the soft reference on the pda. Maybe this is during generation. Maybe you have enough metadata to do the generation entirely using the pda and only load the blueprints after you finish the generation and know what blueprints to load.

The additional benefit to this (or even the DeveloperSettings approach) is that as you make new content, you don’t require a recompile to update your references. And you don’t open yourself up for the sorts of terrible things that ConstructorHelpers have been known to do to projects.

Again, the reason that you’re seeing that as the consistent advice is because it really is the best way to do it and the pattern to get comfortable with from the start of development.

Umm. So if I have a hundred blueprint actors, then I need a hundred C++ classes and then need to manually, in the editor, select the correct blueprint for each C++ class in turn.

No thanks.

Also, I am not proposing using constructor helpers. I am proposing using StaticLoadObject(). Forgive my ignorance if that is basically the same thing.

What I want to be able to do is something like this:

namespace {
    const std::vector<const char *>  ASSETS =
    {
        "/Blueprint'/Game/Props/LitTorch.LitTorch'",
        "StaticMesh'/Game/Props/Chair",
etc. etc.
    };
}

void ObjectFactory::Initialise()
{
    for (uint16_t i = 0u; i < ASSETS.size(); ++i)
    {
        UObject *object = LoadTheDamnAssetByItspath(ASSETS[i]);

        m_assets.emplace(i, object);
    }
}


AActor *ObjectFactory::CreateAsset(uint16_t id, const FVector &position, const FRotator &rotation)
{
    AActor *result = nullptr;
    auto    it     = m_assets.find(id);

    if (m_assets.end() == it)
    {
        UE_LOG(LogTemp, Warning, TEXT("Object type %u not known by factory."), id);
    }
    else
    {
        result = m_world->SpawnActor<AActor>(.... etc. etc. ...);
    }

    return result;
}        

To add an asset to my factory now takes 1 line of code. Not a whole new class and a load of clicking around in the editor.

I am really new. This whole explanation went right over my head. What is UPCG_PDA?

MagForceSeven:

you don’t require a recompile to update your references.

I am a C++ engineer. My work pattern is code→compile→test→code→compile→test. I am working on a fully procedural game. My map is literally empty. I have to have a map so I call it “empty” and the file is “empty.umap”. I only use the editor to play around and see how things look, or mess about with materials and particle effects. So I am completely happy to recompile every time I make a change.

The only reason I want to use a blueprint is I don’t know any other way to combine a static mesh and a particle effect within a single asset. Currently my object factory has to manually detect specific asset IDs and manually attach the particle effect to the static mesh. And then detect the asset when destroying it and deactivate the particle effect. it is a pain.

So I just saw this text on the internet: “The CompileAllBlueprints commandlet allows you to recompile all Blueprint assets in your project from the command line”.

I am using RunUBT.sh and RunUAT.sh to build my project. At no point do I use that “commandlet”. The example I was following did not mention it at all. Should I be? My build steps are:

RunUBT.sh MyGame Linux DebugGame -Project=my_game.uproject
RunUAt.sh BuildCookRun -project=my_game.uproject -targetplatform=Linux -pak -package -stage -cook -clientconfig=DebugGame

If I put a bad path to StaticLoadObject() then this build fails, which is a bit weird. But the lack of that error seems to suggest that the reference is valid in some way.

Not at all, you only need to have 1 class that has all the configuration data. You don’t need a unique one for every blueprint. With the thing I was proposing you’d have two assets for every pcg thing, not a unique class per pcg thing.

Fair enough. However most of the downsides are true for any hardcoding of asset paths in the manner that you are proposing.

So am I, so I understand that. However there are things that you shouldn’t have to restart the editor for, like adding new elements to your PCG set. Changing the algorithm, sure. But adding chair #6 that’s similar to the other ones, it’s just a waste of time. You’re probably working alone, but maybe someday you wanna work with someone else, maybe an artist to make nicer pcg elements than you can. They’re not going to be going to editing code.
My primary hobby project is also an empty map because it’s a tactics game and procedurally add elements to the map. So I really, really do get it.

That was just a made up type so that I could refer back to “a procedurally generated content primary data asset” by short hand.

That’s okay. I’m happy to explain or link to things for specific questions if you don’t find them on your own. Likely any alternative will have a learning curve if you’re new and that’s not a bad thing.
Alternatively there’s a thing in the engine called the Asset Registry. It’s possible that if you organized all your content in a reasonable way, you could ask it for the list of all the blueprints in a particular content directory (or directories) to build that list instead of hardcoding it.

No. That’s just an automated way to compile blueprints the way they are in the Editor to check for errors. Teams will use it on automated build machines to validate that blueprints still compile after someone checks a change into source control.

I guess you’re running UBT manually because Linux doesn’t have a reasonable IDE with Unreal Integration?
I think that you’re way to early in your process to be building and running cooked builds. You should build DebugGameEditor and run that. If you want to test it running, just use the Play In Editor (PIE) that is almost always good enough.

The lack of an error is because you’ve hardcoded a path and the cook doesn’t/can’t/won’t inspect any code. It’s strictly an asset processing tool. And you won’t get any errors from the compile because it only deals in code and knows nothing about assets. So your build fails with a runtime issue because that’s the earliest it can be known. This is one reason (among many) why hardcoding asset paths is discouraged.
It’s also possible (I don’t know how you have your project cook settings set up) that the cook is skipping all your pcg blueprints because nothing that it would cook is referencing them. Admittedly that’s kinda the whole point, I get that. But references from code won’t cause assets to be included in the cook.
In the plan I suggested with the primary data asset, that asset would be something that always cooks and because it would reference the blueprint for the actual content, the blueprint would get cooked. Also you would get errors during the cook (or even blueprint compile I think) if you had a reference from one of those assets to a blueprint that no longer exists.
But if you went with the Asset Registry solution, there are ways to make sure that content is cooked without being referenced.

Listen, the engine really is designed to use both Blueprint and C++ in concert with each other. If you fight that, you’re just going to cause yourself unneeded frustration. If you want to use a hammer with screws, that’s fine but you’re not going to get much useful help. You’re going to get (and find) lots of “use a screwdriver with screws”. Not understanding how to use a screwdriver doesn’t make it any less the right tool. This forum (or the Unreal Slackers discord) want to help you understand it.

What about having a struct that contains an array of soft pointers. Then you can add the assets in the editor and use them in C++ by just using LoadSynchronous()?

You can pass in a different struct for each level to your factory.

If you want to keep it all in C++, I’m sure you can create soft pointers with the asset path.