• Categories
  • Recent
  • Tags
  • Popular
  • Solved
  • Unsolved
  • Users
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (Darkly)
  • No Skin
Collapse
brainCloud Forums
J

JasonL

@JasonL
bitHeads
About
Posts
122
Topics
0
Groups
3
Followers
0
Following
0

Posts

Recent Best Controversial

    Should Redemption Code be used as the recovery record for failed reward fulfillment?
  • J JasonL

    Yes, your current design matches the recommended pattern: Redemption Code is a one-way gate for “has this user consumed this shared code?”, while your claim entity is the authoritative state machine for fulfillment, retries, and audit (Redeeming → Redeemed → Granting → Granted / GrantFailed), with Granted as the idempotency guard for duplicate grants. The main thing to watch is call ordering: it’s preferable to write the claim to Redeeming first as an intent record, then call redeemCode(), so any Redeeming with no further progress is detectable and recoverable by your server without depending on the Redemption Code record.

    Consolidating the brainCloud-side claim init + redemption into a single CloudCode script is a good fit, provided the script is strictly idempotent and fulfillment stays in your server pipeline. The script should read the claim state, upsert to Redeeming if needed, call redeemCode() (skipping if already Redeemed or beyond), update the claim to Redeemed, and return rich state (claimState, claimId, rewardDataId) so your server can then perform fulfillment and issue a final Granted / GrantFailed update. This gives you a clean two-call pattern from the server to brainCloud on the happy path, while the script’s state checks make retries safe even though CloudCode itself is not transactional.


  • Should Redemption Code be used as the recovery record for failed reward fulfillment?
  • J JasonL

    For a shared/multi-use Redemption Code, a specific user’s redeemed record can only be reset or deleted through the tester-only deleteRedemptionForTester() flow, so there is no supported production operator/API path for non-tester accounts, and the tester reset should be treated as a QA/dev tool rather than a live recovery mechanism.

    If reward fulfillment fails after redemption, it does not provide an automatic recovery or re-execution path that restores the same user’s redemption state in production; synchronous failures record a failed attempt, async flows can end in Failed on timeout, and any retry is only possible if the code type’s maxRetries still allows another user-initiated redeemCode() attempt.

    customRedemptionInfo can be used as a persistent per-user audit field if your fulfillment script writes it back, since it stores the script response on the user’s code record. However, it is not designed to be updated later through a direct external API after the fact.

    The tester reset is explicitly intended for testing/cleanup only, not as a production recovery operation.

    For production operational rewards, the safest pattern is a shared Redemption Code for claim detection, plus a separate Custom Entity for the fulfillment state, which provides auditable handling of pending/fulfilled/failed/retrying without relying on the Redemption Code record as the source of truth.


  • Questions about brainCloud Friends and Social Leaderboard behavior
  • J JasonL

    Hi @gyutaelee,

    Thanks for the follow-ups. Here are answers to your three new questions:

    A1: Right now, pagination for GetSocialLeaderboard (or other social leaderboard APIs) is not supported, and adding it would be a non-trivial server-side change, not a quick configuration tweak. It’s something we’d like to improve, but it’s not on the short-term roadmap at the moment.

    A2: Raising maxMultipleLeaderboardScoreLimit to 100
    The maxMultipleLeaderboardScoreLimit value is configurable on a per-app basis, with a default of 10. We do try to keep this value low because GetMultiSocialLeaderboard is quite expensive on the server, but for your use case we should be able to bump it to 20 for your app so you can safely call GetMultiSocialLeaderboard([leaderboardId], 20, replaceName). We’re not normally bumping this limit to 100, but 20 is reasonable. If you’d like us to do that, just let us know your appId and we can review and apply the change.

    A3: Getting only the current player’s rank/score in their friends leaderboard**
    There’s no dedicated API currently that returns just “my rank among my friends” in a single call. However, you can get both the top list and your “my rank” context in one call using GetMultiSocialLeaderboard with a single leaderboardId and a leaderboardResultCount set to your truncated top‑N (e.g., 50 or 20). The response includes a selfIndex field computed server-side:

    • If the current player is inside the top‑N, selfIndex is their rank (0-based).
    • If the current player is outside the top‑N, selfIndex is -1, and you can show something like “Your rank: > N” in the UI.

  • Segment Code Bug Report
  • J JasonL

    All fields are editable during the cloning step, and the Code field is also editable there. I’m not sure why it’s looking like the Code field isn’t editable for you, it should work the same whether it’s under or over the 12‑character limit.


  • Question about CloudCode API Hook and Global Property read costs / usage count
  • J JasonL

    Hi @gyutaelee,

    Thanks for the follow-up. Based on the current behavior, the “first 2 API calls are free” allowance is applied across the whole request chain, not separately for the Pre-hook and the original CloudCode script. In other words, internal bridge.callAPI() usage from both executions shares the same allowance for that request/session.

    So if the Pre-hook makes 1 internal API call and the original script makes 3 more, the first 2 total internal calls are free, and the remaining 2 are billed according to the normal post-free rate.

    For your current version-gate use case, this does not change anything because bridge.getGlobalProperty() is not counted as an API call. But if either the Pre-hook or the original script starts using bridge.callAPI() later, the calls will pool under the same request-level allowance.


  • Question about CloudCode API Hook and Global Property read costs / usage count
  • J JasonL

    Hi @gyutaelee ,

    Based on the current brainCloud's implementation, here are the answers to your questions:

    Q1: Does the Pre-hook count as a separate CloudCode execution / API count?**

    Yes. The Pre-hook counts as both a separate API call and a separate CloudCode script invocation. After running, the server publishes its own analytics event with operation "RUN_HOOK-Pre_VersionGate" that increments both counts.

    Q2: Does bridge.getGlobalProperty() count as an API call?**

    No. bridge.getGlobalProperty() is completely free. It reads directly from the cached Game object in memory and bypasses the API call tracking pipeline entirely.

    Q3: Does the "first 3 free, then 0.5 each" rule apply to hook CloudCode scripts?**

    Yes, the discount applies to internal calls from any script or hook within the session.

    Q4: Pass-through case: usage count breakdown

    • Client calls script.RUN: +1 API call
    • Pre-hook executes: +1 API call
    • bridge.getGlobalProperty() inside hook: free
    • Original CloudCode script: +0 (covered by the original script.RUN request)

    Total external API count: 2

    Q5: Blocked case: usage count breakdown

    • Client calls script.RUN: +1 API call
    • Pre-hook executes: +1 API call
    • bridge.getGlobalProperty() inside hook: 0 (free)
    • Original script: +0 (does not run, server throws before invoking it when hook returns non-200)

    Total external API count: 2

    The blocked case costs the same as pass-through from an API-count perspective. The only savings is that the original script's internal bridge.callAPI() calls are avoided.

    Q6: Could reading a Global Property on every script.RUN become a performance or cost concern?

    Performance: No. getGlobalProperty() reads from an in-memory cached Game object (ConcurrentHashMap per node) with no DB query or network call.

    Cost: The hook itself adds +1 API count to every script.RUN call that has the hook attached.

    Q7: Recommended caching approach for frequently-read, rarely-changed property?

    The cache is already in place, no additional caching needed. brainCloud stores the Game object (including all global properties) in an in-memory cache for each server node. Cross-node invalidation is handled automatically when a global property is updated in the portal. Using bridge.getGlobalProperty() is already the optimal pattern.

    Q8: Portal metrics: what can be broken down separately?

    • API Hook execution count: Partially available. Hooks appear within the CC script invocation counter; no hook-only counter exists.
    • CloudCode script execution count: Available as CC Script Invocations, but includes hooks in the same counter.
    • CloudCode internal API call count: Available as CC API Calls in the Monitoring dashboard.
    • Global Property read count: Not tracked. No metric exists for this.

  • Segment Code Bug Report
  • J JasonL

    Hi @LEE-JONG-GUN,

    Good news: the fix for the Segment code field clone bug has been deployed.

    What changed

    • When you clone a Segment now, the code field is automatically appended with _copy (e.g., myCode becomes myCode_copy).
    • The cloned segment's code field is editable, so you can change it to any unique value and save the clone successfully.

    This resolves the duplicate-code issue that was preventing clones from being saved. Thanks again for the report.


  • Segment Code Bug Report
  • J JasonL

    Good catch! Thanks for bringing this to our attention. We’ll fix it so that cloning a segment doesn’t copy and inactivate the code field, avoiding the duplicate-code issue and allowing the clone to be saved.


  • Integration with .NET server
  • J JasonL

    The SDK is just a plain C# source library you can drop into any .NET project (not Unity-only). You can find usage examples and the source in our GitHub repositories at https://github.com/getbraincloud.


  • Question about using unique indexes for Custom Entities
  • J JasonL

    Hi @gyutaelee, have you tried calling the sysListIndexes method from the API Explorer to verify the index, as mentioned earlier? The Portal’s Custom Indexes UI may not always reflect the underlying MongoDB index options correctly for manually adjusted indexes like unique, so sysListIndexes is the more reliable way to confirm what’s actually on the collection. So run CustomEntity > SysListIndexes in API Explorer and check the returned index list for followerId_followingId and its unique flag.


  • Question about using unique indexes for Custom Entities
  • J JasonL

    Hi @gyutaelee, thanks for the detailed request. We will add a unique compound index for your FOLLOW Custom Entity.

    About Your Questions:

    1. Will this unique index auto-deploy to Staging/Production?
      No. Because brainCloud's API blocks unique indexes at the code level (to prevent sharding issues), the deployer does not know about manually added indexes.

    2. Does this need to be applied per app/environment manually?
      Yes. Each brainCloud app (Dev/Staging/Prod) is a separate appId with its own physical MongoDB collection.

    3. Can we provide appIds for Dev/Staging/Prod so you can add the index to each?
      Yes, absolutely. Please reply with the App IDs for your Staging and Production environments. Once we have them, we'll apply the same unique index to all three environments.

    4. Are manually added Custom Entity indexes included in deploy/migrate/export-import workflows?
      No. The deploy pipeline is config-driven. Any index added directly via MongoDB (outside the Portal/API) is invisible to ImportExportService.

    5. If there are existing duplicate rows, will unique index creation fail?
      Yes. MongoDB returns duplicate key error and aborts the entire index build. Since you mentioned the feature isn't in production yet, you can safely reset/clean up FOLLOW data before we apply the index to avoid this. We may need to check for duplicates first.

    6. Is there expected downtime, lock, write failure, or performance impact?
      No hard downtime Index builds are non-blocking: reads and writes continue during the build.

    7. How to verify the unique index exists after application?
      You can verify it from the Indexes tab of app/design/cloud-data/custom-entities/FOLLOW from portal, or call the method sysListIndexes() via API Explorer.


  • Questions about brainCloud Friends and Social Leaderboard behavior
  • J JasonL

    Hi @gyutaelee ,

    Thanks for the detailed questions.

    1. Friend Relationship Direction - Yes, bidirectional

    • AddFriends: When user A calls AddFriends([B]), both A and B see each other in ListFriends("brainCloud")
    • Both A and B will appear in each other's GetSocialLeaderboard results (if they have scores)
    • RemoveFriends: Removes the relationship from both users atomically

    2. Idempotency - Yes, both are idempotent

    • Calling AddFriends([B]) when already friends: No-op, no error thrown (skips DB write)
    • Calling RemoveFriends([B]) when not friends: No-op, no error thrown

    3. Consistency and Caching - Immediate

    • Friend changes are persisted immediately to the database (no write-behind caching)
    • ListFriends("brainCloud") and GetSocialLeaderboard reflect changes immediately after AddFriends/RemoveFriends
    • No eventual consistency or caching delay

    4. Friend Count Limits - No hard cap

    • No code-enforced limit on brainCloud friends per user
    • Practical consideration: Friend IDs stored as array on UserProfile; very large arrays (>10K) may impact read/write performance

    5. GetSocialLeaderboard Behavior - Returns all friends + self + pacers, no limit

    • Returns all recognized friends + self + pacers
    • No hidden maximum result count
    • Pacers are included (if leaderboard has pacers configured)
    • Warning: Response payload grows linearly with friend count

    6. Recommended API for Top-N - Yes, use GetMultiSocialLeaderboard

    • GetMultiSocialLeaderboard with a single leaderboard ID is a correct approach for top-N results
    • leaderboardResultCount is applied after social filtering and score sorting
    • leaderboardResultCount is capped by maxMultipleLeaderboardScoreLimit app property (default 10, can be raised in app-basis)
    • Preferred over GetSocialLeaderboard for top-N because it has built-in truncation

    7. Social Leaderboard Pagination - Not supported

    • No GetSocialLeaderboardPage API exists (only GetGlobalLeaderboardPage for global leaderboards)
    • Social leaderboards always return the full friend set (potentially truncated by leaderboardResultCount only in the multi variant)
    • I will forward your pagination request for team review

    8. Billing and API Counts - 1 API call per request

    • GetSocialLeaderboard = 1 API call regardless of friends/entries returned
    • GetMultiSocialLeaderboard = 1 API call even with multiple leaderboards
    • AddFriends/RemoveFriends = 1 API call even though they modify both users' profiles

    9. Recommended Usage - Yes, your design aligns perfectly


  • Question about using unique indexes for Custom Entities
  • J JasonL

    Hi @gyutaelee,
    Currently, brainCloud blocks unique indexes on all custom collections as a blanket safeguard. The check happens unconditionally before the system even evaluates whether your collection is owned or sharded, so it rejects the unique option with that error.

    We can manually add the unique index for your FOLLOW collection on our end. Please send us a request with:

    1. Your appId
    2. The entityType (is it FOLLOW only?)
    3. The field name(s) that need uniqueness
    4. The desired index name (e.g., test_index)

    Once we receive your request, we'll add the uniqueness constraint for you directly.


  • Admin Billing API request
  • J JasonL

    I’ll forward your request to the team for review...


  • Automated Promotion not associated for users already in target segment
  • J JasonL

    Yes, the behavior you’re describing is expected with the current implementation. RefreshMySegments, RefreshPromotions, and login will not attach the promotion to users who are already in the segment, because the system is designed to only grant automated promotions when the user enters the segment (i.e., when it shows up in enteredIds). The fact that Reset Segments or Re‑evaluate All Segments fixes it is also expected, because those actions force the user back through the segment‑entry logic.

    We’re working on a fix to make this smoother. The practical effect going forward will be that, when a new automated promotion is created or attached to an existing segment, the next segment refresh will automatically apply it to all currently‑eligible users in the background, without you needing to reset or re‑evaluate segments manually. This should make the behavior more predictable, especially when you have a large number of existing users already in that segment.


  • Question about timing for newly deployed Automated Promotions
  • J JasonL

    Our automated promotions were designed to pull members of a segment into a promotion, which is why they can trigger notifications. When an automated promotion fires for a user, they can be notified, and that notification is intended to draw them back into the game. So startTime is effectively the wall‑clock time when the batch job processes that user, not when the user logs in. A user who never logs in will have their promotion silently expire in the background.

    I’ve forwarded your request to our team to see if we can look at adding a flag that lets developers specify that an automated promotion should only trigger on login, which would likely align well with the kind of “starter‑package” use case you described.


  • [Feature Request] Add "Open in New Window" option for Owner ID in Custom Entity view
  • J JasonL

    Thanks for the suggestion and the explanation of the workflow benefit. I’ll bring this request to our team for review and follow up here...


  • New users are never counted — all users appear as Returning Users after launch
  • J JasonL

    @noah The team is working on this, and we’ll share any progress here once there’s something concrete to report.


  • Feature Request / Question: Selective Promotion Exclusion During App Deployment
  • J JasonL

    Hi, thanks for the detailed report. At the moment, there isn’t a per-promotion exclusion toggle for deployments; the currently recommended way is to keep Preserve Products+Pricing & Promotions in the target environment. Your request for selective promotion exclusion makes sense. I’ll pass this along as a feature request for the team to consider.


  • Two Questions: Follow System & Referral Rewards
  • J JasonL

    Hi @gyutaelee,

    1. For one-way follow: brainCloud doesn’t have a built-in one-way “follow” graph, so you’ll need to implement your own follower/following system using one of the user data mechanisms (e.g. global or entity data) to track who follows whom. This keeps it independent of the Friends API, which is designed around mutual relationships. GetPresenceOfUsers() works with any valid profile IDs, it does not require a Friend relationship between the players to return presence info.

    2. For the referral rewards question: I’m going to forward this to our team to review the best server-side approach for triggering rewards for both the referrer and referee once the milestone (like reaching level 3) is reached.

    Thanks for the detailed explanation of your use cases.

  • Login

  • Login or register to search.
  • First post
    Last post
0
  • Categories
  • Recent
  • Tags
  • Popular
  • Solved
  • Unsolved
  • Users