@energy8platform/game-engine 0.34.0 → 0.34.2
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/dist/flow.cjs.js.map +1 -1
- package/dist/flow.d.ts +15 -2
- package/dist/flow.esm.js.map +1 -1
- package/dist/host.cjs.js +63 -3
- package/dist/host.cjs.js.map +1 -1
- package/dist/host.d.ts +5 -0
- package/dist/host.esm.js +63 -3
- package/dist/host.esm.js.map +1 -1
- package/dist/scene-devtools.cjs.js +150 -7
- package/dist/scene-devtools.cjs.js.map +1 -1
- package/dist/scene-devtools.d.ts +59 -3
- package/dist/scene-devtools.esm.js +151 -8
- package/dist/scene-devtools.esm.js.map +1 -1
- package/dist/scene.cjs.js +37 -12
- package/dist/scene.cjs.js.map +1 -1
- package/dist/scene.d.ts +63 -3
- package/dist/scene.esm.js +37 -12
- package/dist/scene.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/host/createSlotGame.ts +33 -2
- package/src/host/shellConfig.ts +47 -2
package/package.json
CHANGED
|
@@ -186,11 +186,23 @@ export async function createSlotGame<T extends SlotSpinResultBase = SlotSpinResu
|
|
|
186
186
|
jurisdiction?: import('./shellConfig').JurisdictionRestrictions;
|
|
187
187
|
betLevels?: number[];
|
|
188
188
|
defaultBet?: number;
|
|
189
|
-
stake?: { defaultBetLevel?: number };
|
|
189
|
+
stake?: { defaultBetLevel?: number; minBet?: number; maxBet?: number };
|
|
190
|
+
/** Set by the Stake bridge when `/wallet/authenticate` returned a still-open round. */
|
|
191
|
+
activeRound?: { bet?: number; roundId?: string; mode?: string };
|
|
190
192
|
};
|
|
193
|
+
/** Present only on a resume — the bridge synthesises it from the open round. */
|
|
194
|
+
session?: { betAmount?: number };
|
|
191
195
|
lang?: string;
|
|
192
196
|
} | null;
|
|
193
197
|
const config = initData?.config;
|
|
198
|
+
// A reload mid-round is just another entry: authenticate answers with BOTH the currency's
|
|
199
|
+
// default bet and the round still open from the previous page-load. That round was played at
|
|
200
|
+
// its own stake, so the default is the wrong bet to come back on — the bar would show it while
|
|
201
|
+
// the resume drain (and the ×bet win data the scene renders) ran against something else.
|
|
202
|
+
// `config.activeRound.bet` is the bridge stating it outright; `session.betAmount` is the older
|
|
203
|
+
// carrier for the same value (INIT only ever has a session on a resume). Both are ignored when
|
|
204
|
+
// absent or 0 so an ordinary launch still starts on the default.
|
|
205
|
+
const resumedBet = config?.activeRound?.bet || initData?.session?.betAmount || undefined;
|
|
194
206
|
const { resolveCurrency } = await import('./shellConfig');
|
|
195
207
|
// SINGLE source of truth for the symbol: the Stake bridge already puts a full CurrencyMetaData
|
|
196
208
|
// (symbol + placement) on initData.config.currency. In the non-stake/devBridge path that meta
|
|
@@ -217,8 +229,21 @@ export async function createSlotGame<T extends SlotSpinResultBase = SlotSpinResu
|
|
|
217
229
|
// Currency-specific ladder + per-currency default from /wallet/authenticate (Stake);
|
|
218
230
|
// absent on dev/devBridge → buildShellConfig falls back to the spec.
|
|
219
231
|
betLevels: config?.betLevels,
|
|
220
|
-
defaultBet: config?.stake?.defaultBetLevel ?? config?.defaultBet,
|
|
232
|
+
defaultBet: resumedBet ?? config?.stake?.defaultBetLevel ?? config?.defaultBet,
|
|
233
|
+
// Hard stake window; the bridge rejects anything outside it before /bet/play.
|
|
234
|
+
minBet: config?.stake?.minBet,
|
|
235
|
+
maxBet: config?.stake?.maxBet,
|
|
221
236
|
};
|
|
237
|
+
// On a real Stake launch the ladder is CURRENCY-SPECIFIC and mandatory. Falling back to the
|
|
238
|
+
// spec's (EUR-shaped) ladder here would put the game on bets the wallet can't honour — every
|
|
239
|
+
// spin rejected on a high-denomination currency (ARS minBet 50), or silently mispriced. Fail
|
|
240
|
+
// where the cause is visible instead of at the first spin.
|
|
241
|
+
if (isStakeNow && !runtime.betLevels?.length) {
|
|
242
|
+
fatal('Could not load the bet levels for your currency. Please relaunch the game.');
|
|
243
|
+
throw new Error(
|
|
244
|
+
'createSlotGame: Stake launch returned no config.betLevels — refusing to fall back to the spec ladder',
|
|
245
|
+
);
|
|
246
|
+
}
|
|
222
247
|
if (opts.dev) {
|
|
223
248
|
// Dev-only diagnostic. Logged as PLAIN STRINGS (not collapsed objects) so the values are
|
|
224
249
|
// readable in the console without expanding. If the shown symbol is a bare code ("EUR")
|
|
@@ -238,6 +263,12 @@ export async function createSlotGame<T extends SlotSpinResultBase = SlotSpinResu
|
|
|
238
263
|
app: game.app,
|
|
239
264
|
parent: game.uiLayer,
|
|
240
265
|
};
|
|
266
|
+
// Adopt the bet the shell is about to display. `currentBet` was seeded from the SPEC above,
|
|
267
|
+
// which is only ever right by accident: the authoritative default is the per-currency one from
|
|
268
|
+
// /wallet/authenticate. The shell re-syncs us on `betChange`, but that fires ONLY when the
|
|
269
|
+
// player moves the bet — so without this the FIRST spin (and any bonus buy before it) plays at
|
|
270
|
+
// the spec's bet while the bar shows the RGS one.
|
|
271
|
+
currentBet = pixiShellCfg.currentBet ?? currentBet;
|
|
241
272
|
// The game may swap in its own shell (a custom renderer over the same core) via shellFactory;
|
|
242
273
|
// default is the built-in Pixi shell. The host drives whichever it gets through the Shell contract.
|
|
243
274
|
shell = (opts.shellFactory ?? createPixiShell)(pixiShellCfg);
|
package/src/host/shellConfig.ts
CHANGED
|
@@ -73,6 +73,40 @@ export interface ShellRuntime {
|
|
|
73
73
|
/** Per-currency default bet from `/wallet/authenticate` (the bridge surfaces it as
|
|
74
74
|
* `config.stake.defaultBetLevel`). Stake requires the selector to start here on every entry. */
|
|
75
75
|
defaultBet?: number;
|
|
76
|
+
/** Hard per-currency stake bounds from `/wallet/authenticate` (`config.stake.minBet/maxBet`,
|
|
77
|
+
* major units). The bridge REJECTS any bet outside them before `/bet/play`, so the resolved
|
|
78
|
+
* default is clamped into this window — see `resolveDefaultBet`. */
|
|
79
|
+
minBet?: number;
|
|
80
|
+
maxBet?: number;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Resolve the bet the game must START on — the single source of truth for BOTH the shell's
|
|
85
|
+
* selector and the host's `currentBet` (they must never disagree; if they do, the player is
|
|
86
|
+
* charged a bet they never chose).
|
|
87
|
+
*
|
|
88
|
+
* The `preferred` bet is the RGS default when there is one, else the spec's. Neither is trusted
|
|
89
|
+
* blindly: the result is always an actual rung of `betLevels`, inside `[minBet, maxBet]`.
|
|
90
|
+
*
|
|
91
|
+
* Why snapping matters beyond the bounds check: the shell's `stepBet()` locates the current bet
|
|
92
|
+
* with `availableBets.indexOf(state.bet)`. An off-ladder default makes that return -1, so the very
|
|
93
|
+
* first +/- press jumps the bet to `availableBets[0]` instead of stepping.
|
|
94
|
+
*/
|
|
95
|
+
export function resolveDefaultBet(
|
|
96
|
+
betLevels: number[],
|
|
97
|
+
preferred: number | undefined,
|
|
98
|
+
bounds?: { minBet?: number; maxBet?: number },
|
|
99
|
+
): number {
|
|
100
|
+
if (!betLevels.length) return preferred ?? 0; // no ladder to snap to — nothing better to offer
|
|
101
|
+
// Drop rungs the RGS would reject outright. If the bounds exclude the WHOLE ladder the data is
|
|
102
|
+
// self-contradictory; keep the ladder rather than hand back a bet that isn't even selectable.
|
|
103
|
+
const inBounds = betLevels.filter(
|
|
104
|
+
(l) => (bounds?.minBet == null || l >= bounds.minBet) && (bounds?.maxBet == null || l <= bounds.maxBet),
|
|
105
|
+
);
|
|
106
|
+
const pool = inBounds.length ? inBounds : betLevels;
|
|
107
|
+
if (preferred == null) return pool[0];
|
|
108
|
+
// Nearest rung; ties go to the cheaper one (`<` keeps the earlier, ascending-ladder entry).
|
|
109
|
+
return pool.reduce((best, l) => (Math.abs(l - preferred) < Math.abs(best - preferred) ? l : best), pool[0]);
|
|
76
110
|
}
|
|
77
111
|
|
|
78
112
|
/** The subset of Stake's jurisdiction flags the shell can enforce via `ShellFeatures`. */
|
|
@@ -389,8 +423,19 @@ export function buildShellConfig(
|
|
|
389
423
|
): Omit<PixiShellConfig, 'app' | 'parent' | 'gameInfo'> & { gameInfo: GameInfoContent } {
|
|
390
424
|
// Prefer the currency-specific ladder from /wallet/authenticate; fall back to the spec (dev/devBridge).
|
|
391
425
|
const betLevels = runtime.betLevels?.length ? runtime.betLevels : model.spec.betLevels;
|
|
392
|
-
// Stake requires the default to come from authenticate on every entry; spec default is the dev
|
|
393
|
-
|
|
426
|
+
// Stake requires the default to come from authenticate on every entry; spec default is the dev
|
|
427
|
+
// fallback. Snapped onto the ladder + clamped to the RGS bounds so the selector and the host's
|
|
428
|
+
// `currentBet` both start on a bet the server will actually accept.
|
|
429
|
+
// EXCEPT in replay: there the bridge reports the replayed round's OWN stake, a historical amount
|
|
430
|
+
// that need not be a rung of today's ladder. Snapping it would misreport what was actually bet.
|
|
431
|
+
const preferredBet = runtime.defaultBet ?? model.spec.defaultBet;
|
|
432
|
+
const defaultBet =
|
|
433
|
+
runtime.mode === 'replay'
|
|
434
|
+
? (preferredBet ?? betLevels[0])
|
|
435
|
+
: resolveDefaultBet(betLevels, preferredBet, {
|
|
436
|
+
minBet: runtime.minBet,
|
|
437
|
+
maxBet: runtime.maxBet,
|
|
438
|
+
});
|
|
394
439
|
// runtime.currency is the resolved CurrencyConfig (derived from initData.config.currency by the
|
|
395
440
|
// host); opts.currency still wins. Fall back to the spec code, then a neutral euro.
|
|
396
441
|
const currency =
|