Managing Blueprints for level designers

Hi there,

We’re trying to figure out how to manage the exposure and categorization of Blueprints so that level designs can easily find them, and so level designers don’t place things in their level that aren’t intended to be put into a shipping level. This is something we’ve done in past projects, but we’re having trouble figuring out how to do it in UE4. Here are the problems we’re trying to solve in detail:

Level designers need to be able to quickly and intuitively find gameplay entities that are available to them.
There is no way that we’ve discovered to create new Place Mode categories in a Blueprint Class. We’d like to be able to create new categories. For example, I’d like to have a “Weapons” category where all weapons and ammunition pickups show up. Level designers shouldn’t need to sift through the Content Browser to find them - they should be easy to find and in intuitive places. I believe you can do this in C++ classes, but it seems like an oversight if Blueprints can’t also create new categories. Expecting people to comb through the Content Browser is unintuitive, plus it’s not even clear to a designer what Blueprints are even intended to be placed in a level. I thought the “Blueprint Category” property in a Blueprint’s Class Settings would do this, but it doesn’t appear to do anything, and I can’t find any documentation on it.

We want to ensure that Level Designers do not place blueprints that are templates or for testing purposes.
We only want the tuned instances, the Child, Data or “Curated” Blueprints to be placed in the levels. For example, let’s say we have an “Ammo” Class Blueprint that is a template for all types of ammo in the game. Then we create Child Blueprints that are PistolAmmo, RifleAmmo, and RocketAmmo. I only want the child Blueprints to be placed in the level, because I tune them exactly how I want them with proper quantities of ammo, visual effects, etc. I do not want a level designer to place the template in their level and then create a unique instance of an ammo pickup - that will create tuning headaches and bugs down the road.

We also generate a lot of Blueprints for testing and experimentation that we don’t want designers putting into production levels. We would like some way to make it clear that these shouldn’t be placed in shipping levels, and catch them if and when they are.

I suppose I could have a Construction Script try to do something specific when placed, but that seems pretty hacky. I think a better way to handle this would be a “promoted” flag on Blueprints that makes them show up in the Place Mode UI. And, that same flag is what prevents the cooker from throwing warnings when building the game.

Or is there another way that Epic intends people to manage these problems?

I think part of the problems can be solved with Class Viewer, Blueprint are valid classes same as C++ classes and they are viewed together with other classes in Class Viewer in UObject tree, so base classes works like categories, class viewer works the same as content browser, you drag and drop. Other work around would be separating base classes from child classes and use directories as categories, as well as sperateing testing.

As for limited content view, i think cool idea would be for content to have a tags and then limit view to that tag or browse tagged content (something like Apple implemented with files in OS X). As i know other then search functions there no content filtering functions at all, so anything would be cool on that matter

But also you could educate your level designers so you can trust them more ;] there many ways you can improve workflow without need of Epic

Thanks for the feedback. I do trust my level designers (I’m one of them!), but I’ve been doing this too long to think that things won’t go wrong. If we’re building a large world with tens of thousands of things placed into it, things will slip through the cracks. People get tired, they put placeholder object in to test new functionality, we place things temporarily to make demos go more smoothly, etc. That’s okay, it’s just unreasonable to think that everyone will know exactly what has been put in a level that’s being worked on by a dozen people over the course of a year or so. If someone has to leave the team or hand a level off to a new person, good luck having a new person try to sort through every entity in a level! Much like engineers can comment code so that it’s easy to find hacks and things that need to be fixed later, I need the same for our levels.

I subscribe to the Donald Norman philosophy, which I’ll paraphrase as: “There’s no such thing as user error, there’s just failure of designers to make it difficult to make mistakes” :slight_smile:

I’ll check out the Class Viewer as you suggest - I’m still pretty new to the engine, so I’ll post here if I find some good solutions to the problem.

If you ever used UE3 or older, class viewer is same as entity list in there where you placed code pieces to level, now scripts are part of content so content browser gone on spotlight

Also as i said i +1 you ideas about content filtering ;]

Here’s an example custom Blueprint which creates a custom category on palette browser just fine:

UFUNCTION(BlueprintCallable, Category = "My Blueprints|Hello")
static DoSomething();

On Palette it’s found under [My Blueprints > Hello] list.

Than they should not be Blueprints; You should make them as C++ base classes and Blueprints only out of final classes you want to expose to designers.
Or you could do a lazy job of adding a ‘template’ keyword to the blueprints you don’t want designers to use, like:

UFUNCTION(BlueprintCallable, Category = "My Blueprints|Hello", , Keywords = "template do something")
static DoSomething();

Whenever you search (Ctrl+F) any Blueprint graph for the word “template” the search result will list every single node in that blueprint which has the word ‘template’ as a keyword, then you can ask designer to remove them from the graph.

In your code you can check if this is Editor or not (works on packaged in DebugGame only):

UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject);
if(World) {
    if (World->WorldType != EWorldType::Editor) {
       if (GEngine) {GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, "Dear level designer: This Blueprint SHOULD NOT be in shipped game!! Ty."); }