Loading Blueprint from C++, path issues

Hi,

trying to load the data for MyActor2 with this code,
as you can see there are 2 lines with BlueprintActor, ive tried both, no luck.

BP not found is shown when the game starts, see last screenshot, this means that BlueprintActor.Succeeded() did not return true.

 FString PrDir = FPaths::ProjectContentDir()+"/MyActor2_BP";
    GEngine->AddOnScreenDebugMessage(-1,50.0f,FColor::Red, *PrDir);
    //static ConstructorHelpers::FClassFinder<AActor> BlueprintActor(TEXT("/Game/MyActor2_BP"));
    static ConstructorHelpers::FClassFinder<AActor> BlueprintActor(*PrDir);

  

    if (BlueprintActor.Succeeded())
    {
        BlueprintActorClass = BlueprintActor.Class;
        
        if (GEngine )
        {
            GEngine->AddOnScreenDebugMessage(-1,5.0f,FColor::Red, TEXT("BP loaded"));
        }
    }
      else
    {
        GEngine->AddOnScreenDebugMessage(-1,5.0f,FColor::Red, TEXT("BP not found"));
    }

this is the BP i would like to load:
grafik

This is shown when the level is loaded:

so the path to the asset is probably right in *PrDir. But why is it not loading?

Pass in the relative path to the asset

  static ConstructorHelpers::FClassFinder<AActor> BlueprintActor(TEXT("/Game/MyActor2_BP"));
            
  if (BlueprintActor.Succeeded())
  {   
      if (GEngine)
      {
          GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("BP loaded"));
      }
  }
  else
  {
      if (GEngine)
      {
          GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("BP not found"));
      }
  }     

No luck, my code is currently in AMyGameModeBase::BeginPlay which is my custom gamemode, i can see the “BP NOT found” message, so it is set in the world settings to use this gamemode class.

Is this maybe to early or to late to load actors?

Also the actors path is shown in this popup, just recently saw the /Game in there.
grafik

void AMyGameModeBase::BeginPlay() {
    Super::BeginPlay();
    static ConstructorHelpers::FClassFinder<AActor> BlueprintActor(TEXT("/Game/MyActor2_BP"));
            
  if (BlueprintActor.Succeeded())
  {   
      if (GEngine)
      {
          GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("BP loaded"));
      }
  }
  else
  {
      if (GEngine)
      {
          GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("BP NOT found"));
      }
  } 
}

As the name implies ConstructorHelpers need to be in the constructor. You are invoking the command in the wrong place of your code, that is why it fails.

GameMode also doesn’t have a normal begin play anyway.

You need to call it from an actor’s CDO

If you have the class AMyActor then you need to call it in the cpp in

 AMyActor::AMyActor(){
    // -> call your function here.
    static ConstructorHelpers::FClassFinder<AActor> BlueprintActor(TEXT("/Game/MyActor2_BP"));
    if (BlueprintActor.Succeeded())
    { 
         // rest of code
    }
}

Try using FSoftClassPath::TryLoadClass() instead of FClassFinder.

Oh, and if I’m not mistaken, the class path should look like this: /Game/Folder/AssetName.AssetName_C

Yeah _C suffix is for blueprint based assets

Here’s a templated version of loading a blueprint from C++. Used only for loading HUD blueprints, so in this case it is in our AHUD class .h file.

Example of use:

_toolbarHudWidget = LoadHUDWidget<UPrimaryToolbarHUDWidget>(GetWorld(), "/Game/Blueprints/HUD/PrimaryToolbar.PrimaryToolbar_C"); // append _C

Code must be in .h file since it is a template function.

template<typename T = UUserWidget, typename Owner = UObject>
static T* LoadHUDWidget(Owner owningObject, FString widgetName)
{
	// load the HUD bluprint and add to viewport
	FSoftClassPath HUDClassReference(widgetName); // must append "_C"!!!
	UClass* HUDClass = HUDClassReference.TryLoadClass<UUserWidget>();
	if (HUDClass != nullptr)
	{
		// load the blueprint and add it to the viewport
		UUserWidget* tempWidget = CreateWidget<UUserWidget>(owningObject, HUDClass);
		T* UserWidgetClass = Cast<T>(tempWidget);
		if (UserWidgetClass != nullptr)
		{
			UserWidgetClass->AddToViewport();
			return UserWidgetClass;
		}
		else
		{
			LOG("BaseHUD::LoadHUDWidget() - failed for '%s'!", *widgetName);
			return nullptr;
		}
	}
	else 
	{
		LOG("BaseHUD::LoadHUDWidget() - failed for '%s'!", *widgetName);
		return nullptr;
	}
}

Thanks for the reply, had to look up FSoftClassPath

const FSoftClassPath BlockPath(TEXT("/Game/Cas/BuildingBlock.BuildingBlock_C"));
const UClass* BlockClass = BlockPath.TryLoadClass();
checkf(BlockClass != nullptr, TEXT("expected non-null class"));
GetWorld()->SpawnActor(BlockClass, &SpawnPos);

this example can be found in the forums:

but as the next poster in that thread pointed out TryLoadClass() needs some parameter.
Sadly my Visual Studio Code does not display proper context help, have to download the UE sourcecode to figure this out.

started a new fresh project, just in case. firstActor should spawn secondActor, both are C++ classes as shown in the screenshot and they should exist in /Script

grafik

Why does this code not load it?

#include "secondActor.h"
#include "Engine/Engine.h"
#include "Components/BoxComponent.h"
#include "firstActor.h"
#include "Engine/World.h"


AfirstActor::AfirstActor()

{
     static ConstructorHelpers::FClassFinder<AActor> BlueprintActor(TEXT("/Script/secondActor"));
   
    
    if (BlueprintActor.Succeeded())
    { 
        GEngine->AddOnScreenDebugMessage(-1,5.0f,FColor::Red, TEXT("Class FOUND"));
    }
    else {
        GEngine->AddOnScreenDebugMessage(-1,5.0f,FColor::Red, TEXT("Class not FOUND"));
    }
}

I don’t thing you can access an instance of a pure c++ class though the class finder.

SecondActor.h (577 Bytes)
FirstActor.cpp (542 Bytes)
FirstActor.h (573 Bytes)
SecondActor.cpp (902 Bytes)

ASecondActor::ASecondActor()
{	
	PrimaryActorTick.bCanEverTick = false;
	static ConstructorHelpers::FClassFinder<AFirstActor> BlueprintActor(TEXT("/Game/BP_FirstActor"));

	if (GEngine) {
		if (BlueprintActor.Succeeded())
		{
			UClass* BPclass = BlueprintActor.Class;
			GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Green, TEXT("Class Found " + BPclass->GetFullName()));
		}
		else {
			GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("Class not FOUND"));
		}
	}
}

Class found

Full project source:
loading.zip (32.2 KB)

Thank you very much 3dRaven for that complete example, added some more lines of code and now finally a blueprint actor is spawning from c++ code. And thanks to the other contributors as well.

After the next question, which will come, let me buy you a paypal coffee.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.