Virtual Currency - Code

In-game currency used for purchasing [ECON-VirtualCurrency-03]

The Beamable API provides helper functions to subscribe to changes in the currency, and modify the currency (if the client can write itself). The basis for the Currency system is built on the InventoryService, which is built on the Content service. If you're not familiar with how Content operations work, you can read about them in the Content section.

API

Here are API highlights for InventoryUpdateBuilder which builds a list of one or more currency operations to execute, and InventoryService which executes the currency operations.

Note: This Beamable system handles player inventory and also player currency.

Add Currency

public async void AddCurrency()
{
   // Resolve Reference
   var currencyContentPrimary =  await _currencyRefPrimary.Resolve();
   
   // List the operations
   InventoryUpdateBuilder inventoryUpdateBuilder = new InventoryUpdateBuilder();
   inventoryUpdateBuilder.CurrencyChange(currencyContentPrimary.Id, +1);

   // Execute the operations
   await _beamContext.Api.InventoryService.Update(inventoryUpdateBuilder).Then(obj =>
   {
      Debug.Log($"AddCurrency() success.");
   });
}

Remove Currency

public async void RemoveCurrency()
{
   // Resolve Reference
   var currencyContentPrimary =  await _currencyRefPrimary.Resolve();
   
   // List the operations
   InventoryUpdateBuilder inventoryUpdateBuilder = new InventoryUpdateBuilder();
   inventoryUpdateBuilder.CurrencyChange(currencyContentPrimary.Id, -1);

   // Execute the operations
   await _beamContext.Api.InventoryService.Update(inventoryUpdateBuilder).Then(obj =>
   {
      Debug.Log($"RemoveCurrency() success.");
   });
}

Example

📘

Beamable SDK Examples

The following example code is available for download at GitHub.com/Beamable_SDK_Examples

In the InventoryCurrencyExample.cs, the user can click buttons to add, remove, and trade between available currencies.

Game View

Inspector

Code

using System.Collections.Generic;
using System.Linq;
using Beamable.Common.Api.Inventory;
using Beamable.Common.Content;
using Beamable.Common.Inventory;
using Beamable.Examples.Shared;
using UnityEngine;
using UnityEngine.Events;

namespace Beamable.Examples.Services.InventoryService.InventoryCurrencyExample
{
   [System.Serializable]
   public class InventoryCurrencyExampleEvent : UnityEvent<InventoryCurrencyExampleData> { }

   /// <summary>
   /// Demonstrates <see cref="InventoryService"/>.
   /// </summary>
   public class InventoryCurrencyExample : MonoBehaviour
   {
      //  Events  ---------------------------------------
      [HideInInspector]
      public InventoryCurrencyExampleEvent OnRefreshed = new InventoryCurrencyExampleEvent();
      
      //  Fields  ---------------------------------------
      [SerializeField] private CurrencyRef _currencyRefPrimary = null;
      [SerializeField] private CurrencyRef _currencyRefSecondary = null;

      private BeamContext _beamContext;
      private const int CurrencyDeltaPerClick = 1;
      private const string ContentType = "currency";
      private readonly InventoryCurrencyExampleData _inventoryCurrencyExampleData = new 
          InventoryCurrencyExampleData();
         
      //  Unity Methods  --------------------------------
      protected void Start()
      {
         Debug.Log($"Start()");

         SetupBeamable();
      }

      
      //  Methods  --------------------------------------
      private async void SetupBeamable()
      { 
   
         _beamContext = BeamContext.Default;
         await _beamContext.OnReady;

         Debug.Log($"_beamContext.PlayerId = {_beamContext.PlayerId}");

         _inventoryCurrencyExampleData.CurrencyContentPrimary = 
            await _currencyRefPrimary.Resolve();
         
         _inventoryCurrencyExampleData.CurrencyContentSecondary = 
            await _currencyRefSecondary.Resolve();

         // All currencies (Available in game)
         _beamContext.Api.ContentService.Subscribe(ContentService_OnChanged);
         
         // Filtered currencies (Owned by current player)
         _beamContext.Api.InventoryService.Subscribe(ContentType, InventoryService_OnChanged);

      }

      
      public void Refresh()
      {
         string refreshLog = $"Refresh() ...\n" +
                             $"\n * ContentType = {ContentType}" +
                             $"\n * ContentCurrencyNames.Count = 
                             {_inventoryCurrencyExampleData.ContentCurrencyNames.Count}" +
                             $"\n * InventoryCurrencyNames.Count = 
                             {_inventoryCurrencyExampleData.InventoryCurrencyNames.Count}\n\n";
            
         //Debug.Log(refreshLog);

         OnRefreshed?.Invoke(_inventoryCurrencyExampleData);
      }
      

      public async void AddPrimaryCurrency()
      {
         InventoryUpdateBuilder inventoryUpdateBuilder = new InventoryUpdateBuilder();
         inventoryUpdateBuilder.CurrencyChange(_inventoryCurrencyExampleData.CurrencyContentPrimary.Id, 
            CurrencyDeltaPerClick);

         // Add
         await _beamContext.Api.InventoryService.Update(inventoryUpdateBuilder).Then(obj =>
         {
            Debug.Log($"#1. PLAYER AddPrimaryCurrency2() success.");
                     
         });
      }

      
      public async void RemovePrimaryCurrency()
      {
         InventoryUpdateBuilder inventoryUpdateBuilder = new InventoryUpdateBuilder();
         
         // Remove
         inventoryUpdateBuilder.CurrencyChange(_inventoryCurrencyExampleData.CurrencyContentPrimary.Id, 
            -CurrencyDeltaPerClick);

         await _beamContext.Api.InventoryService.Update(inventoryUpdateBuilder).Then(obj =>
         {
            Debug.Log($"#2. PLAYER RemovePrimaryCurrency() success.");
                     
         });
      }

      
      public async void TradePrimaryToSecondary()
      {
         InventoryUpdateBuilder inventoryUpdateBuilder = new InventoryUpdateBuilder();
         
         // Remove Primary
         inventoryUpdateBuilder.CurrencyChange(_inventoryCurrencyExampleData.CurrencyContentPrimary.Id, 
            -CurrencyDeltaPerClick);
         
         // Add Secondary
         inventoryUpdateBuilder.CurrencyChange(_inventoryCurrencyExampleData.CurrencyContentSecondary.Id, 
            CurrencyDeltaPerClick);

         await _beamContext.Api.InventoryService.Update(inventoryUpdateBuilder).Then(obj =>
         {
            Debug.Log($"#3. PLAYER TradePrimaryToSecondary() success.");
                     
         });
      }
      
      
      public async void TradeSecondaryToPrimary()
      {
         InventoryUpdateBuilder inventoryUpdateBuilder = new InventoryUpdateBuilder();
         
         // Remove Secondary
         inventoryUpdateBuilder.CurrencyChange(_inventoryCurrencyExampleData.CurrencyContentSecondary.Id, 
            -CurrencyDeltaPerClick);
         
         // Add Primary
         inventoryUpdateBuilder.CurrencyChange(_inventoryCurrencyExampleData.CurrencyContentPrimary.Id, 
            CurrencyDeltaPerClick);

         await _beamContext.Api.InventoryService.Update(inventoryUpdateBuilder).Then(obj =>
         {
            Debug.Log($"#4. PLAYER TradeSecondaryToPrimary() success.");
                     
         });
      }
      
      
      //  Event Handlers  -------------------------------
      private void ContentService_OnChanged(ClientManifest clientManifest)
      {
         _inventoryCurrencyExampleData.IsChangedContentService = true;
         
         // Filter to ONLY CurrencyContent
         List<ClientContentInfo> clientContentInfos =  clientManifest.entries.Where((clientContentInfo, i) 
               => 
               ExampleProjectHelper.IsMatchingClientContentInfo(clientContentInfo, ContentType)).ToList();
         
         Debug.Log($"GAME - ContentService_OnChanged, " +
                   $"currencies.Count = {clientContentInfos.Count}");
         
         _inventoryCurrencyExampleData.ContentCurrencyNames.Clear();
         foreach (ClientContentInfo clientContentInfo in clientContentInfos)
         {
            string currencyName = 
                ExampleProjectHelper.GetDisplayNameFromContentId(clientContentInfo.contentId);
            string currencyNameFormatted = $"{currencyName}";
            _inventoryCurrencyExampleData.ContentCurrencyNames.Add(currencyNameFormatted);
         }
         
         // Alphabetize
         _inventoryCurrencyExampleData.ContentCurrencyNames.Sort();
         
         Refresh();
      }
      
      
      private void InventoryService_OnChanged(InventoryView inventoryView)
      {
         _inventoryCurrencyExampleData.IsChangedInventoryService = true;
         
         Debug.Log($"PLAYER - InventoryService_OnChanged, " +
                   $"currencies.Count = {inventoryView.currencies.Count}");

         _inventoryCurrencyExampleData.InventoryCurrencyNames.Clear();
         foreach (KeyValuePair<string, long> kvp in inventoryView.currencies)
         {
            string currencyName = ExampleProjectHelper.GetDisplayNameFromContentId(kvp.Key);
            string currencyNameFormatted = $"{currencyName} x {kvp.Value}";
            _inventoryCurrencyExampleData.InventoryCurrencyNames.Add(currencyNameFormatted);
         }
         
         // Alphabetize
         _inventoryCurrencyExampleData.InventoryCurrencyNames.Sort();
         
         Refresh();
      }
   }
}

Did this page help you?