Adding UI - Entitlements Essentials - (Unreal Engine module)
What's on the menu
In this section, you'll learn how to prepare the widgets used to display items owned by the player. The related files are available in the Resources section.
Owned count widget
OwnedCountWidgetEntry_Starter: A C++ class used to display item details. You won't need to modify this menu, as it’s provided as a ready-to-use component.- Header file:
Source/AccelByteWars/TutorialModules/Monetization/EntitlementsEssentials/UI/OwnedCountWidgetEntry_Starter.h - CPP file:
Source/AccelByteWars/TutorialModules/Monetization/EntitlementsEssentials/UI/OwnedCountWidgetEntry_Starter.cpp - Blueprint widget:
Content/TutorialModules/Monetization/EntitlementEssentials/UI/W_OwnedIndicator_Starter.uasset
- Header file:
The OwnedCountWidgetEntry_Starter shows how many units of a certain item the player owns. For durable items, it will display owned instead of a count. This widget is attached to the W_StoreItemEntry widget using the Byte Wars modular system. That means W_StoreItemEntry will always include OwnedCountWidgetEntry_Starter when the entitlements module is active.
Here is a preview of the OwnedCountWidgetEntry_Starter Blueprint widget:

The components used in this widget are defined in the OwnedCountWidgetEntry_Starter class header file.
private:
// ...
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UTextBlock* Tb_OwnedCount;
This widget includes pre-configured variables and helper functions tailored for Byte Wars integration.
- Reference to the subsystem that handles the entitlement logic.
private:
UPROPERTY()
UEntitlementsEssentialsSubsystem_Starter* EntitlementsSubsystem;
void UOwnedCountWidgetEntry_Starter::NativeOnActivated()
{
// ...
EntitlementsSubsystem = GetGameInstance()->GetSubsystem<UEntitlementsEssentialsSubsystem_Starter>();
ensure(EntitlementsSubsystem);
// ...
}
- Reference to its parent widget,
W_StoreItemEntry. Since this widget is only used within that context, it safely assumesW_StoreItemEntryas its parent.
private:
UPROPERTY()
UStoreItemListEntry* W_Parent;
- Function to check if an item is equipped and visually highlight it. This is a Byte Wars specific feature, not part of the service.
private:
// ...
UFUNCTION()
void CheckItemEquipped();
Inventory widget
InventoryWidget_Starter: A C++ class used to display item details. You won't need to modify this menu, as it’s provided as a ready-to-use component.- Header file:
Source/AccelByteWars/TutorialModules/Monetization/EntitlementsEssentials/UI/InventoryWidget_Starter.h - CPP file:
Source/AccelByteWars/TutorialModules/Monetization/EntitlementsEssentials/UI/InventoryWidget_Starter.cpp - Blueprint widgets:
Content/TutorialModules/Monetization/EntitlementEssentials/UI/W_Inventory_PowerUps_Starter.uassetContent/TutorialModules/Monetization/EntitlementEssentials/UI/W_Inventory_Cosmetics_Starter.uasset
- Header file:
The InventoryWidget_Starter displays all items the player owns. Durable items are shown in W_Inventory_Cosmetics_Starter, while consumable items are shown in W_Inventory_PowerUps_Starter. These item types behave differently in-game, which is why they are separated.
Here is a preview of the W_Inventory_PowerUps_Starter Blueprint widget:

Here is a preview of the W_Inventory_Cosmetics_Starter Blueprint widget:

The components used in this widget are defined in the OwnedCountWidgetEntry_Starter class header file.
public:
UPROPERTY(EditAnywhere, BlueprintReadOnly)
UMediaPlayer* MediaPlayer;
private:
// ...
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UAccelByteWarsWidgetSwitcher* Ws_Root;
UPROPERTY(EditAnywhere)
FSlateBrush DefaultPreviewImage;
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UImage* W_SelectedItemPreview;
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UTextBlock* Tb_SelectedItemTitle;
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UMultiLineEditableText* Tb_Description;
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UTileView* Tv_Content;
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UCommonButtonBase* Btn_Equip;
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UCommonButtonBase* Btn_Unequip;
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UCommonButtonBase* Btn_Back;
This widget includes pre-configured variables and helper functions tailored for Byte Wars integration.
- Reference to the subsystem that handles the entitlement logic.
private:
UPROPERTY()
UEntitlementsEssentialsSubsystem_Starter* EntitlementsSubsystem;
void UInventoryWidget_Starter::NativeOnActivated()
{
Super::NativeOnActivated();
EntitlementsSubsystem = GetGameInstance()->GetSubsystem<UEntitlementsEssentialsSubsystem_Starter>();
ensure(EntitlementsSubsystem);
// ...
}
- Reference to the selected
UStoreItemDataObjectdata.
private:
UPROPERTY()
UStoreItemDataObject* SelectedItem;
- Variable that indicates which item type (durable or consumable) to display.
private:
// ...
UPROPERTY(EditAnywhere)
bool bIsConsumable = true;
- Functions to equip and unequip an item. These are Byte Wars specific and not part of the service.
private:
void OnClickListItem(UObject* Object);
void OnClickEquip() const;
void OnClickUnEquip() const;
- Delegates to allow other objects to respond when a specific action is performed.
public:
inline static FSimpleMulticastDelegate OnInventoryMenuDeactivated;
FSimpleMulticastDelegate OnEquipped;
FSimpleMulticastDelegate OnUnequipped;
Ready the menu
-
Open the
OwnedCountWidgetEntry_Starterheader file and add the following function declarations.private:
// ...
void RetrieveEntitlementWithForceRequest(const bool bForceRequest);
void ShowOwnedCount(const FOnlineError& Error, const UStoreItemDataObject* Entitlement); -
Open the
OwnedCountWidgetEntry_StarterCPP file and implement theRetrieveEntitlementWithForceRequest()function. For now, this function retrieves only the item represented by the widget. You'll expand this later to include entitlement retrieval.void UOwnedCountWidgetEntry_Starter::RetrieveEntitlementWithForceRequest(const bool bForceRequest)
{
SetVisibility(ESlateVisibility::Collapsed);
W_Parent = GetFirstOccurenceOuter<UStoreItemListEntry>();
if (W_Parent)
{
// Get item.
const UStoreItemDataObject* ItemData = W_Parent->GetItemData();
if (!ItemData)
{
return;
}
// ...
}
} -
Implement the
ShowOwnedCount()function. This displays the number of items owned, or an Owned indicator if the item is durable, based on the backend response.void UOwnedCountWidgetEntry_Starter::ShowOwnedCount(const FOnlineError& Error, const UStoreItemDataObject* Entitlement)
{
if (!Error.bSucceeded || !Entitlement)
{
return;
}
// Set owned count.
FText Text;
if (Entitlement->GetCount() > 0)
{
Text = Entitlement->GetIsConsumable() ?
FText::FromString(FString::Printf(TEXT("%d x"), Entitlement->GetCount())) : TEXT_OWNED;
}
Tb_OwnedCount->SetText(Text);
// Show the owned count if not empty.
SetVisibility(Tb_OwnedCount->GetText().IsEmpty() ? ESlateVisibility::Collapsed : ESlateVisibility::Visible);
// Check if this item is equipped or not.
if (PARENT_WIDGET_CLASS* ParentWidget = GetFirstOccurenceOuter<PARENT_WIDGET_CLASS>())
{
CheckItemEquipped();
ParentWidget->OnEquipped.AddUObject(this, &ThisClass::CheckItemEquipped);
ParentWidget->OnUnequipped.AddUObject(this, &ThisClass::CheckItemEquipped);
}
} -
Find the
NativeOnActivated()function and replace the existing implementation with the code below. This triggersRetrieveEntitlementWithForceRequest()when the widget is activated and binds the function to the item purchase widget delegate, so the item count updates immediately after a successful purchase.void UOwnedCountWidgetEntry_Starter::NativeOnActivated()
{
Super::NativeOnActivated();
EntitlementsSubsystem = GetGameInstance()->GetSubsystem<UEntitlementsEssentialsSubsystem_Starter>();
ensure(EntitlementsSubsystem);
RetrieveEntitlementWithForceRequest(false);
UItemPurchaseWidget::OnPurchaseCompleteMulticastDelegate.AddWeakLambda(this, [this](const APlayerController* PC)
{
RetrieveEntitlementWithForceRequest(true);
});
UItemPurchaseWidget_Starter::OnPurchaseCompleteMulticastDelegate.AddWeakLambda(this, [this](const APlayerController* PC)
{
RetrieveEntitlementWithForceRequest(true);
});
} -
Navigate to the
NativeOnDeactivated()function and replace the existing implementation with the code below. This unbinds all delegates used by the widget to ensure there are no lingering references when the widget is deactivated.void UOwnedCountWidgetEntry_Starter::NativeOnDeactivated()
{
Super::NativeOnDeactivated();
UItemPurchaseWidget::OnPurchaseCompleteMulticastDelegate.RemoveAll(this);
UItemPurchaseWidget_Starter::OnPurchaseCompleteMulticastDelegate.RemoveAll(this);
if (PARENT_WIDGET_CLASS* ParentWidget = GetFirstOccurenceOuter<PARENT_WIDGET_CLASS>())
{
ParentWidget->OnEquipped.RemoveAll(this);
ParentWidget->OnUnequipped.RemoveAll(this);
}
} -
Open the
InventoryWidget_Starterheader file and add the following function declarations.private:
// ...
void ShowEntitlements(const FOnlineError& Error, const TArray<UStoreItemDataObject*> Entitlements) const; -
Open the
InventoryWidget_StarterCPP file and implement theShowEntitlements()function. This function displays all items the player owns, filtered by thebIsConsumableflag.void UInventoryWidget_Starter::ShowEntitlements(const FOnlineError& Error, const TArray<UStoreItemDataObject*> Entitlements) const
{
if (Error.bSucceeded)
{
// filter items
TArray<UStoreItemDataObject*> FilteredEntitlements = Entitlements;
FilteredEntitlements.RemoveAll([this](const UStoreItemDataObject* Item)
{
return bIsConsumable != Item->GetIsConsumable() || (Item->GetIsConsumable() && Item->GetCount() <= 0);
});
Tv_Content->ClearListItems();
Tv_Content->SetListItems(FilteredEntitlements);
Ws_Root->SetWidgetState(Tv_Content->GetListItems().IsEmpty()
? EAccelByteWarsWidgetSwitcherState::Empty
: EAccelByteWarsWidgetSwitcherState::Not_Empty);
Tv_Content->SetUserFocus(GetOwningPlayer());
}
else
{
Ws_Root->ErrorMessage = Error.ErrorMessage;
Ws_Root->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Error);
}
} -
Build the project and open it with the Unreal Editor once it's done.
-
Open
Content/TutorialModules/Monetization/EntitlementEssentials/DA_EntitlementsEssentials.uassetand enable theIs Starter Mode Active. Save the Data Asset.
Resources
- The files used in this tutorial section are available in the Byte Wars GitHub repository.
- AccelByteWars/Source/AccelByteWars/TutorialModules/Monetization/EntitlementsEssentials/UI/OwnedCountWidgetEntry_Starter.h
- AccelByteWars/Source/AccelByteWars/TutorialModules/Monetization/EntitlementsEssentials/UI/OwnedCountWidgetEntry_Starter.cpp
- AccelByteWars/Content/TutorialModules/Monetization/EntitlementEssentials/UI/W_OwnedIndicator_Starter.uasset
- AccelByteWars/Source/AccelByteWars/TutorialModules/Monetization/EntitlementsEssentials/UI/InventoryWidget_Starter.h
- AccelByteWars/Source/AccelByteWars/TutorialModules/Monetization/EntitlementsEssentials/UI/InventoryWidget_Starter.cpp
- AccelByteWars/Content/TutorialModules/Monetization/EntitlementEssentials/UI/W_Inventory_PowerUps_Starter.uasset
- AccelByteWars/Content/TutorialModules/Monetization/EntitlementEssentials/UI/W_Inventory_Cosmetics_Starter.uasset
- AccelByteWars/Content/TutorialModules/Monetization/EntitlementEssentials/DA_EntitlementsEssentials.uasset