@indiegems/gem-web-sdk 23.2.0 → 24.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -0
- package/dist/conformance.d.ts +5 -2
- package/dist/function.d.ts +22 -1
- package/dist/game.d.ts +1590 -1466
- package/dist/gem-web-sdk.bridge.js +2 -2
- package/dist/gem-web-sdk.conformance.js +3 -3
- package/dist/gem-web-sdk.esm.js +3 -3
- package/dist/gem-web-sdk.function.js +3 -3
- package/dist/gem-web-sdk.game.js +3 -3
- package/dist/gem-web-sdk.min.js +3 -3
- package/dist/gem-web-sdk.sdk.js +3 -3
- package/dist/gem-web-sdk.server.js +2 -2
- package/dist/index.d.ts +8 -1
- package/dist/sdk.d.ts +1600 -1464
- package/dist/server.d.ts +44 -1
- package/docs/analytics.md +40 -0
- package/docs/api/api-reference-function.md +196 -45
- package/docs/api/api-reference-game.md +778 -33
- package/docs/api/api-reference-server.md +477 -3
- package/docs/api/reference.json +1833 -102
- package/docs/arcade-and-store.md +166 -61
- package/docs/arcade-economy.md +184 -184
- package/docs/changelog.md +48 -0
- package/docs/deprecation-policy.md +2 -0
- package/docs/getting-started.md +1 -1
- package/docs/inventory-and-catalogs.md +247 -76
- package/docs/manifest.json +24 -24
- package/docs/platform-rules.md +36 -27
- package/docs/player-sign-in.md +60 -3
- package/docs/rewarded-ads.md +32 -1
- package/docs/server-bundles.md +9 -7
- package/docs/what-a-game-must-do.md +7 -4
- package/package.json +1 -1
- package/schema/bridge.v1.json +97 -7
package/docs/arcade-economy.md
CHANGED
|
@@ -1,32 +1,37 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
The arcade runs
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
> **
|
|
7
|
-
|
|
8
|
-
You do not have to use
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
earned elsewhere, or an achievement.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
# Coins and Achievement Points
|
|
2
|
+
|
|
3
|
+
The arcade runs two things across every game, and a player should be able to tell them apart at a
|
|
4
|
+
glance:
|
|
5
|
+
|
|
6
|
+
> **Coins = the arcade's one currency: play earns them, the Arcade sells them, games price in them. Achievement Points = prestige.**
|
|
7
|
+
|
|
8
|
+
You do not have to use either. A game with no platform currency and no achievements is a complete
|
|
9
|
+
game, and the currencies your core loop runs on — gold, XP, energy, materials, cards — are yours to
|
|
10
|
+
design however you like ([inventory-and-catalogs.md](inventory-and-catalogs.md)). Read this page
|
|
11
|
+
before you design a reward a player carries out of your game, a price they pay with something
|
|
12
|
+
earned elsewhere, or an achievement. Most of the rules below are enforced at upload, so a design
|
|
13
|
+
that ignores them is refused rather than shipped.
|
|
14
|
+
|
|
15
|
+
⚠️ **Gems are retiring.** Every player's Gems become Coins on the date the platform announces, and
|
|
16
|
+
nobody loses value. From then on a price in `GEMS` is refused (`422 platform_currency_unavailable`)
|
|
17
|
+
and a Gem grant pays nothing; uploads already warn on `GEMS`. Move now: reprice every Gem price in
|
|
18
|
+
Coins at **5 Coins per Gem**, move each Gem grant to a Coins grant at the rate in
|
|
19
|
+
[§4](#4-earning-needs-server-authority), and take "Gems" out of your copy. Add no new Gem content.
|
|
20
|
+
|
|
21
|
+
## 1. The two, side by side
|
|
22
|
+
|
|
23
|
+
| | **Coins** (`ARCADE_TICKETS`) | **Achievement Points** |
|
|
24
|
+
| ------------------ | ------------------------------------------------------------------------------- | --------------------------------------------------------- |
|
|
25
|
+
| What it is | the arcade's one currency | permanent prestige: the **Achievement Score** |
|
|
26
|
+
| Which games pay it | any game with a server or a serverless function | an achievement, from any game with a server or a function |
|
|
27
|
+
| What it buys | anything a game prices in it, as its spend scope allows (§5) | nothing — it is never spent |
|
|
28
|
+
| Sold for money | **by the Arcade only**, in Coin packs; never by a game | never |
|
|
29
|
+
| Raised by VIP | yes — +50% on every grant, and the caps with it | never |
|
|
30
|
+
| Who may spend it | a player with a full account; a guest earns and keeps, and spends after sign-up | — |
|
|
31
|
+
|
|
32
|
+
A player earns Coins by playing almost anything, may buy more in the Arcade, and spends them in any
|
|
33
|
+
game that prices in them: upgrades, unlocks, extra attempts, characters, cards, skins, outfits,
|
|
34
|
+
effects, emotes. Achievement points are what a player has done, summed across every game into the
|
|
30
35
|
Achievement Score; they are never bought, boosted or spent, and nothing takes them away except the
|
|
31
36
|
platform, for fraud or moderation.
|
|
32
37
|
|
|
@@ -36,44 +41,38 @@ The arcade does not replace your economy. The currencies and resources your core
|
|
|
36
41
|
gold, XP, wood, energy, lives, cards — stay your game's own: defined in your game config, minted and
|
|
37
42
|
priced by you, invisible to every other game. Nothing on this page applies to them.
|
|
38
43
|
|
|
39
|
-
What you map onto
|
|
40
|
-
platform-wide currency of your own:
|
|
44
|
+
What you map onto Coins and achievements is the layer above that loop — the part that would
|
|
45
|
+
otherwise become a platform-wide currency of your own:
|
|
41
46
|
|
|
42
47
|
| If your design has… | Use |
|
|
43
48
|
| ----------------------------------------------------------------------------------------- | --------------------------------------------------------- |
|
|
44
|
-
| a premium or meta currency that speeds up or unlocks progress
|
|
45
|
-
| a cosmetics currency, or a shop of skins | **Coins**: price the cosmetics in `ARCADE_TICKETS` |
|
|
49
|
+
| a premium or meta currency that speeds up or unlocks progress, or buys cosmetics | **Coins**: price it in `ARCADE_TICKETS` |
|
|
46
50
|
| a trophy count, a mastery rank or a completion percentage that says "this player is good" | **achievements**, whose points join the Achievement Score |
|
|
47
51
|
|
|
48
|
-
⚠️ **Do not build a second
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
energy that paces a session, materials a crafting tree consumes.
|
|
52
|
+
⚠️ **Do not build a second Coins.** A game-local premium or meta-currency — "Crystals" that buy your
|
|
53
|
+
upgrades, "Shards" that buy your skins, earned and hoarded the way a player would earn and hoard the
|
|
54
|
+
arcade's — competes with Coins, splits the player between two wallets that mean the same thing, and
|
|
55
|
+
sidesteps every rule on this page: the spend-scope line and the platform's caps. The release review
|
|
56
|
+
checks for one. A currency that is part of play is fine: gold picked up in a level and spent in that
|
|
57
|
+
run's shop, energy that paces a session, materials a crafting tree consumes.
|
|
55
58
|
|
|
56
|
-
|
|
59
|
+
Which platform currencies **your** game may grant or price is the platform's answer, and it can
|
|
60
|
+
change: `gemctl platform config --game <id>` lists them under `platform_grants` and
|
|
61
|
+
`platform_prices`. A mapping onto a currency the platform will not let your game pay is refused at
|
|
62
|
+
upload, and the refusal names the ones it will.
|
|
57
63
|
|
|
58
|
-
|
|
64
|
+
## 3. A game never sells currency for money
|
|
59
65
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
| **Gem Sink** | no | yes | a progression-heavy game: upgrades, characters, cards bought with Gems earned elsewhere |
|
|
65
|
-
| **No-Gem** | no | no | a game that stays out of Gems entirely |
|
|
66
|
+
**Only the Arcade sells Coins.** A Coin pack is the Arcade Store's product, priced, sold and paid
|
|
67
|
+
for in the Arcade's own checkout. Your game may put the Arcade's offers in front of a player from a
|
|
68
|
+
button of its own, through `gem.store` ([arcade-and-store.md](arcade-and-store.md)), and that is
|
|
69
|
+
the whole of its part:
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
Which platform currencies **your** game may grant or price is the platform's answer, and it can
|
|
73
|
-
change: `gemctl platform config --game <id>` lists them under `platform_grants` and
|
|
74
|
-
`platform_prices`, each with a note on what the arcade wants it used for. A mapping onto a currency
|
|
75
|
-
the platform will not let your game pay is refused at upload, and the refusal names the ones it
|
|
76
|
-
will.
|
|
71
|
+
- **No currency for money.** Your game never sells Coins, a game currency or anything that grants
|
|
72
|
+
one for real money, alone or in a bundle.
|
|
73
|
+
- **No top-up screen of your own** ([§8](#8-the-arcade-owns-the-display-of-every-platform-currency)).
|
|
74
|
+
- **Bought and earned Coins spend the same.** Your game cannot tell them apart and prices nothing
|
|
75
|
+
differently for either.
|
|
77
76
|
|
|
78
77
|
## 4. Earning needs server authority
|
|
79
78
|
|
|
@@ -86,13 +85,13 @@ What may move it:
|
|
|
86
85
|
- **Your game server** — a platform-allocated dedicated server, through the progression add and max
|
|
87
86
|
routes.
|
|
88
87
|
- **Your serverless function**, called by the player it pays, on a progression that sets
|
|
89
|
-
`function_may_grant: true`. It may pay
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
`function_may_grant: true`. It may pay Coins and unlock achievements for **that player only**,
|
|
89
|
+
and never for a guest. A function a player calls may also change only that player's own state —
|
|
90
|
+
any write it aims at another player is refused. Opting in makes the function's own checks the
|
|
91
|
+
only thing deciding a reward was earned, so read
|
|
93
92
|
[serverless-functions.md](serverless-functions.md) before you set it.
|
|
94
93
|
- **Never the browser.** A mapped progression cannot be `client_writable`, and nothing else in your
|
|
95
|
-
config — a recipe, a loot-table entry, another progression's reward — may write it.
|
|
94
|
+
config — a recipe, a loot-table entry, another progression's reward, a bonus — may write it.
|
|
96
95
|
|
|
97
96
|
So a browser-only game with neither a server nor a function pays nothing platform-wide. That is the
|
|
98
97
|
rule read strictly, not a gap: a browser credential is public, and anything it could pay, a modified
|
|
@@ -104,156 +103,154 @@ to-dos. A one-time prize, such as finishing the tutorial or a first-time milesto
|
|
|
104
103
|
stays modest. Work the rate out from what each firing pays and how often a player fires it, and keep
|
|
105
104
|
it between 250 and 1,000 an hour: the release review estimates it, and a rate outside that band
|
|
106
105
|
blocks release unless the creator has approved it for that game. The platform's ceilings
|
|
107
|
-
([§6](#6-every-number-is-the-platforms-and-it-moves)) still trim each grant and each day
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
([§6](#6-every-number-is-the-platforms-and-it-moves)) still trim each grant and each day; read them
|
|
107
|
+
from `gemctl platform config`, never from here.
|
|
108
|
+
|
|
109
|
+
**Configure the unboosted figure, and let the platform raise it.** A mapping's `amount` or
|
|
110
|
+
`per_unit` is what a player with no VIP and no Boost earns. The platform applies VIP's +50%, or a
|
|
111
|
+
Boost, itself when it pays ([§7](#7-vip-and-what-a-player-buys-with-money)).
|
|
112
|
+
|
|
113
|
+
**Show a payout with the platform's answer, never your own arithmetic.** Before a claim,
|
|
114
|
+
`gem.gameConfig.preview(target)` says what this player will get, what VIP would add, and which
|
|
115
|
+
bonuses apply; after it, `gem.earnings.fromReceipt(change)` says what they got, in the same shape
|
|
116
|
+
([inventory-and-catalogs.md](inventory-and-catalogs.md#showing-a-payout-before-and-after-preview-and-fromreceipt)).
|
|
117
|
+
⚠️ **Never multiply by `gem.player.boost`, and never copy a config amount into your game's code.**
|
|
118
|
+
Both go wrong the moment the platform retunes a number, and the release review flags hand-written
|
|
119
|
+
multiplier code.
|
|
110
120
|
|
|
111
121
|
**Achievements hold the same line, harder.** An achievement that awards points may not sit on a
|
|
112
|
-
progression anything in your config writes: a recipe priced in
|
|
122
|
+
progression anything in your config writes: a recipe priced in Coins that adds to it would sell the
|
|
113
123
|
achievement. Points are never bought, boosted, spent, decayed or expired, and the platform removes
|
|
114
124
|
them only for fraud or moderation ([achievements.md](achievements.md)).
|
|
115
125
|
|
|
116
|
-
## 5. Spending:
|
|
126
|
+
## 5. Spending: pricing in Coins
|
|
117
127
|
|
|
118
|
-
Any game may sell an item or a recipe for
|
|
119
|
-
|
|
128
|
+
Any game may sell an item or a recipe for Coins, with no server and no approval: the item or recipe
|
|
129
|
+
carries `platform_prices`, and the player pays through the arcade's purchase sheet,
|
|
120
130
|
`gem.purchases.request`
|
|
121
|
-
([inventory-and-catalogs.md](inventory-and-catalogs.md#16-selling-for-a-platform-currency)).
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
- **
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
So while the scope is `cosmetic_only`, a Coins price on an item is always the pair
|
|
135
|
-
`currency: ARCADE_TICKETS` and `category: cosmetic`; on a recipe, every item it grants declares
|
|
136
|
-
`category: cosmetic`. Once it is `any`, a play item may carry a Coins price and keeps
|
|
137
|
-
`category: progression`.
|
|
131
|
+
([inventory-and-catalogs.md](inventory-and-catalogs.md#16-selling-for-a-platform-currency)).
|
|
132
|
+
|
|
133
|
+
- **What Coins may price is their spend scope**, a platform setting. Coins' is `any`, so they may
|
|
134
|
+
price play items and cosmetics alike. The platform owns the scope and can change it; read it in
|
|
135
|
+
`gemctl platform config`, and take it from a refusal rather than from this page.
|
|
136
|
+
- **Spending needs a full account.** The platform refuses a guest's spend with
|
|
137
|
+
`403 guest_upgrade_required`, and the arcade takes the player through sign-up. A guest keeps
|
|
138
|
+
earning, and their Coins carry over when they sign up.
|
|
139
|
+
- **A paid roll is gated.** A recipe priced in Coins that rolls a loot table, or carries a bonus
|
|
140
|
+
that rolls, is a paid random item: the arcade's purchase sheet shows the odds before the player
|
|
141
|
+
pays, and the platform refuses it for a known minor and in restricted regions
|
|
142
|
+
(`paid_chance_restricted`). Show the odds in your own shop too
|
|
143
|
+
([inventory-and-catalogs.md](inventory-and-catalogs.md#12-loot-tables-and-odds)).
|
|
138
144
|
|
|
139
145
|
**How much to charge: 500 Coins is worth about $1.** Price anything in Coins at what it would be
|
|
140
146
|
worth in dollars, times 500: a $1 emote is 500 Coins, a $3 outfit 1,500, a $10 skin 5,000. A play
|
|
141
|
-
item is worth what its counterpart costs in the hit games of its kind. At the
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
it for that game.
|
|
147
|
+
item is worth what its counterpart costs in the hit games of its kind. At the earn rate in
|
|
148
|
+
[§4](#4-earning-needs-server-authority), that is about an hour of play for each dollar. Never show a
|
|
149
|
+
dollar figure beside a Coins price. The release review lists every Coins price with its dollar value
|
|
150
|
+
and hours of play, and a price under 100 or over 10,000 Coins blocks release unless the creator has
|
|
151
|
+
approved it for that game.
|
|
147
152
|
|
|
148
|
-
**`category` defaults to `progression
|
|
149
|
-
|
|
150
|
-
|
|
153
|
+
**`category` still matters.** It defaults to `progression`; mark an item `category: cosmetic` only
|
|
154
|
+
when it changes nothing but how the player looks. The release review checks the label, and the
|
|
155
|
+
platform reads it whenever a currency's scope is `cosmetic_only`.
|
|
151
156
|
|
|
152
157
|
**A cosmetic can still wait for progress.** "Reach level 10 to unlock the dragon skin" is a recipe
|
|
153
|
-
with a
|
|
158
|
+
with a requirement and a Coins price, and the platform refuses a locked player with
|
|
154
159
|
`recipe_locked` before it takes anything ([game-economy-tutorial.md](game-economy-tutorial.md)).
|
|
155
160
|
|
|
156
|
-
**Take the scope from the refusal, not from this page.** The platform owns each currency's scope and
|
|
157
|
-
can change it. A refusal names the scope that applied, and `gemctl platform config` lists which
|
|
158
|
-
currencies your game may price in at all. A scope changed after you published stops the prices it
|
|
159
|
-
no longer admits: the purchase is refused and the price leaves the catalog, with nothing charged.
|
|
160
|
-
|
|
161
161
|
**The arcade sells cosmetics of its own for Coins, and never sells prestige.** Besides your game's
|
|
162
162
|
shop, the arcade has a Coins shop of its own profile cosmetics. Every arcade item is either a
|
|
163
163
|
**shop** item — a cosmetic priced in Coins — or **earned**: a default, a free claim, an achievement
|
|
164
|
-
or Achievement Score reward. An earned item can never be given a price,
|
|
165
|
-
|
|
164
|
+
or Achievement Score reward. An earned item can never be given a price, so what a player shows off
|
|
165
|
+
for what they did cannot be bought.
|
|
166
166
|
|
|
167
167
|
## 6. Every number is the platform's, and it moves
|
|
168
168
|
|
|
169
|
-
Each platform currency carries settings the arcade holds
|
|
170
|
-
|
|
169
|
+
Each platform currency carries settings the arcade holds and can change at any time, without a
|
|
170
|
+
release of this SDK or of your game:
|
|
171
171
|
|
|
172
172
|
- which games may grant it;
|
|
173
173
|
- how much one grant may pay, how much one game may pay one player per window, and how much all
|
|
174
174
|
games together may pay one player per day — the **daily maximum**;
|
|
175
175
|
- the most a player may hold — the **holdings cap**;
|
|
176
176
|
- whether games may price in it, and what it may price;
|
|
177
|
-
- whether a Boost raises it;
|
|
177
|
+
- whether VIP or a Boost raises it;
|
|
178
178
|
- whether the arcade shows it in its header and wallet.
|
|
179
179
|
|
|
180
|
-
**Author against `gemctl platform config`, never against a number you remember.**
|
|
181
|
-
lists every currency a `platform_grants` mapping may target, with its current ceilings, every
|
|
182
|
-
currency a price may name, and a note on when to reach for each. A currency it does not list for a
|
|
183
|
-
site cannot be used there.
|
|
180
|
+
**Author against `gemctl platform config`, never against a number you remember.**
|
|
184
181
|
|
|
185
182
|
Your game declares no cap of its own. You choose only what each firing pays; the ceilings bound it,
|
|
186
183
|
and the order's `platform_grant` entry — `fired`, `clamped` or `suppressed` — is the receipt for what
|
|
187
184
|
landed:
|
|
188
185
|
|
|
189
|
-
- **A ceiling trims; it does not refuse.**
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
186
|
+
- **A ceiling trims; it does not refuse.** A firing that would cross the per-firing cap, the
|
|
187
|
+
per-game cap or the daily maximum pays what is left of it and reads `clamped`; once the day is
|
|
188
|
+
spent it pays 0. When the player reaches the daily maximum, the arcade tells them in its own
|
|
189
|
+
chrome, and that notice is never relayed into your game
|
|
193
190
|
([daily-challenges.md](daily-challenges.md)), though it can read how much more it may pay
|
|
194
191
|
([the earn allowance](inventory-and-catalogs.md#showing-how-much-more-a-player-can-earn)).
|
|
195
192
|
- **The holdings cap is all or nothing.** A grant that would take the player's balance past it pays
|
|
196
193
|
nothing and reads `clamped` with `clamped_by: holdings_cap`. Nothing a player already holds is
|
|
197
194
|
ever taken away.
|
|
198
195
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
## 7.
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
- **It
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
196
|
+
A preview shows the uncapped figure, because the limits are private; the receipt says when a limit
|
|
197
|
+
trimmed the payout, and `gem.earnings.fromReceipt` shows it.
|
|
198
|
+
|
|
199
|
+
## 7. VIP, and what a player buys with money
|
|
200
|
+
|
|
201
|
+
The Arcade Store sells **Coin packs** and **VIP**, a pass. Your game never sells either itself; it
|
|
202
|
+
may open the Arcade's own sheet from a button of its own
|
|
203
|
+
([arcade-and-store.md](arcade-and-store.md)).
|
|
204
|
+
|
|
205
|
+
**VIP is a pass with +50% Coins.** While a player holds it:
|
|
206
|
+
|
|
207
|
+
- **Every Coins grant pays +50%, and the ceilings scale with it**, so the extra stays real at the
|
|
208
|
+
cap. Your game does nothing to apply it: keep `amount` at the unboosted figure. The highest
|
|
209
|
+
multiplier in force wins — a player who also holds an older 2x Boost earns 2x, not 3x — and what
|
|
210
|
+
they earned stays theirs when VIP ends.
|
|
211
|
+
- **It never touches achievement points.**
|
|
212
|
+
- **It can unlock more in your game, through your config.** A recipe or loot table may carry
|
|
213
|
+
`bonuses`, each with a `requires`; `{ kind: 'holds_pass', pass: 'vip' }` is VIP. The platform
|
|
214
|
+
judges it when the recipe runs, and a bonus never fails the base grant
|
|
215
|
+
([inventory-and-catalogs.md](inventory-and-catalogs.md#bonuses-more-for-a-player-who-meets-a-requirement)).
|
|
216
|
+
- **A game can offer it at the moment it matters** — "VIP: +1 roll, 45 Coins" before a chest opens
|
|
217
|
+
— from `gem.gameConfig.preview`'s `upsells`, opened with `gem.store.showPass`. Upsell **before**
|
|
218
|
+
you grant, never after: the platform holds nothing back for later
|
|
219
|
+
([inventory-and-catalogs.md](inventory-and-catalogs.md#offering-vip-before-a-reward-the-upsell)).
|
|
220
|
+
|
|
221
|
+
**The Boost is retired.** No Boost is on sale. A player who holds the 2x Boost keeps it until it
|
|
222
|
+
ends, and `gem.player.boost` still reports it.
|
|
223
|
+
|
|
224
|
+
⚠️ **Gate on the pass, never on the multiplier.** What VIP unlocks is decided by `holds_pass`,
|
|
225
|
+
checked by the platform, or by a pass read on your server or function. `gem.player.boost` shows
|
|
226
|
+
VIP's +50% too, and it is for display only: never make content, difficulty, power, access, prices,
|
|
227
|
+
matchmaking or odds depend on it. The full rule is
|
|
228
|
+
[platform-rules.md](platform-rules.md#8-a-players-boost-is-for-display-never-a-gate).
|
|
228
229
|
|
|
229
230
|
## 8. The arcade owns the display of every platform currency
|
|
230
231
|
|
|
231
|
-
The arcade draws the player's
|
|
232
|
-
|
|
232
|
+
The arcade draws the player's Coins in its own chrome while your game runs, and animates every
|
|
233
|
+
payout into the right total:
|
|
233
234
|
|
|
234
235
|
- **No counter.** Keep no balance, running total or wallet of a platform currency on any screen of
|
|
235
236
|
yours. Read `gem.platform.currencies.get()` to decide whether a price is affordable, never to draw
|
|
236
237
|
a number. A balance can change while your game is paused, so read it again on every
|
|
237
238
|
`onPause(false)` if you keep anything worked out from it, such as a greyed-out Buy button.
|
|
238
|
-
- **No celebration of your own.** At a payout, cue the arcade's wallet with `gem.cueReward`,
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
call, and the reward flies once
|
|
239
|
+
- **No celebration of your own.** At a payout, cue the arcade's wallet with `gem.cueReward`,
|
|
240
|
+
`currencySlug: 'ARCADE_TICKETS'`, from the coin on your reward screen. If it returns `false`, do
|
|
241
|
+
nothing. When your serverless function pays it, pass one `cueId` (a `crypto.randomUUID()`) to
|
|
242
|
+
both the cue and the `gem.functions.invoke` call, and the reward flies once
|
|
243
243
|
([inventory-and-catalogs.md](inventory-and-catalogs.md#showing-the-reward-land-in-the-arcades-wallet)).
|
|
244
244
|
- **No "daily max" of your own making.** Your game cannot see what every other game paid the player,
|
|
245
245
|
and must not compute a maximum. To show how much more your game can pay, read
|
|
246
|
-
`gem.platform.earnAllowance.get()` (
|
|
247
|
-
|
|
248
|
-
- **No top-up or payment screen of your own.** Never draw a "buy Coins" offer, a checkout, a
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
([arcade-and-store.md](arcade-and-store.md)). When a purchase is refused for
|
|
255
|
-
`insufficient_funds`, say so in your shop's own words ("Not enough Coins") and stop there: a
|
|
256
|
-
refusal never opens the store by itself.
|
|
246
|
+
`gem.platform.earnAllowance.get()` (display only); the arcade still tells the player when they
|
|
247
|
+
reach the maximum.
|
|
248
|
+
- **No top-up or payment screen of your own.** Never draw a "buy Coins" offer, a checkout, a wallet
|
|
249
|
+
top-up, or anything shaped like the arcade's purchase sheet. Your shop's own Buy button is yours,
|
|
250
|
+
and so is a "Get Coins" button that calls `gem.store.purchase` with a Coin pack, or a "Get VIP"
|
|
251
|
+
button that calls `gem.store.showPass('vip')`, from the player's press: the checkout each one
|
|
252
|
+
leads to is the Arcade's own. When a purchase is refused for `insufficient_funds`, say so in your
|
|
253
|
+
shop's own words ("Not enough Coins") and stop there: a refusal never opens the store by itself.
|
|
257
254
|
- **No amount at all when you are not connected to the arcade.** Hide every platform price and
|
|
258
255
|
reward unless `gem.awaitBridge()` settled `connected`.
|
|
259
256
|
- **Draw a currency with the art the SDK ships**: the icon beside an amount, the hero only on a
|
|
@@ -264,37 +261,40 @@ never computes the score, restates it, or turns it into a currency of its own.
|
|
|
264
261
|
|
|
265
262
|
## 9. What the arcade does not have
|
|
266
263
|
|
|
267
|
-
- **No Stars, Tokens
|
|
268
|
-
Coins, `ARCADE_TICKETS`).
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
- **No Gems or Coins for money from a game**, alone or in a bundle. Only the arcade's own store
|
|
272
|
-
sells Gems, and nothing sells Coins.
|
|
264
|
+
- **No Gems, once they retire**, and no Stars, Tokens, Supporter Seals or the old `COINS` currency
|
|
265
|
+
(retired; not today's Coins, `ARCADE_TICKETS`). None of them can be granted, priced in or bought:
|
|
266
|
+
a config naming one is refused at upload, and a mapping onto one reads `suppressed`.
|
|
267
|
+
- **No currency for money from a game**, alone or in a bundle. Only the Arcade sells Coins.
|
|
273
268
|
- **No achievement points or earned items for anything a player pays for.**
|
|
274
|
-
- **No content behind a
|
|
269
|
+
- **No content behind a multiplier.** VIP's +50% and a Boost are shown, never checked; content goes
|
|
270
|
+
behind `holds_pass`.
|
|
271
|
+
- **Nothing held for later.** The platform keeps no pending or missed bonus and no voucher: a bonus
|
|
272
|
+
is judged when the recipe runs.
|
|
275
273
|
|
|
276
274
|
## 10. When an upload or a grant is refused
|
|
277
275
|
|
|
278
|
-
| What you get
|
|
279
|
-
|
|
|
280
|
-
| a mapping refused, naming the currencies your game may pay
|
|
281
|
-
|
|
|
282
|
-
| a
|
|
283
|
-
| a
|
|
284
|
-
|
|
|
285
|
-
| `
|
|
286
|
-
| a receipt `
|
|
287
|
-
|
|
|
276
|
+
| What you get | What happened | What to do |
|
|
277
|
+
| ---------------------------------------------------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
278
|
+
| a mapping refused, naming the currencies your game may pay | the platform does not let your game grant that currency | target one it lists — `gemctl platform config` has the current set |
|
|
279
|
+
| an upload warning, or after the cut `422 platform_currency_unavailable`, on `GEMS` | Gems are retiring | reprice in `ARCADE_TICKETS` at 5 Coins per Gem, and move Gem grants to Coins |
|
|
280
|
+
| a receipt `suppressed`, reason `not_allowlisted…` | the platform stopped letting your game grant that currency | target a currency `gemctl platform config` lists; paid balances stay |
|
|
281
|
+
| a price refused, naming a spend scope | the currency's scope does not admit that item | price it in a currency whose scope does, or mark the item `category: cosmetic` only if it changes nothing but looks |
|
|
282
|
+
| `403 guest_upgrade_required` | a guest tried to spend Coins | nothing — the arcade takes them through sign-up |
|
|
283
|
+
| `paid_chance_restricted` | a paid roll for a known minor, or in a restricted region | nothing for the base of a free recipe; a bonus roll is skipped, a paid roll refused |
|
|
284
|
+
| a receipt `suppressed`, reason `functions_not_opted_in` | your function wrote a paying progression that has not opted in | read [serverless-functions.md](serverless-functions.md), then set `function_may_grant: true` |
|
|
285
|
+
| `403 function_foreign_entity_write` | a function a player called wrote another player | take the player from the call's context, never its input |
|
|
286
|
+
| a receipt `clamped` | a ceiling trimmed the payout, or the day was already spent | nothing — show what landed with `gem.earnings.fromReceipt` |
|
|
287
|
+
| a receipt `clamped`, `clamped_by: holdings_cap` | the player already holds as much as they may | nothing — the player spends before they earn more |
|
|
288
288
|
|
|
289
289
|
## What to read next
|
|
290
290
|
|
|
291
|
-
- [`inventory-and-catalogs.md`](inventory-and-catalogs.md) — platform grants (§13) and
|
|
292
|
-
platform currency (§16), in full.
|
|
293
|
-
- [`
|
|
294
|
-
|
|
291
|
+
- [`inventory-and-catalogs.md`](inventory-and-catalogs.md) — platform grants (§13), requirements and
|
|
292
|
+
bonuses (§9), the payout preview and selling for a platform currency (§16), in full.
|
|
293
|
+
- [`arcade-and-store.md`](arcade-and-store.md) — the Arcade Store, `showPass` and the VIP read.
|
|
294
|
+
- [`game-economy-tutorial.md`](game-economy-tutorial.md) — a shop, step by step.
|
|
295
295
|
- [`daily-challenges.md`](daily-challenges.md) — the commonest thing that pays a platform currency.
|
|
296
296
|
- [`achievements.md`](achievements.md) — achievements, their points and the Achievement Score.
|
|
297
297
|
- [`serverless-functions.md`](serverless-functions.md) — paying a player from a game with no
|
|
298
298
|
dedicated server, and what a function a player calls may change.
|
|
299
|
-
- [`platform-rules.md`](platform-rules.md) — the
|
|
299
|
+
- [`platform-rules.md`](platform-rules.md) — gate on the pass, never on the multiplier.
|
|
300
300
|
- [`brand-art.md`](brand-art.md) — the art for every platform currency, and the rules for drawing it.
|
package/docs/changelog.md
CHANGED
|
@@ -16,6 +16,54 @@ Its entries are grouped under up to five headings:
|
|
|
16
16
|
- **Rebuild**: a type changed. Recompile against the new version; code that compiles today keeps compiling unless the entry says otherwise.
|
|
17
17
|
- **New capability**: something a game can now do. Nothing changes unless you use it.
|
|
18
18
|
|
|
19
|
+
## 24.0.0
|
|
20
|
+
|
|
21
|
+
Upgrading from 23.3.0. Impact: required.
|
|
22
|
+
|
|
23
|
+
### Must change
|
|
24
|
+
|
|
25
|
+
- Stop using the store offers call answering sign_in_required as a test for a guest. A current Arcade now answers a guest with ok, because a guest can buy. Use GemPlayer.isGuest instead. It is true only when the Arcade says the player is a guest who can sign up here, and false for a full account, for a surface with no sign-up, and for an older Arcade that does not say. It follows a guest who signs up in place.
|
|
26
|
+
- Check any code that branches on the offer kind. ArcadeOffer.kind is now typed as ArcadeOfferKind, and a pack of a platform currency other than GEMS is reported as coin_pack rather than gem_pack. The gem_pack value is deprecated. Handle coin_pack wherever you handle gem_pack, or such packs will fall through your branches.
|
|
27
|
+
- If your tests run the parent conformance kit against an Arcade host or a stand-in for one, update them for kit version 9. The version constant moved from 8 to 9, there is a new storeScenario member on the parent under test, and there are six new pass cases. Supply a store scenario so those cases can run.
|
|
28
|
+
|
|
29
|
+
### Should change
|
|
30
|
+
|
|
31
|
+
- GamePass.endsAt is deprecated on the browser, function and server halves. An exact end instant is a value two games could match to link one player's identities, so the platform will stop sending it and it will read null. Move to GamePass.daysLeft, which gives whole days remaining, capped at 7. A known guest is answered as not holding the pass. See [the deprecation policy](deprecation-policy.md#4-what-is-deprecated-today).
|
|
32
|
+
|
|
33
|
+
### May stop
|
|
34
|
+
|
|
35
|
+
- If your game works out expected rewards or the effect of a player's boost by hand, you can drop that arithmetic. The config preview now computes the multiplier, platform grants with their rounding, and bonus eligibility for you.
|
|
36
|
+
|
|
37
|
+
### Rebuild
|
|
38
|
+
|
|
39
|
+
- Types changed in two places. The store offers result now allows an optional pass and optional earn multipliers on each offer. The server match object gains playerPasses and playerBoost. Recompiling is enough, unless your code supplies its own stand-in for the match object, which then needs the two new members.
|
|
40
|
+
|
|
41
|
+
### New capability
|
|
42
|
+
|
|
43
|
+
- Offers now say which pass they sell and which earn multipliers they carry. Each ArcadeOffer has an optional pass and optional earnMultipliers, so a game can show what an offer raises before the player buys it.
|
|
44
|
+
- A game can sell a pass by its slug. StoreApi.passOnSale tells you whether the pass is on sale here, and StoreApi.showPass opens its sheet. The ShowPassOutcome it returns is ok only once a fresh read of the player's passes shows the pass held, and otherwise ok or pending as that type describes.
|
|
45
|
+
- A game can preview what a config change would grant before applying it. You pass a config id, never an amount or a pass. The preview works out the player's multiplier, holdings and local offers, and reports grants, platform grants with a breakdown crediting a held pass or Boost, bonuses with eligibility and unmet requirements, and upsells for passes the player could buy. Rolls are reported as a count from a table, never an outcome. Errors and targets have their own types.
|
|
46
|
+
- Earnings can be read from a receipt. The new earnings API turns a receipt's platform grant change into the same platform grant shape the preview uses, from the base amount granted and the boost source. It is available on the browser, on the function half, and on the server and match server. The function half resolves the currency from the invoking player's currencies, while the server half takes a currency id only.
|
|
47
|
+
- A dedicated game server can now read a player's passes and Boost in a match. Use the match player passes read to gate on a pass, using the same GamePass shape as the browser. The match player Boost read returns a MatchPlayerBoost with its multipliers, for display only. Both reads go through optional runtime hooks, host.passes and host.boost, and an image without a hook, or a listen host, is refused by name. A refusal surfaces as an API error that keeps its original code.
|
|
48
|
+
|
|
49
|
+
## 23.3.0
|
|
50
|
+
|
|
51
|
+
*Written from the API facts alone; no summary was generated for this release.*
|
|
52
|
+
|
|
53
|
+
Upgrading from 23.2.0. Impact: required.
|
|
54
|
+
|
|
55
|
+
### Must change
|
|
56
|
+
|
|
57
|
+
- FrameCallbacks.onPlayer changed its signature.
|
|
58
|
+
- FrameOptions.onPlayer changed its signature.
|
|
59
|
+
|
|
60
|
+
### New capability
|
|
61
|
+
|
|
62
|
+
- AccountApi.onSignInAvailableChange was added.
|
|
63
|
+
- AccountApi.signInAvailable was added.
|
|
64
|
+
- GemPlayer.signInAvailable was added.
|
|
65
|
+
- SendPlayerInput.signInAvailable was added.
|
|
66
|
+
|
|
19
67
|
## 23.2.0
|
|
20
68
|
|
|
21
69
|
*Written from the API facts alone; no summary was generated for this release.*
|
|
@@ -100,6 +100,8 @@ deprecated.
|
|
|
100
100
|
| `GemPlayer.displayHandle` | `PlayerIdentity.displayTag` — the same value | `7.0.0` | Package API surface |
|
|
101
101
|
| `GemPlayer.avatarUrl` | `PlayerIdentity.avatarIconUrl` — the same value | `7.0.0` | Package API surface |
|
|
102
102
|
| `AdRequest.format: 'interstitial'` | `gem.moments.signal` — a platform moment at the same break, from the press that leaves it | `14.0.0` | Package API surface |
|
|
103
|
+
| `GamePass.endsAt` | `GamePass.daysLeft` — whole days, capped at 7 | `24.0.0`, for the member | Package API surface, plus runtime delivery |
|
|
104
|
+
| `ArcadeOffer.kind: 'gem_pack'` | `'coin_pack'` — Gems are retired, and Coins are the one platform currency | `24.0.0` | Package API surface |
|
|
103
105
|
| `profile(playerId)` | The room read's per-member display identity | Not a package release | Runtime delivery only |
|
|
104
106
|
|
|
105
107
|
**"For the member" is the split from section 3**, and it is the row's real answer: `4.0.0` is
|