Spawn blueprint actor from c++ in packaged game

I know this question have been adressed decent amount of times, and I’ve read alot of solutions, but still struggle to understand what am I doing wrong, so please advice!

I have a c++ class “ADialogueCharacter : public ACharacter”, from this class I’ve created blueprint “NPC_generic” and every NPC derives from this blueprint, for example Hitch and Bill.

Now, on game start I’m loading NPC’s in MyGameMode.

ATheBarGameMode.cpp

ATheBarGameMode::ATheBarGameMode()
{
	............................
	NPC_forDay.Empty();
	NPC_forDay.Add(UDayFlow::LoadNPCBlueprint(TEXT("Blueprint'/Game/NPC/Hitch.Hitch_C'"), 13));
	NPC_forDay.Add(UDayFlow::LoadNPCBlueprint(TEXT("Blueprint'/Game/NPC/NPC_generic.NPC_generic_C'"), 0));
	NPC_forDay.Add(UDayFlow::LoadNPCBlueprint(TEXT("Blueprint'/Game/NPC/Bill.Bill_C'"), 11));

	.............................
}

The function I use to load them is a static library function, which takes NPC asset location and unique NPC ID

FNPC_BP UDayFlow::LoadNPCBlueprint(FString refPath, int char_ID)
    {
    	ConstructorHelpers::FObjectFinder<UClass> NPC_BP(*refPath);
    	if (NPC_BP.Object)
    	{
    		FNPC_BP singleNPC;
    		singleNPC.BP_Ref = NPC_BP.Object;
    		singleNPC.NPC_ID = char_ID;
    		return singleNPC;
    	}
    	return FNPC_BP();
    }

All the code above is sligtly modified, because before I used FObjectFinder and loaded blueprits, which worked in editor, but gave me errors with missing assets when i packaged a game. I found out, that I could not load BP’s outside editor, and it’s kind of a right thing, so after some ressearch switched to UClass.

This time packaged game started good, and there were no errors, but It turned out, that no NPC was spawning, despite the fact that all spawning code below seems to be working.

The spawning function itself I borrowd from Rama, here it is:

template <typename VictoryObjType>
static FORCEINLINE VictoryObjType* SpawnBP(
	UWorld*         TheWorld, 
	UClass*         TheBP,
	const FVector&  Loc,
	const FRotator& Rot,
	const bool      bNoCollisionFail = true,
	AActor*         Owner            = NULL,
	APawn*          Instigator       = NULL
) {
	if(!TheWorld) return NULL;
	if(!TheBP) return NULL;
 
	FActorSpawnParameters SpawnInfo;
	SpawnInfo.bNoCollisionFail   = bNoCollisionFail;
	SpawnInfo.Owner              = Owner;
	SpawnInfo.Instigator         = Instigator;
	SpawnInfo.bDeferConstruction = false;
 
	return TheWorld->SpawnActor<VictoryObjType>(TheBP, Loc, Rot, SpawnInfo);
}

and I use it like that:

ACharacter* UDayFlow::executeEventSpawnNPC(
	FEventCharComes charComesEvent, 
	TArray <FNPC_BP> NPC_BP_Ref,
	UWorld*         TheWorld,
	const FVector&  Loc,
	const FRotator& Rot
) {		
	int char_ID = charComesEvent.char_ID;

	FNPC_BP *NPC_BP = NPC_BP_Ref.FindByPredicate([char_ID](const FNPC_BP& item) {return item.NPC_ID == char_ID; });

	if (NPC_BP != nullptr)
	{
		ACharacter* spawnedNPC = SpawnBP<ACharacter>(TheWorld, NPC_BP->BP_Ref, Loc, Rot);
		return spawnedNPC;
	};
	return nullptr;
}

Here I find NPC reference, which I got from ObjectFinder in the first code fragment and try to spawn it as ACharacter type. I made absolutely no changes to this part of code, comparing to when I was loading BP’s directly and I don’t understand what could I change here.

Will appreciate any help.

I’ve just switched to FClassFinder, I’ve tried it before, but with type. Unfortunately it did not help even with ADialogueCharacter.
It loads game with no errors, It works in editor (either under VS debugger, or self loaded), but when I package, or Launch nothing spawns (no errors though).
I believe It has to do something with the fact that I have to somehow myabe cast to BP class that I want to spawn (TSublcassOf?)

The other thing, that bothered me, that in the ADialogueCharacter class I do not actually have any meshes, that I can see in game (I add meshes later in derived blueprints), so It just has a capsule component and a direction arrow, both hidden in game. So I’ve made capsule visible, in constructor of ADialogueCharacter. Unfortunately it did nothing.

So next thing I’ll see how I can use UE_LOG to check what could be wrong, cos VS debugger doesn’t help (game just works as intended, when I start it in PIE mode). Myabe add onscreen message - print asset name right before spawning it.

Usually you would reference blueprints
that you are using through maps
somehow, but if you are only
referencing these through C++

I’m mostly sure it’s not cooking problem, I know what you are talking about and I’ve added all necessary assets to package list.

I’ve added few debug lines before and after calling spawn function :

if (NPC_BP != nullptr)
	{
		GEngine->AddOnScreenDebugMessage(-1, 50.0f, FColor::Green, FString::Printf(L"before spawning BP:    %s", *NPC_BP->BP_Ref->GetName())); // TODO: remove debug message
		ADialogueCharacter* spawnedNPC = SpawnBP<ADialogueCharacter>(TheWorld, NPC_BP->BP_Ref, Loc, Rot);
		GEngine->AddOnScreenDebugMessage(-1, 50.0f, FColor::Green, FString::Printf(L"after spawning BP:    %s", *spawnedNPC->GetName())); // TODO: remove debug message
		return spawnedNPC;
	};

It outputs asset name on screen right before I send it to spawning function and secont time a name of class returned from function. They differ a bit (before spawn: Hitch_C, after spawn: Hitch_C_0), and I’m not sure if it means something. (keeping in mind it acts the same in editor builds and it works just fine there)

Thanks for sticking with me on that one, kamrann.

I’ve packaged with “use pack file” turned off, all of the meshes and materials are in place. I also made default character capsule visible, so even if there’s something wrong with meshes I should see it atleast, but still nothing.
The thing is rigth after spawn, my character runs to a door and triggerbox-opens it. I log all those actions up to a point when NPC stops, successfully compleeting AImovement request. In package game I see that after spawn character recieves request to move but instantly ends movement without succession.

When you say the “above code is slightly modified”, do you mean your current code is different to the snippets you posted? Or you mean what you posted is your updated code?

The code posted is wrong, you’re still trying to load blueprints. If you know that, then post whatever code you’re using now. You also need to use the debugger to let us know what the values are of your variables, specifically BP_Ref.

Thank you for reply!
The above code is as it’s posted in question, what I meant is that before I used FObjecFinder<UObject> instead of <UClass> and packaged game crashed with CDO error even though editor builds ran smoothly.
With code above packaged game starts and it looks like it loads something, but spawns nothing.

Okay, I think you’ll find that your code is not actually succeeding in loading the class.

You should switch to using ConstructorHelpers::FClassFinder as follows:

static ConstructorHelpers::FClassFinder< ADialogueCharacter > NPC_BP(*refPath);
...
singleNPC.BP_Ref = NPC_BP.Class;

Then, you should drop the word ‘Blueprint’ from your path, and also drop the surrounding single quotes. That was an old format and you now need just the raw path name. Also with FClassFinder, you can drop the end part of the path, so you just use "/Game/NPC/Hitch", though "/Game/NPC/Hitch.Hitch_C" will probably work too.

In future, I recommend you use the Visual Studio debugger and/or log variable values with UE_LOG. You will solve many problems yourself that way, and if you’re still stuck, it will be a lot easier for people to help with that information.

Yes you can log a message to record whether the class you loaded is null or not. Given this works in the editor, I’m fairly sure that will be the reason nothing is spawned.

It could be a cooking problem. Usually you would reference blueprints that you are using through maps somehow, but if you are only referencing these through C++, they won’t be detected during cooking so the blueprints will not actually get cooked into the packaged game. To get around this you can open project settings, go to packaging/cooking settings (I don’t remember exactly), and try adding the path containing your blueprints to the ‘Additional asset directories to cook’ property.

Okay, so at least we know the blueprint class is working fine. Those outputs are correct - the first is the name of the class, the second is the name of the object, which defaults to class name plus number suffix if not specified.

So your actor is actually being spawned fine, it’s just not visible. Most likely explanation - maybe it’s your mesh that isn’t getting cooked? Have you added that to the extra paths too, or referenced it elsewhere? By the way, if you disable pak file use in packaging settings, then you can examine the content folder of the packaged output and see for yourself which assets made it in.

I’d recommend against manually referencing things in general, it’s just too brittle. Best is to use TSubclassOf properties on your classes, which you set from within the editor to the desired blueprint, rather than specifying the blueprint from its path in C++. That way the blueprint is referenced and the cooker can automatically include anything that it references. Another approach is to use object libraries (right click in content browser, Miscellaneous), and then you only need to add the path to the object library asset(s) to “Additional assets to cook”.

I’m running out of ideas then. I’d suggest you scour the output logs, both from the packaging process, and then from running the packaged game. If there are any warnings at all, they might explain the cause of the problem.

Another thing you could try is adding an extra component of some kind, maybe static mesh, to the ADialogueCharacter in C++, just to see if that shows up.

Ok, I finally got what was wrong. It was an FVector, which I passed to spawning function. I generate it from XML file (this is where I keep all game events) and somehow in packaged version it became nullified and thus my character was spawning somewhere out of my view and away form navmesh. This is yet a thing for me to figure, but I managed to spawn character before my eyes, so I will accept this answer and dig further.
Thank you, kamrann, very much for you advises and help, I learned few valuable things from you!