View as Markdown

Economy

Read more about the Economy system in Hiro here.

Functions #

ReapplyInitializeUser #

Apply the current initialize_user configuration to an existing user account. Only currencies the user has never held and items they do not currently own are granted, so users keep any progress they already have.

Hiro stores a version hash of the initialize_user configuration against each user. If the configuration has not changed since the user was last initialized, this function is a no-op, making it safe to call repeatedly (for example, on login).

1
2
3
4
5
6
userId := "userId"

err := systems.GetEconomySystem().ReapplyInitializeUser(ctx, logger, db, nk, userId)
if err != nil {
  return err
}

RewardCreate #

Prepare a new reward configuration to be filled in and used later.

1
rewardConfig := systems.GetEconomySystem().RewardCreate()

RewardConvert #

Transform a wire representation of a reward into an equivalent configuration representation.

1
2
3
4
5
6
7
8
9
contents := &hiro.AvailableRewards{
  Guaranteed:     nil,
  Weighted:       nil,
  MaxRolls:       0,
  TotalWeight:    0,
  MaxRepeatRolls: 0,
}

rewardConfig := systems.GetEconomySystem().RewardConvert(contents)

RewardRoll #

Resolve a reward configuration into an actual reward. Rolling selects among any weighted entries and merges them with the guaranteed entries, resolves every min, max, and multiple range to a fixed amount, expands item sets into specific item IDs, and scales the rolled currency and item amounts by the reward modifiers currently active for the user or team.

Rolling is the only step that applies active reward modifiers. A reward built by hand and passed straight to RewardGrant skips them, so roll for rewards even when the config contains no weighted entries.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
userId := "userId"
rewardConfig := &hiro.EconomyConfigReward{
  Guaranteed:     nil,
  Weighted:       nil,
  MaxRolls:       0,
  MaxRepeatRolls: 0,
  TotalWeight:    0,
}

reward, err := systems.GetEconomySystem().RewardRoll(ctx, logger, nk, userId, rewardConfig)
if err != nil {
  return err
}

RewardGrant #

Update a user’s economy, inventory, and/or energy models with the contents of a rolled reward. It takes a full hiro.Reward object like the RewardRoll function produces from an *hiro.EconomyConfigReward so it can carry currencies, items, specific item instances (with pre-set properties), energies, energy modifiers, reward modifiers, a team reward, a mailbox expiry, and a message.

Always roll before you grant
Granting credits the amounts in the reward exactly as received and performs no modifier math, so resolve the amounts with RewardRoll first even when it doesn’t contain any weighted rewards. When a reward carries reward_modifiers, RewardGrant registers them as active on the player but doesn’t apply them to the reward it’s granting. They take effect on the next RewardRoll.
1
2
3
4
5
6
7
8
9
userId := "userId"
// reward can be received from another function call, such as RewardRoll above.
metadata := map[string]interface{}{}
ignoreLimits := false

newItems, updatedItems, notGrantedItemIDs, err := systems.GetEconomySystem().RewardGrant(ctx, logger, nk, userId, reward, metadata, ignoreLimits)
if err != nil {
  return err
}

DonationClaim #

Claim donation rewards for a user for the given donation.

1
2
3
4
5
6
7
userId := "userId"
donationIds := []string{"donationId_001", "donationId_002", "donationId_003"}

donationsList, err := systems.GetEconomySystem().DonationClaim(ctx, logger, nk, userId, donationIds)
if err != nil {
  return err
}

DonationGet #

Get all donations for the given list of users.

1
2
3
4
5
6
userIds := []string{"userId_001", "userId_002", "userId_003"}

donationsList, err := systems.GetEconomySystem().DonationGet(ctx, logger, nk, userIds)
if err != nil {
  return err
}

DonationGive #

Contribute to a particular donation for a user.

1
2
3
4
5
6
7
8
userId := "userId"
donationId := "donationId"
fromUserId := "fromUserId"

updatedWallet, updatedInventory, rewardModifiers, contributorReward, timestamp, err := systems.GetEconomySystem().DonationGive(ctx, logger, nk, userId, donationId, fromUserId)
if err != nil {
  return err
}

DonationRequest #

Create a donation request for a given donation and user.

1
2
3
4
5
6
7
userId := "userId"
donationId := "donationId"

donation, success, err := systems.GetEconomySystem().DonationRequest(ctx, logger, nk, userId, donationId)
if err != nil {
  return err
}

List #

Get the defined store items and placements within the economy system.

1
2
3
4
5
6
userId := "userId"

storeItems, placements, rewardModifiers, timestamp, err := systems.GetEconomySystem().List(ctx, logger, nk, userId)
if err != nil {
  return err
}

Grant #

Add currencies, items, and reward modifiers to a user’s economy. Takes raw currencies/items maps plus optional reward modifiers (no reward config rolling, mailbox delivery, or energy/team reward handling).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
userId := "userId"
currencies := map[string]int64{"coins": 10}
items := map[string]int64{"sword": 1}
modifiers := []*hiro.RewardModifier{{}}
walletMetadata := map[string]interface{}{}

updatedWallet, rewardModifiers, timestamp, err := systems.GetEconomySystem().Grant(ctx, logger, nk, userId, currencies, items, modifiers, walletMetadata)
if err != nil {
  return err
}

UnmarshalWallet #

Unmarshal and return an account’s wallet as a map[string]int64.

1
2
3
4
5
6
account := &api.Account{}

wallet, err := systems.GetEconomySystem().UnmarshalWallet(account)
if err != nil {
  return err
}

PurchaseIntent #

Create a purchase intent for a particular store item and user.

1
2
3
4
5
6
7
8
9
userId := "userId"
itemId := "itemId"
store := hiro.EconomyStoreType_ECONOMY_STORE_TYPE_APPLE_APPSTORE
sku := "sku"

err := systems.GetEconomySystem().PurchaseIntent(ctx, logger, nk, userId, itemId, store, sku)
if err != nil {
  return err
}

PurchaseItem #

Validate a purchase and give the user the appropriate rewards.

1
2
3
4
5
6
7
8
9
userId := "userId"
itemId := "itemId"
store := hiro.EconomyStoreType_ECONOMY_STORE_TYPE_APPLE_APPSTORE
receipt := "<receipt>"

updatedWallet, updatedInventory, reward, isSandboxPurchase, err := systems.GetEconomySystem().PurchaseItem(ctx, logger, db, nk, userId, itemId, store, receipt)
if err != nil {
  return err
}

PurchaseRestore #

Process a restore attempt for the given user, based on a set of restore receipts.

1
2
3
4
5
6
7
8
userId := "userId"
store := hiro.EconomyStoreType_ECONOMY_STORE_TYPE_APPLE_APPSTORE
receipts := []string{"<receipt_001>", "<receipt_002>"}

err := systems.GetEconomySystem().PurchaseRestore(ctx, logger, nk, userId, store, receipts)
if err != nil {
  return err
}

PlacementStatus #

Get the status of a specified placement.

1
2
3
4
5
6
7
8
9
userId := "userId"
rewardId := "rewardId"
placementId := "placementId"
retryCount := 3

placementStatus, err := systems.GetEconomySystem().PlacementStatus(ctx, logger, nk, userId, rewardId, placementId, retryCount)
if err != nil {
  return err
}

PlacementStart #

Indicate that a user has begun viewing an ad placement.

1
2
3
4
5
6
7
8
userId := "userId"
placementId := "placementId"
metadata := map[string]string{}

placementStatus, err := systems.GetEconomySystem().PlacementStart(ctx, logger, nk, userId, placementId, metadata)
if err != nil {
  return err
}

PlacementSuccess #

Indicate that a user has successfully viewed an ad placement and provide the appropriate reward.

1
2
3
4
5
6
7
8
userId := "userId"
placementId := "placementId"
rewardId := "rewardId"

reward, placementMetadata, err := systems.GetEconomySystem().PlacementSuccess(ctx, logger, nk, userId, rewardId, placementId)
if err != nil {
  return err
}

PlacementFail #

Indicate that a user has failed to successfully view an ad placement.

1
2
3
4
5
6
7
8
userId := "userId"
placementId := "placementId"
rewardId := "rewardId"

placementMetadata, err := systems.GetEconomySystem().PlacementFail(ctx, logger, nk, userId, rewardId, placementId)
if err != nil {
  return err
}

SetAllowFakeReceipts #

Allow or disallow fake receipts for the economy system. Call this during server module initialization, fake receipts are disabled by default.

1
2
3
// Enable fake receipts.
economySystem := systems.GetEconomySystem()
economySystem.SetAllowFakeReceipts(true)

Hooks #

SetOnDonationClaimReward #

Set a custom reward function which will run after a donation’s reward is rolled.

1
2
3
4
5
6
systems.GetEconomySystem().SetOnDonationClaimReward(DonationClaimReward)

func DonationClaimReward(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, userID, sourceID string, source *hiro.EconomyConfigDonation, rewardConfig *hiro.EconomyConfigReward, reward *hiro.Reward) (*hiro.Reward, error) {
	// Modify reward or take additional actions.
	return reward, nil
}

SetOnDonationContributorReward #

Set a custom reward function which will run after a donation’s sender reward is rolled.

1
2
3
4
5
6
systems.GetEconomySystem().SetOnDonationContributorReward(OnDonationContributorReward)

func OnDonationContributorReward(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, userID, sourceID string, source *hiro.EconomyConfigDonation, rewardConfig *hiro.EconomyConfigReward, reward *hiro.Reward) (*hiro.Reward, error) {
	// Modify reward or take additional actions.
	return reward, nil
}

SetOnPlacementReward #

Set a custom reward function which will run after a placement’s reward is rolled.

1
2
3
4
5
6
systems.GetEconomySystem().SetOnPlacementReward(OnPlacementReward)

func OnPlacementReward(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, userID, sourceID string, source *hiro.EconomyPlacementInfo, rewardConfig *hiro.EconomyConfigReward, reward *hiro.Reward) (*hiro.Reward, error) {
	// Modify reward or take additional actions.
	return reward, nil
}

SetOnStoreItemReward #

Set a custom reward function which will run after store item’s reward is rolled.

1
2
3
4
5
6
systems.GetEconomySystem().SetOnStoreItemReward(OnStoreItemReward)

func OnStoreItemReward(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, userID, sourceID string, source *hiro.EconomyConfigStoreItem, rewardConfig *hiro.EconomyConfigReward, reward *hiro.Reward) (*hiro.Reward, error) {
	// Modify reward or take additional actions.
	return reward, nil
}