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

Implement Subsystem - Wallet Essentials - (Unreal Engine module)

Last updated on July 28, 2025

Unwrap the subsystem

Byte Wars uses a Game Instance Subsystem called WalletEssentialsSubsystem to wrap the AccelByte Gaming Services (AGS) Online Subsystem (OSS). This subsystem utilizes the FOnlineWalletAccelByte provided by the AGS OSS. In this tutorial, you'll work with a starter version of the subsystem, allowing you to implement the required functions from scratch.

What's in the Starter Pack

To follow along with this tutorial, a starter subsystem class named WalletEssentialsSubsystem_Starter has been prepared. You can find it in the Resources section. It includes the following files:

  • Header file: Source/AccelByteWars/TutorialModules/Monetization/WalletEssentials/WalletEssentialsSubsystem_Starter.h
  • CPP file: Source/AccelByteWars/TutorialModules/Monetization/WalletEssentials/WalletEssentialsSubsystem_Starter.cpp

The WalletEssentialsSubsystem_Starter class includes several helpful components:

  • Declaration and initialization of the AGS OSS FOnlineWalletAccelByte interface, which provides access to AGS Software Development Kit (SDK) features.
private:
FOnlineWalletAccelBytePtr WalletInterface;
void UWalletEssentialsSubsystem_Starter::Initialize(FSubsystemCollectionBase& Collection)
{
// ...
const FOnlineSubsystemAccelByte* Subsystem = static_cast<FOnlineSubsystemAccelByte*>(Online::GetSubsystem(GetWorld()));
ensure(Subsystem);

WalletInterface = Subsystem->GetWalletInterface();
ensure(WalletInterface);
// ...
}
  • A helper function for retrieving the local user number from a Player Controller. This is necessary because widgets, the primary users of this subsystem, use Player Controllers to reference players, while the OSS interface requires a local user number to identify the requesting user.
private:
// ...
static int32 GetLocalUserNumFromPlayerController(const APlayerController* PlayerController);

Additionally, there is a model file Source/AccelByteWars/TutorialModules/Monetization/WalletEssentials/WalletEssentialsModel.h that defines the delegates used to handle backend responses, along with a predefined localized text that displays when the subsystem fails to retrieve the data.

#define TEXT_BALANCE_ERROR NSLOCTEXT("AccelByteWars", "balance_error", "NaN")

DECLARE_MULTICAST_DELEGATE_TwoParams(FOnGetWalletInfoComplete, bool /*bWasSuccessful*/, const FAccelByteModelsWalletInfo& /*Response*/);

Implement query wallet info

  1. Open the WalletEssentialsSubsystem_Starter header file and declare the following function to request the wallet information from the backend.

    public:
    void QueryOrGetWalletInfoByCurrencyCode(
    const APlayerController* OwningPlayer,
    const FString& CurrencyCode,
    const bool bAlwaysRequestToService = true) const;
  2. Declare the following delegate and handler function to process the backend response.

    public:
    // ...
    FOnGetWalletInfoComplete OnQueryOrGetWalletInfoCompleteDelegates;
    private:
    // ...
    void OnQueryOrGetWalletInfoByCurrencyCodeComplete(
    int32 LocalUserNum,
    bool bWasSuccessful,
    const FAccelByteModelsWalletInfo& Response,
    const FString& Error) const;
  3. Go to the WalletEssentialsSubsystem_Starter CPP file and implement the QueryOrGetWalletInfoByCurrencyCode() function. This function sends a request to retrieve the player's wallet information.

    void UWalletEssentialsSubsystem_Starter::QueryOrGetWalletInfoByCurrencyCode(
    const APlayerController* OwningPlayer,
    const FString& CurrencyCode,
    const bool bAlwaysRequestToService) const
    {
    const int32 LocalUserNum = GetLocalUserNumFromPlayerController(OwningPlayer);
    WalletInterface->GetWalletInfoByCurrencyCode(LocalUserNum, CurrencyCode, bAlwaysRequestToService);
    }
  4. Implement the OnQueryOrGetWalletInfoByCurrencyCodeComplete() function, which triggers the OnQueryOrGetWalletInfoCompleteDelegates delegate using the data from the backend response.

    void UWalletEssentialsSubsystem_Starter::OnQueryOrGetWalletInfoByCurrencyCodeComplete(
    int32 LocalUserNum,
    bool bWasSuccessful,
    const FAccelByteModelsWalletInfo& Response,
    const FString& Error) const
    {
    OnQueryOrGetWalletInfoCompleteDelegates.Broadcast(bWasSuccessful, Response);
    }
  5. Still in the CPP file, navigate to the Initialize() function and replace its contents with the following code. This binds the OnQueryOrGetWalletInfoByCurrencyCodeComplete() function to the actual response delegate in the FOnlineWalletAccelByte interface.

    void UWalletEssentialsSubsystem_Starter::Initialize(FSubsystemCollectionBase& Collection)
    {
    Super::Initialize(Collection);

    const FOnlineSubsystemAccelByte* Subsystem = static_cast<FOnlineSubsystemAccelByte*>(Online::GetSubsystem(GetWorld()));
    ensure(Subsystem);

    WalletInterface = Subsystem->GetWalletInterface();
    ensure(WalletInterface);

    WalletInterface->OnGetWalletInfoCompletedDelegates->AddUObject(this, &ThisClass::OnQueryOrGetWalletInfoByCurrencyCodeComplete);
    }
  6. Navigate to the Deinitialize() function and replace its contents with the following code. This unbinds the OnQueryOrGetWalletInfoByCurrencyCodeComplete() function.

    void UWalletEssentialsSubsystem_Starter::Deinitialize()
    {
    Super::Deinitialize();

    WalletInterface->OnGetWalletInfoCompletedDelegates->RemoveAll(this);
    }

Resources