This is… sort of okay.
What said not to do is getting actual blueprint objects. Despite the “WidgetBlueprint” prefix there, you’re not actually getting a blueprint there, you’re really getting the blueprint class. (Note the _C suffix standard to blueprint classes.) The prefix in string asset references is mostly cosmetic, so even if you say “WidgetBlueprint”, it’s actually finding a “WidgetBlueprintGeneratedClass”, which happens to be what you want. 's how I get my widget class for the previous example:
AMyHUD::AMyHUD( const class FPostConstructInitializeProperties& PCIP )
static ConstructorHelpers::FClassFinder<UUserWidget> HudWidgetClassFinder( TEXT("WidgetBlueprintGeneratedClass'/Game/UI/HUD/HUDWidget.HUDWidget_C'") );
HUDWidgetClass = HudWidgetClassFinder.Class;
Which brings me to the actual reason why this approach is Bad Practice: Do not use hardcoded asset references outside of object/class finders. I see people doing it all the time and I wish I could magically impose this knowledge on everyone, but it’s a bad thing to do.
The reason is that once you start cooking your game, asset references defined in this way are completely invisible to the cooker. Cooking only cares about assets you’re actually using, otherwise you’d end up shipping cooked games with piles of data that isn’t actually used anywhere. The cooker determines what assets are being used by loading the maps you’re cooking as well as the native classes you’re using and looking for any asset properties in the loaded results.
What’s going to happen is the cooker will load your HUD class, get its default object, look at the HUDWidgetClass property and find that it is empty. This is because the path to your widget blueprint class only exists in PostInitializeComponents. So unless the class is somehow referred to elsewhere, the cooker will determine this widget blueprint is unused and omit it from your cooked game, obviously leading to HUD construction issues.
There are two ways to ensure a reference exists to be gathered for the cooker:
- Create a blueprint for your type (, AInventoryHUD) and use it to assign an asset to your class property.
- If you don’t need a blueprint and would just rather specify the asset path in native code, use FObjectFinder/FClassFinder to assign the results to your class property.
In both cases, this will result in your class default object for AInventoryHUD (or AInventoryHUDBlueprint, in the blueprint case) containing a reference to your widget blueprint, thus allowing it to be proprely cooked.
FObjectFinder/FClassFinder is just a wrapper around StaticLoadObject that does a few sanity checks like making sure it is being used from the constructor. Because if not used from the constructor, you end up with asset referencing issues. As a rule of thumb, you should avoid calling StaticLoadObject directly unless you’re certain of what you’re doing.