@energy8platform/game-engine 0.7.0 → 0.8.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/README.md +10 -2
- package/dist/core.cjs.js +22 -6
- package/dist/core.cjs.js.map +1 -1
- package/dist/core.d.ts +6 -1
- package/dist/core.esm.js +22 -6
- package/dist/core.esm.js.map +1 -1
- package/dist/debug.cjs.js +3 -2
- package/dist/debug.cjs.js.map +1 -1
- package/dist/debug.esm.js +3 -2
- package/dist/debug.esm.js.map +1 -1
- package/dist/index.cjs.js +49 -16
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +9 -3
- package/dist/index.esm.js +34 -16
- package/dist/index.esm.js.map +1 -1
- package/package.json +2 -2
- package/src/core/GameApplication.ts +4 -0
- package/src/core/SceneManager.ts +20 -6
- package/src/debug/DevBridge.ts +6 -4
- package/src/index.ts +13 -0
- package/src/state/StateMachine.ts +11 -8
- package/src/types.ts +12 -0
package/dist/index.esm.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Ticker, Assets, Container, Text, Application, AnimatedSprite, Texture, Graphics, NineSliceSprite } from 'pixi.js';
|
|
2
2
|
import { CasinoGameSDK, Bridge } from '@energy8platform/game-sdk';
|
|
3
|
+
export { BridgeDestroyedError, BridgeNotReadyError, SDKError, TimeoutError } from '@energy8platform/game-sdk';
|
|
3
4
|
import { FancyButton, ProgressBar as ProgressBar$1, ScrollBox } from '@pixi/ui';
|
|
4
5
|
import { LayoutContainer } from '@pixi/layout/components';
|
|
5
6
|
|
|
@@ -362,11 +363,12 @@ class Tween {
|
|
|
362
363
|
* ```
|
|
363
364
|
*/
|
|
364
365
|
class SceneManager extends EventEmitter {
|
|
366
|
+
static MAX_TRANSITION_DEPTH = 10;
|
|
365
367
|
/** Root container that scenes are added to */
|
|
366
368
|
root;
|
|
367
369
|
registry = new Map();
|
|
368
370
|
stack = [];
|
|
369
|
-
|
|
371
|
+
_transitionDepth = 0;
|
|
370
372
|
/** Current viewport dimensions — set by ViewportManager */
|
|
371
373
|
_width = 0;
|
|
372
374
|
_height = 0;
|
|
@@ -394,12 +396,15 @@ class SceneManager extends EventEmitter {
|
|
|
394
396
|
}
|
|
395
397
|
/** Whether a scene transition is in progress */
|
|
396
398
|
get isTransitioning() {
|
|
397
|
-
return this.
|
|
399
|
+
return this._transitionDepth > 0;
|
|
398
400
|
}
|
|
399
401
|
/**
|
|
400
402
|
* Navigate to a scene, replacing the entire stack.
|
|
401
403
|
*/
|
|
402
404
|
async goto(key, data, transition) {
|
|
405
|
+
if (this._transitionDepth >= SceneManager.MAX_TRANSITION_DEPTH) {
|
|
406
|
+
throw new Error('[SceneManager] Max transition depth exceeded — possible infinite loop');
|
|
407
|
+
}
|
|
403
408
|
const prevKey = this.currentKey;
|
|
404
409
|
// Exit all current scenes
|
|
405
410
|
while (this.stack.length > 0) {
|
|
@@ -414,6 +419,9 @@ class SceneManager extends EventEmitter {
|
|
|
414
419
|
* Useful for overlays, modals, pause screens.
|
|
415
420
|
*/
|
|
416
421
|
async push(key, data, transition) {
|
|
422
|
+
if (this._transitionDepth >= SceneManager.MAX_TRANSITION_DEPTH) {
|
|
423
|
+
throw new Error('[SceneManager] Max transition depth exceeded — possible infinite loop');
|
|
424
|
+
}
|
|
417
425
|
const prevKey = this.currentKey;
|
|
418
426
|
await this.pushInternal(key, data, transition);
|
|
419
427
|
this.emit('change', { from: prevKey, to: key });
|
|
@@ -426,6 +434,9 @@ class SceneManager extends EventEmitter {
|
|
|
426
434
|
console.warn('[SceneManager] Cannot pop the last scene');
|
|
427
435
|
return;
|
|
428
436
|
}
|
|
437
|
+
if (this._transitionDepth >= SceneManager.MAX_TRANSITION_DEPTH) {
|
|
438
|
+
throw new Error('[SceneManager] Max transition depth exceeded — possible infinite loop');
|
|
439
|
+
}
|
|
429
440
|
const prevKey = this.currentKey;
|
|
430
441
|
await this.popInternal(true, transition);
|
|
431
442
|
this.emit('change', { from: prevKey, to: this.currentKey });
|
|
@@ -434,6 +445,9 @@ class SceneManager extends EventEmitter {
|
|
|
434
445
|
* Replace the top scene with a new one.
|
|
435
446
|
*/
|
|
436
447
|
async replace(key, data, transition) {
|
|
448
|
+
if (this._transitionDepth >= SceneManager.MAX_TRANSITION_DEPTH) {
|
|
449
|
+
throw new Error('[SceneManager] Max transition depth exceeded — possible infinite loop');
|
|
450
|
+
}
|
|
437
451
|
const prevKey = this.currentKey;
|
|
438
452
|
await this.popInternal(false);
|
|
439
453
|
await this.pushInternal(key, data, transition);
|
|
@@ -478,7 +492,7 @@ class SceneManager extends EventEmitter {
|
|
|
478
492
|
return new Ctor();
|
|
479
493
|
}
|
|
480
494
|
async pushInternal(key, data, transition) {
|
|
481
|
-
this.
|
|
495
|
+
this._transitionDepth++;
|
|
482
496
|
const scene = this.createScene(key);
|
|
483
497
|
this.root.addChild(scene.container);
|
|
484
498
|
// Set initial size
|
|
@@ -490,20 +504,20 @@ class SceneManager extends EventEmitter {
|
|
|
490
504
|
// Push to stack BEFORE onEnter so currentKey is correct during initialization
|
|
491
505
|
this.stack.push({ scene, key });
|
|
492
506
|
await scene.onEnter?.(data);
|
|
493
|
-
this.
|
|
507
|
+
this._transitionDepth--;
|
|
494
508
|
}
|
|
495
509
|
async popInternal(showTransition, transition) {
|
|
496
510
|
const entry = this.stack.pop();
|
|
497
511
|
if (!entry)
|
|
498
512
|
return;
|
|
499
|
-
this.
|
|
513
|
+
this._transitionDepth++;
|
|
500
514
|
await entry.scene.onExit?.();
|
|
501
515
|
if (showTransition) {
|
|
502
516
|
await this.transitionOut(entry.scene.container, transition);
|
|
503
517
|
}
|
|
504
518
|
entry.scene.onDestroy?.();
|
|
505
519
|
entry.scene.container.destroy({ children: true });
|
|
506
|
-
this.
|
|
520
|
+
this._transitionDepth--;
|
|
507
521
|
}
|
|
508
522
|
async transitionIn(container, config) {
|
|
509
523
|
const type = config?.type ?? TransitionType.NONE;
|
|
@@ -2205,6 +2219,9 @@ class GameApplication extends EventEmitter {
|
|
|
2205
2219
|
this.sdk.on('error', (err) => {
|
|
2206
2220
|
this.emit('error', err);
|
|
2207
2221
|
});
|
|
2222
|
+
this.sdk.on('balanceUpdate', (data) => {
|
|
2223
|
+
this.emit('balanceUpdate', data);
|
|
2224
|
+
});
|
|
2208
2225
|
}
|
|
2209
2226
|
applySDKConfig() {
|
|
2210
2227
|
// If SDK provides viewport dimensions, use them as design reference
|
|
@@ -2318,10 +2335,11 @@ class GameApplication extends EventEmitter {
|
|
|
2318
2335
|
* ```
|
|
2319
2336
|
*/
|
|
2320
2337
|
class StateMachine extends EventEmitter {
|
|
2338
|
+
static MAX_TRANSITION_DEPTH = 10;
|
|
2321
2339
|
_states = new Map();
|
|
2322
2340
|
_guards = new Map();
|
|
2323
2341
|
_current = null;
|
|
2324
|
-
|
|
2342
|
+
_transitionDepth = 0;
|
|
2325
2343
|
_context;
|
|
2326
2344
|
constructor(context) {
|
|
2327
2345
|
super();
|
|
@@ -2333,7 +2351,7 @@ class StateMachine extends EventEmitter {
|
|
|
2333
2351
|
}
|
|
2334
2352
|
/** Whether a transition is in progress */
|
|
2335
2353
|
get isTransitioning() {
|
|
2336
|
-
return this.
|
|
2354
|
+
return this._transitionDepth > 0;
|
|
2337
2355
|
}
|
|
2338
2356
|
/** State machine context (shared data) */
|
|
2339
2357
|
get context() {
|
|
@@ -2381,9 +2399,8 @@ class StateMachine extends EventEmitter {
|
|
|
2381
2399
|
* @returns true if the transition succeeded, false if blocked by a guard
|
|
2382
2400
|
*/
|
|
2383
2401
|
async transition(to, data) {
|
|
2384
|
-
if (this.
|
|
2385
|
-
|
|
2386
|
-
return false;
|
|
2402
|
+
if (this._transitionDepth >= StateMachine.MAX_TRANSITION_DEPTH) {
|
|
2403
|
+
throw new Error('[StateMachine] Max transition depth exceeded — possible infinite loop');
|
|
2387
2404
|
}
|
|
2388
2405
|
const from = this._current;
|
|
2389
2406
|
// Check guard
|
|
@@ -2398,7 +2415,7 @@ class StateMachine extends EventEmitter {
|
|
|
2398
2415
|
if (!toState) {
|
|
2399
2416
|
throw new Error(`[StateMachine] State "${to}" not registered.`);
|
|
2400
2417
|
}
|
|
2401
|
-
this.
|
|
2418
|
+
this._transitionDepth++;
|
|
2402
2419
|
try {
|
|
2403
2420
|
// Exit current state
|
|
2404
2421
|
if (from !== null) {
|
|
@@ -2415,7 +2432,7 @@ class StateMachine extends EventEmitter {
|
|
|
2415
2432
|
throw err;
|
|
2416
2433
|
}
|
|
2417
2434
|
finally {
|
|
2418
|
-
this.
|
|
2435
|
+
this._transitionDepth--;
|
|
2419
2436
|
}
|
|
2420
2437
|
return true;
|
|
2421
2438
|
}
|
|
@@ -2456,7 +2473,7 @@ class StateMachine extends EventEmitter {
|
|
|
2456
2473
|
await state?.exit?.(this._context);
|
|
2457
2474
|
}
|
|
2458
2475
|
this._current = null;
|
|
2459
|
-
this.
|
|
2476
|
+
this._transitionDepth = 0;
|
|
2460
2477
|
}
|
|
2461
2478
|
/**
|
|
2462
2479
|
* Destroy the state machine.
|
|
@@ -4071,7 +4088,8 @@ class DevBridge {
|
|
|
4071
4088
|
nextActions: customResult.nextActions ?? ['spin'],
|
|
4072
4089
|
session: customResult.session ?? null,
|
|
4073
4090
|
creditPending: false,
|
|
4074
|
-
|
|
4091
|
+
bonusFreeSpin: customResult.bonusFreeSpin ?? null,
|
|
4092
|
+
currency: this._config.currency,
|
|
4075
4093
|
gameId: this._config.gameConfig?.id ?? 'dev-game',
|
|
4076
4094
|
};
|
|
4077
4095
|
this.delayedSend('PLAY_RESULT', result, id);
|
|
@@ -4085,7 +4103,7 @@ class DevBridge {
|
|
|
4085
4103
|
this.delayedSend('BALANCE_UPDATE', { balance: this._balance }, id);
|
|
4086
4104
|
}
|
|
4087
4105
|
handleGetState(id) {
|
|
4088
|
-
this.delayedSend('STATE_RESPONSE', this._config.session, id);
|
|
4106
|
+
this.delayedSend('STATE_RESPONSE', { session: this._config.session ?? null }, id);
|
|
4089
4107
|
}
|
|
4090
4108
|
handleOpenDeposit() {
|
|
4091
4109
|
if (this._config.debug) {
|