メインコンテンツまでスキップ

Adding UI - Entitlements Essentials - (Unreal Engine module)

Last updated on July 28, 2025

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

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:

OwnedCountWidgetEntry_Starter preview

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 assumes W_StoreItemEntry as 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.uasset
      • Content/TutorialModules/Monetization/EntitlementEssentials/UI/W_Inventory_Cosmetics_Starter.uasset

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:

W_Inventory_PowerUps_Starter preview

Here is a preview of the W_Inventory_Cosmetics_Starter Blueprint widget:

W_Inventory_Cosmetics_Starter preview

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 UStoreItemDataObject data.
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

  1. Open the OwnedCountWidgetEntry_Starter header file and add the following function declarations.

    private:
    // ...
    void RetrieveEntitlementWithForceRequest(const bool bForceRequest);
    void ShowOwnedCount(const FOnlineError& Error, const UStoreItemDataObject* Entitlement);
  2. Open the OwnedCountWidgetEntry_Starter CPP file and implement the RetrieveEntitlementWithForceRequest() 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;
    }
    // ...
    }
    }
  3. 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);
    }
    }
  4. Find the NativeOnActivated() function and replace the existing implementation with the code below. This triggers RetrieveEntitlementWithForceRequest() 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);
    });
    }
  5. 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);
    }
    }
  6. Open the InventoryWidget_Starter header file and add the following function declarations.

    private:
    // ...
    void ShowEntitlements(const FOnlineError& Error, const TArray<UStoreItemDataObject*> Entitlements) const;
  7. Open the InventoryWidget_Starter CPP file and implement the ShowEntitlements() function. This function displays all items the player owns, filtered by the bIsConsumable flag.

    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);
    }
    }
  8. Build the project and open it with the Unreal Editor once it's done.

  9. Open Content/TutorialModules/Monetization/EntitlementEssentials/DA_EntitlementsEssentials.uasset and enable the Is Starter Mode Active. Save the Data Asset.

    Data Asset changes preview Unreal Byte Wars Entitlement Essentials

Resources