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