⌘K
↑↓ Navigate ↵ Open Esc Close
Tier 2Virtual CurrencyProductScript06 / 29

Virtual Currency: a four-wallet economy, three response formats to watch for

Cloud Code, the pattern for the RunScript call every custom script in this article is invoked through.

brainCloud supports Virtual Currencies: an app can configure an unlimited number of them. bitBuddies runs four: Coins, Gems, and FakeDollars scoped to the parent account, plus a per-buddy BuddyBling scoped to each child account. Every award, consume, and cross-currency exchange goes through a custom Cloud Code script, invoked with the same RunScript call from Article 5. Balances are not tracked client-side between calls. The client reads whatever balance the script response hands back and displays it.

How it works

  1. Initial balances ride in on the login response itself. A separate currency-fetch call at startup is not needed. data.currency.{gems,coins,fakeDollars}.balance is already in the auth payload.
  2. A child's currency (BuddyBling) is fetched separately, per child. It is not in the parent auth payload. It comes back from a dedicated child/fetchCurrencies script call scoped to that one child profile.
  3. Award and consume are separate named scripts, not one generic call. AwardCoinsToUser, AwardGemsToUser, and ConsumeCoinsForUser are three different custom Cloud Code scripts, each invoked through RunScript with its own script-name constant. There is no single "adjustBalance(currency, delta)" entry point; what changes between these calls is which script runs, not how it's called.
  4. Every response nests the new balance somewhere slightly different. Three currency scripts return three differently structured responses; read each one carefully before copying the pattern.

Code

Balances arrive with the login response, no extra callBrainCloudManager.cs:86-97
var currency = data["currency"] as Dictionary<string, object>;
if (currency != null)
{
    var gems = currency["gems"] as Dictionary<string, object>;
    CurrentUserInfo.UpdateGems((int)gems["balance"]);

    var coins = currency["coins"] as Dictionary<string, object>;
    CurrentUserInfo.UpdateCoins((int)coins["balance"]);

    var fakeMoney = currency["fakeDollars"] as Dictionary<string, object>;
    CurrentUserInfo.UpdateFakeMoney((int)fakeMoney["balance"]);
}
Award coins: RunScript, then parseBrainCloudManager.cs:627-654
public void RewardCoinsToParent(int in_coins)
{
    var scriptData = new Dictionary<string, object> { { "increaseAmount", in_coins } };
    Wrapper.ScriptService.RunScript(
        BitBuddiesConsts.AWARD_COINS_SCRIPT_NAME,   // "AwardCoinsToUser"
        scriptData.Serialize(),
        HandleSuccess("RewardCoinsToParent Success", OnRewardCoinsToParent),
        HandleFailure("RewardCoinsToParent Failed", OnFailureCallback));
}

private void OnRewardCoinsToParent(string jsonResponse, object cbObject)
{
    var packet = JsonReader.Deserialize<Dictionary<string, object>>(jsonResponse);
    var response = ((packet["data"] as Dictionary<string, object>)["response"] as Dictionary<string, object>);
    var getResult = response["getResult"] as Dictionary<string, object>;                        // <- "getResult"
    var currencyMap = (getResult["data"] as Dictionary<string, object>)["currencyMap"] as Dictionary<string, object>;
    var coins = currencyMap["coins"] as Dictionary<string, object>;
    CurrentUserInfo.UpdateCoins((int)coins["balance"]);
}
Consume coins: a differently nested responseBrainCloudManager.cs:612-624
public void OnConsumeCoins(string jsonResponse)
{
    var packet = JsonReader.Deserialize<Dictionary<string, object>>(jsonResponse);
    var response = ((packet["data"] as Dictionary<string, object>)["response"] as Dictionary<string, object>);
    var result = response["consumeCurrencyResult"] as Dictionary<string, object>;                // <- "consumeCurrencyResult", not "getResult"
    var currencyMap = (result["data"] as Dictionary<string, object>)["currencyMap"] as Dictionary<string, object>;
    var coins = currencyMap["coins"] as Dictionary<string, object>;
    CurrentUserInfo.UpdateCoins((int)coins["balance"]);
}
Award to a child profile: flatter still, and carries the child app idBrainCloudManager.cs:750-756
public void AwardBlingToChild(int in_amount)
{
    // Params for AwardBlingToChild(childAppId, profileId, increaseAmount)
    var scriptData = new Dictionary<string, object>
    {
        { "childAppId", BitBuddiesConsts.APP_CHILD_ID },
        { "profileId", GameManager.Instance.SelectedAppChildrenInfo.profileId },
        { "increaseAmount", in_amount }
    };
    // response.currencyMap.buddyBling.balance: no getResult/consumeCurrencyResult wrapper at all
}
What a coin-award script looks like on the server (different app: Marketplace/CloudCode/AwardUserCoins.ccjs)
var currencyService = bridge.getVirtualCurrencyServiceProxy();
var result = currencyService.awardCurrency("Coins", userLevel);
if (result.status == 200) {
  response = result.data.currencyMap.Coins.balance;
}

Gotchas worth knowing up front

  • Three award/consume scripts, three differently structured responses. response.getResult.data.currencyMap… (award), response.consumeCurrencyResult.data.currencyMap… (consume), and a flat response.currencyMap… (child award) all mean the same thing: the new balance. A parsing helper written against one of these will silently break on the others. A currency-response parser should not be generalized from a single example.
  • BuddyBling isn't in the login payload. If a child's currency reads zero on first render, check whether child/fetchCurrencies has actually resolved yet. It's a separate round-trip from auth, not bundled with it.
  • The script bodies that produce these bitBuddies responses aren't in this repo. Every call site and response above is read straight from bitBuddies' real client C#, so that part is fully verified. What actually runs inside AwardCoinsToUser/ConsumeCoinsForUser on the server is documented only in bitBuddies' README, in prose. That's a credible description, not confirmed source.
  • The AwardUserCoins.ccjs stand-in above is probably the wrong service, even though it's the right pattern. brainCloud's API catalog has a Product service with AwardParentCurrency/ConsumeParentCurrency/AwardPeerCurrency, and "parent/peer currency" is brainCloud's own term for exactly bitBuddies' parent-child app architecture (see Parent–Child Accounts). That's a closer conceptual match for AwardCoinsToUser/AwardBlingToChild than the generic Virtual Currency service the stand-in script uses. This remains unconfirmed, since bitBuddies' script bodies aren't in this repo either way. An equivalent parent/child currency flow should check Product's parent/peer methods before reaching for generic Virtual Currency.