UMG and Inventory slots

Hello!

I have ran into a slight problem with using UMG and C++.

What I want to achieve, is an inventory system with X amount of inventory slots, where I can define X.

At the moment, I imagine the system as:
Inventory (Extended UserWidget)
InventorySlot (Extended UserWidget)

I have already created the design of the two in Blueprint. However, the problem is, that I have not found a way to either add the Inventory to my Viewport, or create X amount of InventorySlots and add them to my Inventory UserWidget.

I have tried this in the Inventory.cpp:


void UInventory::CreateInventory()
{
	UInventory::AddToViewport();
}

CreateInventory() is called by an Input from the Player Pawn (this is a derival of the thirdperson template). By executing CreateInventory(), I get the error “Access reading violation” and UE4.6.1 crashes.

To sum it up: I would like to know how I can display my Inventory widget through C++, as well as add X amount of Inventory Slot widgets.

IIRC in Blueprint you have to first ‘create’ or spawn the widget inside the player HUD, and then call ‘Add To Viewport’ on that created widget, you’ll probably want to find the same functions in code.

Think of ‘Create Widget’ as though it’s spawning something, then you add that spawned ‘thing’ to the viewport. I’m not sure if this HAS to be done inside a sub-class of ‘AHUD’, but it might.

Thank you for the reply. :slight_smile: I will have a look into it.

As an example, is how I instantiate my UMG HUD widget in C++. Once it is created, I just use that instance pointer to add/remove the widget as needed:


HUDWidgetInstance->AddToViewport();

Okay, I have tried to take your example into practice, and with this, I have added a command to my character:


void AMyGameCharacter::OpenInventory()
{
	Inventory->HUDWidgetInstance->AddToViewport();

}

I have confirmed that PostInitializeComponents is loaded by checking it with debug text, however as soon as I execute the above, UE4.6.1 crashes and I get the following error:

Access violation reading location 0x0000000000000430.

is the code for AInventoryHUD:


void AInventoryHUD::PostInitializeComponents()
{
	Super::PostInitializeComponents();
	
	HUDWidgetInstance = CreateWidget<UInventoryWidget>(Cast<APlayerController>(GetOwner()), HUDWidgetClass);
	//check(HUDWidgetInstance != nullptr); //This makes it crash as well.


	if (GEngine)
	{
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, TEXT("TEST"));
	}
}



	HUDWidgetClass = Cast<UClass>(StaticLoadObject(UClass::StaticClass(), NULL, TEXT("WidgetBlueprint'/Game/**BlueprintPath**/**YourBlueprintName.YourBlueprintName**_C'")));
	if (HUDWidgetClass != NULL)
	{
		HUDWidgetInstance = Cast<**YourSubClassOfUUserwidget**>(CreateWidget<UUserWidget>(GetOwningPlayerController(), HUDWidgetClass));

		if(HUDWidgetInstance != NULL)
		{
			HUDWidgetInstance->AddToViewport();
		}
	}


This method should work although I do believe I’ve read somewhere on these forums that Epic dev’s stated that you should not get blueprint references like this as it may change in the future. Don’t expect this method to be future proof but it has been working for my needs for the time being.

Hey it seems you got it working but tought i just drop this anyways.

Heya, sorry for the late answer. Your implementation made it work. :slight_smile:

It seems to be very similar to the other way, but thanks for the showing that thread. ^,^

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:

  1. Create a blueprint for your type (, AInventoryHUD) and use it to assign an asset to your class property.
  2. 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.