View as Markdown

Economy

Read more about the Economy system in Hiro here .

Store type configuration #

When making hard currency purchases, set the correct EHiroEconomyStoreType based on the player’s platform. The store type determines which platform’s receipt validation endpoint the server uses.

ValueDescription
ECONOMY_STORE_TYPE_APPLE_APPSTOREApple App Store
ECONOMY_STORE_TYPE_GOOGLE_PLAYGoogle Play Store
ECONOMY_STORE_TYPE_FBINSTANTFacebook Instant Games
ECONOMY_STORE_TYPE_UNSPECIFIEDDefaults to Apple App Store

For more details on store types and purchase validation, see Virtual Store .

Initializing the economy system #

The economy system requires a logger, the Nakama system, and the store type for receipt validation.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
EEconomyStoreType StoreType;

#if PLATFORM_ANDROID
    StoreType = EEconomyStoreType::GooglePlay;
#elif PLATFORM_IOS
    StoreType = EEconomyStoreType::AppleAppstore;
#else
    StoreType = EEconomyStoreType::Unspecified;
#endif

auto EconomySystem = MakeShared<FHiroEconomySystem>(Logger, NakamaSystem, StoreType);
Systems.Add(EconomySystem);

Donation claim #

Claim one or more rewards which are partially or full donated by other players.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
FHiroEconomyDonationClaimRequest Request;
Request.Items = {TEXT("donation_1"), TEXT("donation_2")};

FHiroOnEconomyDonationClaim OnEconomyDonationClaim;
OnEconomyDonationClaim.AddDynamic(this, &AMyActor::OnEconomyDonationClaim);
FOnError OnError;

HiroClient->EconomyDonationCLaim(Session, Request, OnEconomyDonationClaim, OnError);

void AMyActor::OnEconomyDonationClaim(const FHiroEconomyDonationClaimRewards& EconomyDonationClaimRewards)
{
    UE_LOG(LogTemp, Log, TEXT("%s"), *EconomyDonationClaimRewards.ToJson());
}

Donate some resource (currencies, items, etc.) to a user by donation ID.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
FHiroEconomyDonationGiveRequest Request;
Request.UserId = TEXT("user_1");
Request.DonationId = TEXT("donation_1");

FHiroOnEconomyDonationGive OnEconomyDonationGive;
OnEconomyDonationGive.AddDynamic(this, &AMyActor::OnEconomyDonationGive);
FOnError OnError;

HiroClient->EconomyDonationGive(Session, Request, OnEconomyDonationGive, OnError);

void AMyActor::OnEconomyDonationGive(const FHiroEconomyUpdateAck& EconomyUpdateAck)
{
    UE_LOG(LogTemp, Log, TEXT("%s"), *EconomyUpdateAck.ToJson());
}

Get donation progress #

Get progress on one or more donations for a set of players by their IDs.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
FHiroEconomyDonationGetRequest Request;
Request.Ids = {TEXT("donation_1"), TEXT("donation_2")};

FHiroOnEconomyDonationGet OnEconomyDonationGet;
OnEconomyDonationGet.AddDynamic(this, &AMyActor::OnEconomyDonationGet);
FOnError OnError;

HiroClient->EconomyDonationGet(Session, Request, OnEconomyDonationGet, OnError);

void AMyActor::OnEconomyDonationGet(const FHiroEconomyDonationsByUserList& EconomyDonationsByUserList)
{
    UE_LOG(LogTemp, Log, TEXT("%s"), *EconomyDonationsByUserList.ToJson());
}

Request a donation #

Request a donation which other players can contribute into.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
FHiroEconomyDonationRequest Request;
Request.DonationId = TEXT("donation_1");

FHiroOnEconomyDonationRequest OnEconomyDonationRequest;
OnEconomyDonationRequest.AddDynamic(this, &AMyActor::OnEconomyDonationRequest);
FOnError OnError;

HiroClient->EconomyDonationRequest(Session, Request, OnEconomyDonationRequest, OnError);

void AMyActor::OnEconomyDonationRequest(const FHiroEconomyDonationAck& EconomyDonationAck)
{
    UE_LOG(LogTemp, Log, TEXT("%s"), *EconomyDonationAck.ToJson());
}

Get store items #

Get all store items defined in the Virtual Store.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
FHiroEconomyListRequest Request;
Request.StoreType = EHiroEconomyStoreType::ECONOMY_STORE_TYPE_APPLE_APPSTORE;

FHiroOnEconomyStoreGet OnEconomyStoreGet;
OnEconomyStoreGet.AddDynamic(this, &AMyActor::OnEconomyStoreGet);
FOnError OnError;

HiroClient->EconomyStoreGet(Session, Request, OnEconomyStoreGet, OnError);

void AMyActor::OnEconomyStoreGet(const FHiroEconomyList& EconomyList)
{
    UE_LOG(LogTemp, Log, TEXT("%s"), *EconomyList.ToJson());
}

Get store items by category #

Get store items from the Virtual Store filtered to a specific category.

1
2
3
4
5
6
7
HiroClientExtension->EconomyStoreGetByCategory(HiroClient, Session, Request, TEXT("coin_packs"),
OnEconomyStoreGet, OnError);

void AMyActor::OnEconomyStoreGet(const FHiroEconomyList& EconomyList)
{
    UE_LOG(LogTemp, Log, TEXT("%s"), *EconomyList.ToJson());
}

Passing an empty category returns all store items.

Grant currencies or reward modifiers #

Grant one or more currencies or reward modifiers to the player.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
FHiroEconomyGrantRequest Request;
Request.Currencies.Add(TEXT("coins"), 100);

FHiroOnEconomyGrant OnEconomyGrant;
OnEconomyGrant.AddDynamic(this, &AMyActor::OnEconomyGrant);
FOnError OnError;

HiroClient->EconomyGrant(Session, Request, OnEconomyGrant, OnError);

void AMyActor::OnEconomyGrant(const FHiroEconomyUpdateAck& EconomyUpdateAck)
{
    UE_LOG(LogTemp, Log, TEXT("%s"), *EconomyUpdateAck.ToJson());
}

Send a purchase intent #

Send a marker of intent to purchase by the player.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
FHiroEconomyPurchaseIntentRequest Request;
Request.ItemId = TEXT("item_1");
Request.StoreType = EHiroEconomyStoreType::ECONOMY_STORE_TYPE_APPLE_APPSTORE;
Request.Sku = TEXT("sku_1");

FHiroOnEconomyPurchaseIntent OnEconomyPurchaseIntent;
OnEconomyPurchaseIntent.AddDynamic(this, &AMyActor::OnEconomyPurchaseIntent);
FOnError OnError;

HiroClient->EconomyPurchaseIntent(Session, Request, OnEconomyPurchaseIntent, OnError);

Purchase a store item #

Purchase a store item by the player.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
FHiroEconomyPurchaseRequest Request;
Request.ItemId = TEXT("item_1");
Request.StoreType = EHiroEconomyStoreType::ECONOMY_STORE_TYPE_APPLE_APPSTORE;
Request.Receipt = TEXT("<receipt>");

FHiroOnEconomyPurchaseItem OnEconomyPurchaseItem;
OnEconomyPurchaseItem.AddDynamic(this, &AMyActor::OnEconomyPurchaseItem);
FOnError OnError;

HiroClient->EconomyPurchaseItem(Session, Request, OnEconomyPurchaseItem, OnError);

void AMyActor::OnEconomyPurchaseItem(const FHiroEconomyPurchaseAck& EconomyPurchaseAck)
{
    UE_LOG(LogTemp, Log, TEXT("%s"), *EconomyPurchaseAck.ToJson());
}

The server populates Inventory only when the purchase changes the player’s inventory. Purchases that grant currency alone leave it unpopulated.

When populated, Inventory holds the player’s complete inventory, not only the items the purchase added. Replace your local copy instead of merging into it.

An unpopulated Inventory means the purchase left it unchanged. It doesn’t mean the player owns nothing, so don’t clear cached inventory state when this field is empty.

Get ad placement status #

Get the current status on an Ad placement which may have been rewarded.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
FHiroEconomyPlacementStatusRequest Request;
Request.RewardId = TEXT("reward_1");
Request.PlacementId = TEXT("placement_1");
Request.Count = 0;

FHiroOnEconomyPlacementStatus OnEconomyPlacementStatus;
OnEconomyPlacementStatus.AddDynamic(this, &AMyActor::OnEconomyPlacementStatus);
FOnError OnError;

HiroClient->EconomyPlacementStatus(Session, Request, OnEconomyPlacementStatus, OnError);

void AMyActor::OnEconomyPlacementStatus(const FHiroEconomyPlacementStatus& EconomyPlacementStatus)
{
    UE_LOG(LogTemp, Log, TEXT("%s"), *EconomyPlacementStatus.ToJson());
}

Start a new ad placement #

Start a new Ad placement by placement ID.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
FHiroEconomyPlacementStartRequest Request;
Request.PlacementId = TEXT("placement_1");

FHiroOnEconomyPlacementStart OnEconomyPlacementStart;
OnEconomyPlacementStart.AddDynamic(this, &AMyActor::OnEconomyPlacementStart);
FOnError OnError;

HiroClient->EconomyPlacementStart(Session, Request, OnEconomyPlacementStart, OnError);

void AMyActor::OnEconomyPlacementStart(const FHiroEconomyPlacementStatus& EconomyPlacementStatus)
{
    UE_LOG(LogTemp, Log, TEXT("%s"), *EconomyPlacementStatus.ToJson());
}

Placement success #

Webhook RPC to handle Rewarded Video Ad placement success callbacks.

1
2
3
4
5
FHiroOnEconomyPlacementSuccess  OnEconomyPlacementSuccess;
OnEconomyPlacementSuccess.AddDynamic(this, &AMyActor::OnEconomyPlacementSuccess);
FOnError OnError;

HiroClient->EconomyPlacementSuccess(Session, OnEconomyPlacementSuccess, OnError);

Placement fail #

Webhook RPC to handle Rewarded Video Ad placement failure callbacks.

1
2
3
4
5
FHiroOnEconomyPlacementFail  OnEconomyPlacementFail;
OnEconomyPlacementFail.AddDynamic(this, &AMyActor::OnEconomyPlacementFail);
FOnError OnError;

HiroClient->EconomyPlacementFail(Session, OnEconomyPlacementFail, OnError);