Skip to content

Accessing Configs Data and Profiles

Game Configs

Accessing Single Document

To access a specific document by its ID, you can use the following code:

var document = Balancy.CMS.GetModelByUnnyId<YourModel>(id);
const document = Balancy.CMS.getModelByUnnyId<YourModel>(id);

Example:

var item26 = Balancy.CMS.GetModelByUnnyId<Balancy.Models.SmartObjects.Item>("26");
Debug.Log($"item26.unnyId = {item26.UnnyId}");
Debug.Log($"item26.Name = {item26.Name}");
Debug.Log($"item26.MaxStack = {item26.MaxStack}");
const item26 = Balancy.CMS.getModelByUnnyId<SmartObjectsItem>("26");
console.log(`item26.unnyId = ${item26.unnyId}`);
console.log(`item26.Name = ${item26.name.getValue()}`);
console.log(`item26.MaxStack = ${item26.maxStack}`);

Accessing List of Documents

To get a list of all documents of a specific type, you can use the following code:

var documents = Balancy.CMS.GetModels<YourModel>(includeChildren);
const documents = Balancy.CMS.getModels<YourModel>(includeChildren);

includeChildren - if true, the method returns all documents of the specified type and their children. If false, it returns only the documents of the specified type.

Example:

var allItems = Balancy.CMS.GetModels<Balancy.Models.SmartObjects.Item>(true);
Debug.Log("AllItems count = " + allItems.Length);
foreach (var item in allItems)
{
    Debug.Log("=== New Item ===");
    Debug.Log($"unnyId = {item.UnnyId}");
    Debug.Log($"Name = {item.Name}");
    Debug.Log($"MaxStack = {item.MaxStack}");
}
const allItems = Balancy.CMS.getModels<SmartObjectsItem>(true);
console.log(`AllItems count = ${allItems.length}`);
allItems.forEach(item => {
    console.log("=== New Item ===");
    console.log(`unnyId = ${item.unnyId}`);
    console.log(`Name = ${item.name.getValue()}`);
    console.log(`MaxStack = ${item.maxStack}`);
});

Profiles

Custom Profile

If you have a custom profile, you can easily access it:

var profile = Balancy.Profiles.Get<Profile>();
const profile = Balancy.Profiles.get<Profile>();

System Profile

The system profile contains various data points that are crucial for understanding the user's interactions and status in the application.

var systemProfile = Balancy.Profiles.System;
const systemProfile = Balancy.Profiles.system;

System Profile Fields

  • Payments: Provides access to payment-related information, including purchase history, total spend, VIP level, and other payment metrics.

    • DaysForPurchase: Number of days since the last purchase.
    • Purchases: List of individual purchases made by the user.
    • TotalSpend: Total amount spent by the user.
    • LastPaymentTime: Timestamp of the last payment.
    • MaxPayment: Maximum payment made by the user.
    • PaymentsCount: Total number of payments made.
    • ResourcesMultiplier: Multiplier applied to resources from payments.
    • LevelVIP: VIP level of the user.
    • ComfortablePayment: A comfortable payment value determined by user behavior.
  • SmartInfo: Stores general LiveOps information

    • GameOffers: List of offers available in the game.
    • GameOfferGroups: Grouped offers available in the game.
    • GameEvents: List of events happening in the game.
  • SegmentsInfo: Contains information about different user segments that the profile belongs to.

    • Segments: List of user segments.
  • GeneralInfo: Holds general, non-categorized information about the user.

    • PlayTime: Total playtime of the user.
    • AppVersion: Version of the app used by the user.
    • EngineVersion: Version of the game engine.
    • Platform: Platform on which the app is running.
    • PlatformId: Identifier for the platform.
    • SystemLanguage: Language of the user's system.
    • Country: User's country.
    • TimeSincePurchase: Time elapsed since the last purchase.
    • Session: Current session number.
    • IsNewUser: Indicates if the user is new.
    • FirstLoginTime: Timestamp of the user's first login.
    • Level: Current level of the user.
    • TutorialStep: Current tutorial step the user is on.
    • TrafficSource: Source of user acquisition.
    • DontDisturb: Indicates if the user has enabled Do Not Disturb.
    • LastLoginTime: Timestamp of the last login.
    • CurrentDay: Current in-game day.
    • TrafficCampaign: Campaign associated with user acquisition.
    • ProfileId: Unique identifier for the user's profile.
    • DeviceId: Unique device identifier.
    • CustomId: Custom identifier set by the application.
    • GameLocalization: Localization settings for the game.
    • TimeSinceInstall: Time elapsed since the app was installed.
    • DeviceModel: Model of the user's device.
    • DeviceName: Name of the user's device.
    • DeviceType: Type of device (e.g., mobile, tablet).
    • OperatingSystem: Operating system of the user's device.
    • OperatingSystemFamily: Family of the operating system.
    • SystemMemorySize: Size of the system memory.
    • InstallVersion: Version of the app at the time of installation.
  • TestsInfo: Stores information regarding A/B tests that the user is currently involved in.

    • Tests: List of A/B tests.
    • AvoidedTests: List of tests that the user has opted out of.
  • AdsInfo: Provides data on ads viewed or interacted with by the user.

    • RevenueTotal: Total revenue generated from ads.
    • AdRewarded: Information about rewarded ads.
    • AdInterstitial: Information about interstitial ads.
    • AdCustom: Information about custom ads.
    • InterstitialAdsPeriod: Time period between interstitial ads.
    • RevenueToday: Revenue generated from ads today.
  • LiveOpsInfo: Contains information related to additional LiveOps activities, such as Daily Bonus.

    • DailyRewardCollected: Indicates if the daily reward has been collected.
    • DailyRewardCollectTime: Timestamp of the last daily reward collection.
  • Inventories: Tracks inventory-related data for the user, such as items and counts.

    • Currencies: Information about in-game currencies.
    • EventItems: Information about events specific items.
    • Items: Information about general items.

Reset Account (All Profiles)

To reset all profiles, use the following code:

Balancy.Profiles.Reset();
Balancy.Profiles.reset();

The reset is instant, and you can access fresh profiles immediately after the reset.

Game Events and Offers

Use LiveOps Callbacks to receive notifications about update statuses of Events and Offers at runtime. Use one of the methods below to request the list of active Events or Offers:

var smartInfo = Balancy.Profiles.System.SmartInfo;
var activeGameEvents = smartInfo.GameEvents;
var activeOffers = smartInfo.GameOffers;
var activeOfferGroups = smartInfo.GameOfferGroups;
const smartInfo = Balancy.Profiles.system.smartInfo;
const activeGameEvents = smartInfo.gameEvents;
const activeOffers = smartInfo.gameOffers;
const activeOfferGroups = smartInfo.gameOfferGroups;

There are several methods you can use to know how much time is left for an event or offer to end or to start.

offerInfo.GetSecondsLeftBeforeDeactivation();//offerInfo is an element of Balancy.Profiles.System.SmartsInfo.GameOffers
eventInfo.GetSecondsLeftBeforeDeactivation();//eventInfo is an element of Balancy.Profiles.System.SmartsInfo.GameEvents
gameEvent.GetSecondsLeftBeforeDeactivation();
gameEvent.GetSecondsBeforeActivation(ignoreTriggers);
offerInfo.getSecondsLeftBeforeDeactivation();//offerInfo is an element of Balancy.Profiles.system.smartsInfo.gameOffers
eventInfo.getSecondsLeftBeforeDeactivation();//eventInfo is an element of Balancy.Profiles.system.smartsInfo.gameEvents
gameEvent.getSecondsLeftBeforeDeactivation();
gameEvent.getSecondsBeforeActivation(ignoreTriggers);

Some of the conditions might have complex logic and include not only the time, but also some user properties or segmentations. You can pass ignoreTriggers=true to ignore such conditions.

A/B Tests

Use LiveOps Callbacks to receive notifications about new A/B Tests at runtime. Use the method below to request the list of active A/B Tests:

var myAbTests = Balancy.Profiles.System.TestsInfo.Tests;
foreach (var myAbTest in myAbTests)
    Debug.Log($"My Test {myAbTest.Test?.Name} variant = {myAbTest.Variant?.Name} finished = {myAbTest.Finished}");
const myAbTests = Balancy.Profiles.system.testsInfo.tests;
for (let i = 0;i< myAbTests.count;i++) {
    const myAbTest = myAbTests.get(i);
    console.log(i, ")", myAbTest.test?.name, "variant = ", myAbTest.variant?.name, " finished = ", myAbTest.finished);
}

Segmentation

Use LiveOps Callbacks to receive notifications about changes in Segmentation at runtime. Use the method below to request the status of your Segments.

var mySegments = Balancy.Profiles.System.SegmentsInfo.Segments;
foreach (var mySegment in mySegments) {
    if (mySegment.IsIn)
        Debug.Log($"My Segment {mySegment.Segment?.Name}");
}
const mySegments = Balancy.Profiles.system.segmentsInfo.segments;
for (let i = 0;i < mySegments.count;i++) {
    const mySegment = mySegments.get(i);
    if (mySegment.isIn)
        console.log("My Segment " + mySegment.segment?.name);
}

Game Shops

The shop system is organized in a hierarchical structure:

  • Game Shops: Top-level containers that represent different stores (e.g., Main Shop, Event Shop, VIP Shop)
  • Shop Pages: Categories within a shop (e.g., Items, Weapons, Consumables)
  • Shop Slots: Individual items available for purchase within a page
  • Store Items: The actual purchasable items with pricing and rewards

Accessing Available Shops

To retrieve the list of available Game Shops, use the following method:

var shopsInfo = Balancy.Profiles.System.ShopsInfo;
var gameShops = shopsInfo.GameShops;
const shopsInfo = Balancy.Profiles.system.shopsInfo;
const gameShops = shopsInfo.gameShops;

This returns a collection of GameShop objects, each representing a unique shop configuration.

Working with Active Shop

You can access the currently active shop directly:

var activeShop = shopsInfo.ActiveShopInfo;
var shopName = activeShop?.Shop?.Name;
const activeShop = shopsInfo.activeShopInfo;
const shopName = activeShop?.shop?.name?.value;

The active shop is automatically determined by Balancy based on your dashboard configuration and user segmentation.

Accessing Shop Pages

Each Game Shop can have multiple pages for organizing items into categories. To retrieve and work with shop pages:

var shopPages = activeShop?.ActivePages;
var firstPage = shopPages?.FirstOrDefault();

// Iterate through all pages
foreach (var page in shopPages)
{
    Debug.Log($"Page: {page.Page?.Name}");
}
const shopPages = activeShop?.activePages?.toArray() || [];
const firstPage = shopPages.length > 0 ? shopPages[0] : null;

// Iterate through all pages
shopPages.forEach(page => {
    console.log(`Page: ${page.page?.name?.value}`);
});

Displaying Shop Slots and Store Items

Each Shop Page contains multiple Shop Slots, which reference store items available for purchase:

var shopSlots = selectedPage?.ActiveSlots;

foreach (var shopSlot in shopSlots)
{
    var storeItem = shopSlot.Slot?.StoreItem;
    var itemName = storeItem?.Name;
    var price = storeItem?.Price?.Product?.Price;
    var priceType = storeItem?.Price?.Type;

    Debug.Log($"Item: {itemName}, Price: {price}, Type: {priceType}");
}
const shopSlots = selectedPage?.activeSlots?.toArray() || [];

shopSlots.forEach(shopSlot => {
    const storeItem = shopSlot.slot?.storeItem;
    const itemName = storeItem?.name?.value;
    const price = storeItem?.price?.product?.price;
    const priceType = storeItem?.price?.type;

    console.log(`Item: ${itemName}, Price: ${price}, Type: ${priceType}`);
});

Shop Slot Availability and Limits

Shop slots can have various availability restrictions and purchase limits. Use these methods to check slot status:

// Check if slot is currently available for purchase
bool isAvailable = shopSlot.IsAvailable();

// Get seconds until slot becomes available
int secondsUntilAvailable = shopSlot.GetSecondsLeftUntilAvailable();

// Check if slot has purchase limits
bool hasLimits = shopSlot.HasLimits();

// Get purchase limit information
int purchaseLimit = shopSlot.GetPurchasesLimitForCycle();
int purchasesDone = shopSlot.GetPurchasesDoneDuringTheLastCycle();

Debug.Log($"Available: {isAvailable}");
Debug.Log($"Limit: {purchasesDone}/{purchaseLimit}");
// Check if slot is currently available for purchase
const isAvailable = shopSlot.isAvailable();

// Get seconds until slot becomes available
const secondsUntilAvailable = shopSlot.getSecondsLeftUntilAvailable();

// Check if slot has purchase limits
const hasLimits = shopSlot.hasLimits();

// Get purchase limit information
const purchaseLimit = shopSlot.getPurchasesLimitForCycle();
const purchasesDone = shopSlot.getPurchasesDoneDuringTheLastCycle();

console.log(`Available: ${isAvailable}`);
console.log(`Limit: ${purchasesDone}/${purchaseLimit}`);

Purchasing Shop Items

High-Level Purchase Methods

For most use cases, use the high-level purchase methods that handle all the complexity automatically:

// Purchase from shop slot (recommended)
Balancy.API.InitPurchaseShop(shopSlot, (success, errorMessage) => {
    if (success) {
        Debug.Log("Purchase successful!");
    } else {
        Debug.Log($"Purchase failed: {errorMessage}");
    }
});

// Direct store item purchase (use only when necessary)
Balancy.API.InitPurchase(storeItem, (success, errorMessage) => {
    Debug.Log($"Purchase result: {success}, Error: {errorMessage}");
});
// Purchase from shop slot (recommended)
Balancy.API.initPurchaseShop(shopSlot, (success, errorMessage) => {
    if (success) {
        console.log("Purchase successful!");
    } else {
        console.log(`Purchase failed: ${errorMessage}`);
    }
});

// Direct store item purchase (use only when necessary)
Balancy.API.initPurchase(storeItem, (success, errorMessage) => {
    console.log(`Purchase result: ${success}, Error: ${errorMessage}`);
});

Low-Level Purchase Methods

For advanced scenarios, you can use low-level purchase methods:

// Soft currency purchase
bool success = Balancy.API.SoftPurchaseShopSlot(shopSlot);

// Hard currency purchase (requires payment processing)
var paymentInfo = new Balancy.Core.PaymentInfo
{
    Receipt = receipt,
    Price = price,
    Currency = currency,
    ProductId = productId,
    OrderId = orderId
};

Balancy.API.HardPurchaseShopSlot(shopSlot, paymentInfo, (response) => {
    Debug.Log($"Purchase result: {response.Success}");
}, requireValidation: true);
// Soft currency purchase
const success = Balancy.API.softPurchaseShopSlot(shopSlot);

// Hard currency purchase (requires payment processing)
const paymentInfo = new BalancyPaymentInfo(
    price, receipt, productId, currency, orderId
);

Balancy.API.hardPurchaseShopSlot(shopSlot, paymentInfo, (response) => {
    console.log(`Purchase result: ${response.success}`);
}, true);

For detailed information about purchase methods and payment processing, refer to the API Documentation.

Listening for Shop Updates

Since shop contents may change dynamically based on events, segmentation, or time-based conditions, subscribe to onShopUpdated to refresh the shop interface:

Balancy.Callbacks.OnShopUpdated += () =>
{
    Debug.Log("Shop data updated - refreshing UI");
    RefreshShopDisplay();
};
const shopUpdatedId = Balancy.Callbacks.onShopUpdated.subscribe(() => {
    console.log("Shop data updated - refreshing UI");
    refreshShopDisplay();
});

// Unsubscribe when component is destroyed
Balancy.Callbacks.onShopUpdated.unsubscribe(shopUpdatedId);

Finding Shop Slots

You can search for specific shop slots using various methods:

var shopsInfo = Balancy.Profiles.System.ShopsInfo;

// Find slot by ID
var shopSlot = shopsInfo.FindShopSlotById("slot_123");

// Find slot by store slot reference
var shopSlotByReference = shopsInfo.FindShopSlot(storeSlot);

// Find slot within specific shop
var shopSlotInShop = activeShop.FindShopSlotById("slot_123");
const shopsInfo = Balancy.Profiles.system.shopsInfo;

// Find slot by ID
const shopSlot = shopsInfo.findShopSlotById("slot_123");

// Find slot by store slot reference
const shopSlotByReference = shopsInfo.findShopSlot(storeSlot);

// Find slot within specific shop
const shopSlotInShop = activeShop.findShopSlotById("slot_123");

Best Practices

  1. Always check availability before allowing purchases using shopSlot.IsAvailable()
  2. Display purchase limits to inform users about remaining purchases
  3. Subscribe to shop updates to keep the UI synchronized with server changes
  4. Use high-level purchase methods (InitPurchaseShop) for most scenarios
  5. Handle purchase callbacks to update UI and provide user feedback
  6. Implement proper error handling for failed purchases
  7. Cache shop data temporarily but refresh on updates to avoid stale information

Using these methods, you can create a fully dynamic in-game shop system where items, pages, pricing, and purchase logic are seamlessly managed by Balancy, providing a flexible and powerful e-commerce solution for your game.

Battle Pass

The Battle Pass system is organized hierarchically:

  • Battle Pass Game Event: A time-limited event containing battle pass configuration
  • Battle Pass Config: Defines progression requirements, levels, and reward lines
  • Reward Lines: Different tracks (e.g., Free Track, Premium Track) with rewards for each level
  • Progression System: Score-based advancement through levels
  • Reward Status: Tracks what rewards are available, claimed, or locked

Battle Pass events are a subtype of Game Events. To access active battle pass events:

var smartInfo = Balancy.Profiles.System.SmartInfo;
var activeGameEvents = smartInfo.GameEvents;

foreach (var eventInfo in activeGameEvents)
{
    if (eventInfo.GameEvent is Balancy.Models.LiveOps.BattlePass.GameEvent battlePassEvent)
    {
        Debug.Log($"Battle Pass: {battlePassEvent.Name}");
        var config = battlePassEvent.Config;
        // Work with battle pass...
    }
}
const smartInfo = Balancy.Profiles.system.smartInfo;
const activeGameEvents = smartInfo.gameEvents;

for (let i = 0; i < activeGameEvents.count; i++) {
  const eventInfo = activeGameEvents.get(i);
  const gameEvent = eventInfo.gameEvent;
  if (gameEvent instanceof LiveOpsBattlePassGameEvent) {
    console.log(`Battle Pass: ${gameEvent.name?.value}`);
    const config = gameEvent.config;
    // Work with battle pass...
  }
}

Battle Pass Progress Information

To access player's progress in battle passes:

var battlePassesInfo = Balancy.Profiles.System.BattlePassesInfo;
var battlePassInfo = battlePassesInfo.FindBattlePassInfo(battlePassEvent);

if (battlePassInfo != null)
{
    var currentLevel = battlePassInfo.Level;
    var currentScore = battlePassInfo.Scores;
    var isFinished = battlePassInfo.Finished;

    Debug.Log($"Level: {currentLevel}, Score: {currentScore}");
}
const battlePassesInfo = Balancy.Profiles.system.battlePassesInfo;
const battlePassInfo = battlePassesInfo.findBattlePassInfo(battlePassEvent);

if (battlePassInfo) {
    const currentLevel = battlePassInfo.level;
    const currentScore = battlePassInfo.scores;
    const isFinished = battlePassInfo.finished;

    console.log(`Level: ${currentLevel}, Score: ${currentScore}`);
}

Battle Pass Configuration

The Battle Pass configuration contains essential information about progression and rewards:

var config = battlePassEvent.Config;
if (config != null)
{
    var battlePassName = config.Name;
    var progressionType = config.Type;
    var progressionItem = config.ProgressionItem; // Item used for scoring
    var levelScores = config.Scores; // Score requirements for each level
    var rewardLines = config.Rewards; // Available reward tracks

    Debug.Log($"Battle Pass: {battlePassName}");
    Debug.Log($"Progression Type: {progressionType}");
    Debug.Log($"Total Levels: {levelScores.Length}");
}
const config = battlePassEvent.config;
if (config) {
    const battlePassName = config.name?.value;
    const progressionType = config.type;
    const progressionItem = config.progressionItem; // Item used for scoring
    const levelScores = config.scores; // Score requirements for each level
    const rewardLines = config.rewards; // Available reward tracks

    console.log(`Battle Pass: ${battlePassName}`);
    console.log(`Progression Type: ${progressionType}`);
    console.log(`Total Levels: ${levelScores.length}`);
}

Working with Reward Lines

Battle Pass reward lines represent different tracks (e.g., Free, Premium) that players can progress through:

var rewardLines = config.Rewards;

foreach (var rewardLine in rewardLines)
{
    if (rewardLine != null)
    {
        var lineName = rewardLine.Name;
        var accessItem = rewardLine.AccessItem; // Item required to unlock this track
        var rewards = rewardLine.Rewards; // Rewards for each level

        Debug.Log($"Reward Line: {lineName}");
        Debug.Log($"Access Item: {accessItem?.Name}");
        Debug.Log($"Total Rewards: {rewards.Length}");
    }
}
const rewardLines = config.rewards;

rewardLines.forEach((rewardLine, lineIndex) => {
    if (rewardLine) {
        const lineName = rewardLine.name?.value;
        const accessItem = rewardLine.accessItem; // Item required to unlock this track
        const rewards = rewardLine.rewards; // Rewards for each level

        console.log(`Reward Line: ${lineName}`);
        console.log(`Access Item: ${accessItem?.name?.value}`);
        console.log(`Total Rewards: ${rewards.length}`);
    }
});

Reward Status and Claiming

Each reward line has progress information that tracks availability and claim status:

var progressInfos = battlePassInfo.ProgressInfo;

for (int lineIndex = 0; lineIndex < progressInfos.Count; lineIndex++)
{
    var progressInfo = progressInfos[lineIndex];
    var isTrackAvailable = progressInfo.Available; // Player has access to this track

    // Check each level's reward status
    for (int levelIndex = 0; levelIndex < levelScores.Length; levelIndex++)
    {
        var rewardStatus = progressInfo.GetRewardStatus(levelIndex);

        switch (rewardStatus)
        {
            case Balancy.Data.SmartObjects.BattlePassRewardStatus.NotAvailable:
                Debug.Log($"Level {levelIndex + 1}: Not Available");
                break;
            case Balancy.Data.SmartObjects.BattlePassRewardStatus.Available:
                Debug.Log($"Level {levelIndex + 1}: Ready to Claim!");
                break;
            case Balancy.Data.SmartObjects.BattlePassRewardStatus.Claimed:
                Debug.Log($"Level {levelIndex + 1}: Already Claimed");
                break;
        }
    }
}
const progressInfos = battlePassInfo.progressInfo;

for (let lineIndex = 0; lineIndex < progressInfos.count; lineIndex++) {
    const progressInfo = progressInfos.get(lineIndex);
    const isTrackAvailable = progressInfo.available; // Player has access to this track

    // Check each level's reward status
    for (let levelIndex = 0; levelIndex < levelScores.length; levelIndex++) {
        const rewardStatus = progressInfo.getRewardStatus(levelIndex);

        switch (rewardStatus) {
            case SmartObjectsBattlePassRewardStatus.NotAvailable:
                console.log(`Level ${levelIndex + 1}: Not Available`);
                break;
            case SmartObjectsBattlePassRewardStatus.Available:
                console.log(`Level ${levelIndex + 1}: Ready to Claim!`);
                break;
            case SmartObjectsBattlePassRewardStatus.Claimed:
                console.log(`Level ${levelIndex + 1}: Already Claimed`);
                break;
        }
    }
}

Claiming Rewards

To claim available rewards from the battle pass:

// Claim reward for specific level and reward line
bool claimSuccess = progressInfo.ClaimReward(levelIndex);

if (claimSuccess)
{
    Debug.Log($"Successfully claimed reward for level {levelIndex + 1}!");
}
else
{
    Debug.Log("Failed to claim reward - not available or already claimed");
}
// Claim reward for specific level and reward line
const claimSuccess = progressInfo.claimReward(levelIndex);

if (claimSuccess) {
    console.log(`Successfully claimed reward for level ${levelIndex + 1}!`);
} else {
    console.log("Failed to claim reward - not available or already claimed");
}

Time Management

Battle Pass events have time-based mechanics. Use these methods to check timing:

// Check if battle pass is currently active
bool isActive = battlePassEvent.GetSecondsLeftBeforeDeactivation() > 0;

// Get remaining time
int secondsLeft = battlePassEvent.GetSecondsLeftBeforeDeactivation();

// Get time until activation (if not yet started)
int secondsUntilStart = battlePassEvent.GetSecondsBeforeActivation(false);

Debug.Log($"Active: {isActive}");
Debug.Log($"Time left: {secondsLeft} seconds");
// Check if battle pass is currently active
const isActive = battlePassEvent.getSecondsLeftBeforeDeactivation() > 0;

// Get remaining time
const secondsLeft = battlePassEvent.getSecondsLeftBeforeDeactivation();

// Get time until activation (if not yet started)
const secondsUntilStart = battlePassEvent.getSecondsBeforeActivation(false);

console.log(`Active: ${isActive}`);
console.log(`Time left: ${secondsLeft} seconds`);

Battle Pass Progression Types

Battle Pass supports different progression mechanics:

Progression Type Description
Collect Players earn points by collecting specific items
Spend Players earn points by spending specific items
Custom Custom progression logic defined by your game

Best Practices

  1. Check event timing before displaying battle pass UI
  2. Validate reward status before allowing claim attempts
  3. Handle track access - check if players have access to premium tracks
  4. Subscribe to updates to keep progress synchronized
  5. Provide clear progression feedback showing current level and next level requirements
  6. Display time remaining prominently to create urgency
  7. Handle edge cases like finished battle passes or expired events
  8. Cache battle pass data temporarily but refresh on updates
  9. Implement proper error handling for failed reward claims
  10. Show preview of upcoming rewards to motivate progression

Using these methods, you can create an engaging Battle Pass system that encourages regular player engagement through time-limited, level-based progression with multiple reward tracks.

Daily Bonus

Balancy provides built-in support for Daily Bonuses, allowing developers to configure and manage recurring rewards that players can claim on a daily basis. The system supports various types of daily bonuses, including calendar-based rewards, streak-based rewards, and flexible reset rules.

Accessing Daily Bonuses

To retrieve the list of available Daily Bonuses, use the following method:

var liveOpsInfo = Balancy.Profiles.System.LiveOpsInfo;
var dailyBonuses = liveOpsInfo.DailyBonusInfos;

foreach (var dailyBonusInfo in dailyBonuses)
{
    var bonusConfig = dailyBonusInfo.DailyBonus;
    Debug.Log($"Daily Bonus: {bonusConfig?.Name}");
}
const liveOpsInfo = Balancy.Profiles.system.liveOpsInfo;
const dailyBonuses = liveOpsInfo.dailyBonusInfos;

for (let i = 0; i < dailyBonuses.count; i++) {
    const dailyBonusInfo = dailyBonuses.get(i);
    const bonusConfig = dailyBonusInfo.dailyBonus;
    console.log(`Daily Bonus: ${bonusConfig?.name}`);
}

This returns a collection of DailyBonusInfo objects, each representing a player's progress in a specific daily bonus configuration.

Checking Next Reward Availability

To check when the next reward will be available:

int secondsTillNextReward = dailyBonusInfo.GetSecondsTillTheNextReward();
Debug.Log($"Next reward available in: {secondsTillNextReward} seconds");
const secondsTillNextReward = dailyBonusInfo.getSecondsTillTheNextReward();
console.log(`Next reward available in: ${secondsTillNextReward} seconds`);

If secondsTillNextReward is 0, the player can immediately claim their next reward.

Checking Reward Eligibility

Before claiming a reward, you can check if it's available:

bool canClaim = dailyBonusInfo.CanClaimNextReward();
Debug.Log($"Can claim next reward: {canClaim}");
const canClaim = dailyBonusInfo.canClaimNextReward();
console.log(`Can claim next reward: ${canClaim}`);

Claiming the Next Reward

To claim the next available daily reward:

var result = dailyBonusInfo.ClaimNextReward();
Debug.Log($"Claimed reward: {result}");
const result = dailyBonusInfo.claimNextReward();
console.log("Claimed reward:", result);

After a reward is claimed, the system automatically updates the bonus state.

Listening for Daily Bonus Updates

Since daily bonuses may change dynamically, it's recommended to subscribe to updates:

Balancy.Callbacks.OnDailyBonusUpdated += () =>
{
    Debug.Log("Daily bonus data updated.");
};
const updateCallback = () => {
    console.log("Daily bonus data updated.");
};
const callbackId = Balancy.Callbacks.onDailyBonusUpdated.subscribe(updateCallback);

// Unsubscribe when no longer needed
Balancy.Callbacks.onDailyBonusUpdated.unsubscribe(callbackId);

Daily Bonus Types

Balancy supports four different daily bonus reset behaviors:

Bonus Type Description Use Case
Collect All to Reset The sequence resets only after all rewards are collected Traditional 7-day login bonus
Skip to Reset If the player misses a day, the sequence resets to day 1 Streak-based rewards requiring consistency
Calendar Reset Rewards reset based on calendar cycles (weekly/monthly) Monthly login calendars
Skip to Reset (Current Week) Resets weekly if any reward is skipped Weekly challenges

Checking Bonus Type

var bonusType = dailyBonusInfo.DailyBonus?.Type;

switch (bonusType)
{
    case LiveOpsDailyBonusType.CollectAllToReset:
    Debug.Log("Collect all rewards to reset sequence");
    break;
case LiveOpsDailyBonusType.SkipToReset:
        Debug.Log("Missing a day resets the sequence");
        break;
    case LiveOpsDailyBonusType.CalendarReset:
        Debug.Log("Resets based on calendar schedule");
        break;
    case LiveOpsDailyBonusType.SkipToResetCurrentWeek:
        Debug.Log("Weekly reset if rewards are skipped");
        break;
}
const bonusType = dailyBonusInfo.dailyBonus?.type;

switch (bonusType) {
    case LiveOpsDailyBonusType.CollectAllToReset:
        console.log("Collect all rewards to reset sequence");
        break;
    case LiveOpsDailyBonusType.SkipToReset:
        console.log("Missing a day resets the sequence");
        break;
    case LiveOpsDailyBonusType.CalendarReset:
        console.log("Resets based on calendar schedule");
        break;
    case LiveOpsDailyBonusType.SkipToResetCurrentWeek:
        console.log("Weekly reset if rewards are skipped");
        break;
}

Reward Progression

Checking Current Progress

// Get current progress information
var currentDay = dailyBonusInfo.GetNextRewardNumber();
var rewardsCollected = dailyBonusInfo.DailyRewardCollected;
var lastCollectTime = dailyBonusInfo.DailyRewardCollectTime;

Debug.Log($"Current Day: {currentDay}");
Debug.Log($"Rewards Collected: {rewardsCollected}");
Debug.Log($"Last Collect Time: {lastCollectTime}");
// Get current progress information
const currentDay = dailyBonusInfo.getNextRewardNumber();
const rewardsCollected = dailyBonusInfo.dailyRewardCollected;
const lastCollectTime = dailyBonusInfo.dailyRewardCollectTime;

console.log(`Current Day: ${currentDay}`);
console.log(`Rewards Collected: ${rewardsCollected}`);
console.log(`Last Collect Time: ${lastCollectTime}`);

Working with Rewards

Displaying Available Rewards

var allRewards = dailyBonusInfo.GetAllRewards();

for (int i = 0; i < allRewards.Length; i++)
{
    var reward = allRewards[i];
    var dayNumber = i + 1;
    var isClaimed = dayNumber <= dailyBonusInfo.DailyRewardCollected;

    Debug.Log($"Day {dayNumber} - Claimed: {isClaimed}");

    if (reward?.Items != null)
    {
        foreach (var item in reward.Items)
        {
            Debug.Log($"  - {item?.Item?.Name} x{item?.Count}");
        }
    }
}
const allRewards = dailyBonusInfo.getAllRewards();

allRewards.forEach((reward, index) => {
    const dayNumber = index + 1;
    const isClaimed = dayNumber <= dailyBonusInfo.dailyRewardCollected;

    console.log(`Day ${dayNumber} - Claimed: ${isClaimed}`);

    if (reward?.items) {
        reward.items.forEach(item => {
            console.log(`  - ${item?.item?.name?.value} x${item?.count}`);
        });
    }
});

Getting Next Reward

var nextReward = dailyBonusInfo.GetNextReward();
bool isNextRewardBonus = dailyBonusInfo.IsNextRewardBonus();

if (isNextRewardBonus)
{
    Debug.Log("Next reward is the bonus reward!");
    var bonusReward = dailyBonusInfo.DailyBonus?.BonusReward;
    // Display bonus reward...
}
else if (nextReward != null)
{
    Debug.Log("Next regular reward:");
    foreach (var item in nextReward.Items)
    {
        Debug.Log($"  - {item?.Item?.Name} x{item?.Count}");
    }
}
const nextReward = dailyBonusInfo.getNextReward();
const isNextRewardBonus = dailyBonusInfo.isNextRewardBonus();

if (isNextRewardBonus) {
    console.log("Next reward is the bonus reward!");
    const bonusReward = dailyBonusInfo.dailyBonus?.bonusReward;
    // Display bonus reward...
} else if (nextReward) {
    console.log("Next regular reward:");
    nextReward.items?.forEach(item => {
        console.log(`  - ${item?.item?.name?.value} x${item?.count}`);
    });
}

Using these methods, you can efficiently manage daily login rewards, ensuring a smooth user experience while leveraging Balancy’s automated reward tracking.