@energy8platform/game-engine 0.7.1 → 0.9.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 +178 -68
- package/dist/core.cjs.js +31 -7
- package/dist/core.cjs.js.map +1 -1
- package/dist/core.d.ts +8 -1
- package/dist/core.esm.js +31 -7
- package/dist/core.esm.js.map +1 -1
- package/dist/index.cjs.js +39 -15
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +10 -2
- package/dist/index.esm.js +39 -15
- package/dist/index.esm.js.map +1 -1
- package/dist/react.cjs.js +470 -0
- package/dist/react.cjs.js.map +1 -0
- package/dist/react.d.ts +871 -0
- package/dist/react.esm.js +455 -0
- package/dist/react.esm.js.map +1 -0
- package/dist/vite.cjs.js +5 -0
- package/dist/vite.cjs.js.map +1 -1
- package/dist/vite.esm.js +5 -0
- package/dist/vite.esm.js.map +1 -1
- package/package.json +25 -3
- package/src/core/GameApplication.ts +1 -0
- package/src/core/SceneManager.ts +33 -7
- package/src/react/EngineContext.ts +26 -0
- package/src/react/ReactScene.ts +88 -0
- package/src/react/applyProps.ts +107 -0
- package/src/react/catalogue.ts +17 -0
- package/src/react/createPixiRoot.ts +31 -0
- package/src/react/extendAll.ts +51 -0
- package/src/react/hooks.ts +46 -0
- package/src/react/index.ts +23 -0
- package/src/react/reconciler.ts +169 -0
- package/src/state/StateMachine.ts +11 -8
- package/src/types.ts +3 -0
- package/src/vite/index.ts +5 -0
package/dist/index.esm.js
CHANGED
|
@@ -363,14 +363,17 @@ class Tween {
|
|
|
363
363
|
* ```
|
|
364
364
|
*/
|
|
365
365
|
class SceneManager extends EventEmitter {
|
|
366
|
+
static MAX_TRANSITION_DEPTH = 10;
|
|
366
367
|
/** Root container that scenes are added to */
|
|
367
368
|
root;
|
|
368
369
|
registry = new Map();
|
|
369
370
|
stack = [];
|
|
370
|
-
|
|
371
|
+
_transitionDepth = 0;
|
|
371
372
|
/** Current viewport dimensions — set by ViewportManager */
|
|
372
373
|
_width = 0;
|
|
373
374
|
_height = 0;
|
|
375
|
+
/** @internal GameApplication reference — passed to scenes */
|
|
376
|
+
_app;
|
|
374
377
|
constructor(root) {
|
|
375
378
|
super();
|
|
376
379
|
if (root)
|
|
@@ -380,6 +383,10 @@ class SceneManager extends EventEmitter {
|
|
|
380
383
|
setRoot(root) {
|
|
381
384
|
this.root = root;
|
|
382
385
|
}
|
|
386
|
+
/** @internal Set the app reference (called by GameApplication) */
|
|
387
|
+
setApp(app) {
|
|
388
|
+
this._app = app;
|
|
389
|
+
}
|
|
383
390
|
/** Register a scene class by key */
|
|
384
391
|
register(key, ctor) {
|
|
385
392
|
this.registry.set(key, ctor);
|
|
@@ -395,12 +402,15 @@ class SceneManager extends EventEmitter {
|
|
|
395
402
|
}
|
|
396
403
|
/** Whether a scene transition is in progress */
|
|
397
404
|
get isTransitioning() {
|
|
398
|
-
return this.
|
|
405
|
+
return this._transitionDepth > 0;
|
|
399
406
|
}
|
|
400
407
|
/**
|
|
401
408
|
* Navigate to a scene, replacing the entire stack.
|
|
402
409
|
*/
|
|
403
410
|
async goto(key, data, transition) {
|
|
411
|
+
if (this._transitionDepth >= SceneManager.MAX_TRANSITION_DEPTH) {
|
|
412
|
+
throw new Error('[SceneManager] Max transition depth exceeded — possible infinite loop');
|
|
413
|
+
}
|
|
404
414
|
const prevKey = this.currentKey;
|
|
405
415
|
// Exit all current scenes
|
|
406
416
|
while (this.stack.length > 0) {
|
|
@@ -415,6 +425,9 @@ class SceneManager extends EventEmitter {
|
|
|
415
425
|
* Useful for overlays, modals, pause screens.
|
|
416
426
|
*/
|
|
417
427
|
async push(key, data, transition) {
|
|
428
|
+
if (this._transitionDepth >= SceneManager.MAX_TRANSITION_DEPTH) {
|
|
429
|
+
throw new Error('[SceneManager] Max transition depth exceeded — possible infinite loop');
|
|
430
|
+
}
|
|
418
431
|
const prevKey = this.currentKey;
|
|
419
432
|
await this.pushInternal(key, data, transition);
|
|
420
433
|
this.emit('change', { from: prevKey, to: key });
|
|
@@ -427,6 +440,9 @@ class SceneManager extends EventEmitter {
|
|
|
427
440
|
console.warn('[SceneManager] Cannot pop the last scene');
|
|
428
441
|
return;
|
|
429
442
|
}
|
|
443
|
+
if (this._transitionDepth >= SceneManager.MAX_TRANSITION_DEPTH) {
|
|
444
|
+
throw new Error('[SceneManager] Max transition depth exceeded — possible infinite loop');
|
|
445
|
+
}
|
|
430
446
|
const prevKey = this.currentKey;
|
|
431
447
|
await this.popInternal(true, transition);
|
|
432
448
|
this.emit('change', { from: prevKey, to: this.currentKey });
|
|
@@ -435,6 +451,9 @@ class SceneManager extends EventEmitter {
|
|
|
435
451
|
* Replace the top scene with a new one.
|
|
436
452
|
*/
|
|
437
453
|
async replace(key, data, transition) {
|
|
454
|
+
if (this._transitionDepth >= SceneManager.MAX_TRANSITION_DEPTH) {
|
|
455
|
+
throw new Error('[SceneManager] Max transition depth exceeded — possible infinite loop');
|
|
456
|
+
}
|
|
438
457
|
const prevKey = this.currentKey;
|
|
439
458
|
await this.popInternal(false);
|
|
440
459
|
await this.pushInternal(key, data, transition);
|
|
@@ -476,10 +495,14 @@ class SceneManager extends EventEmitter {
|
|
|
476
495
|
if (!Ctor) {
|
|
477
496
|
throw new Error(`[SceneManager] Scene "${key}" is not registered`);
|
|
478
497
|
}
|
|
479
|
-
|
|
498
|
+
const scene = new Ctor();
|
|
499
|
+
if (this._app) {
|
|
500
|
+
scene.__engineApp = this._app;
|
|
501
|
+
}
|
|
502
|
+
return scene;
|
|
480
503
|
}
|
|
481
504
|
async pushInternal(key, data, transition) {
|
|
482
|
-
this.
|
|
505
|
+
this._transitionDepth++;
|
|
483
506
|
const scene = this.createScene(key);
|
|
484
507
|
this.root.addChild(scene.container);
|
|
485
508
|
// Set initial size
|
|
@@ -491,20 +514,20 @@ class SceneManager extends EventEmitter {
|
|
|
491
514
|
// Push to stack BEFORE onEnter so currentKey is correct during initialization
|
|
492
515
|
this.stack.push({ scene, key });
|
|
493
516
|
await scene.onEnter?.(data);
|
|
494
|
-
this.
|
|
517
|
+
this._transitionDepth--;
|
|
495
518
|
}
|
|
496
519
|
async popInternal(showTransition, transition) {
|
|
497
520
|
const entry = this.stack.pop();
|
|
498
521
|
if (!entry)
|
|
499
522
|
return;
|
|
500
|
-
this.
|
|
523
|
+
this._transitionDepth++;
|
|
501
524
|
await entry.scene.onExit?.();
|
|
502
525
|
if (showTransition) {
|
|
503
526
|
await this.transitionOut(entry.scene.container, transition);
|
|
504
527
|
}
|
|
505
528
|
entry.scene.onDestroy?.();
|
|
506
529
|
entry.scene.container.destroy({ children: true });
|
|
507
|
-
this.
|
|
530
|
+
this._transitionDepth--;
|
|
508
531
|
}
|
|
509
532
|
async transitionIn(container, config) {
|
|
510
533
|
const type = config?.type ?? TransitionType.NONE;
|
|
@@ -2237,6 +2260,7 @@ class GameApplication extends EventEmitter {
|
|
|
2237
2260
|
});
|
|
2238
2261
|
// Wire SceneManager to the PixiJS stage
|
|
2239
2262
|
this.scenes.setRoot(this.app.stage);
|
|
2263
|
+
this.scenes.setApp(this);
|
|
2240
2264
|
// Wire viewport resize → scene manager + input manager
|
|
2241
2265
|
this.viewport.on('resize', ({ width, height, scale }) => {
|
|
2242
2266
|
this.scenes.resize(width, height);
|
|
@@ -2322,10 +2346,11 @@ class GameApplication extends EventEmitter {
|
|
|
2322
2346
|
* ```
|
|
2323
2347
|
*/
|
|
2324
2348
|
class StateMachine extends EventEmitter {
|
|
2349
|
+
static MAX_TRANSITION_DEPTH = 10;
|
|
2325
2350
|
_states = new Map();
|
|
2326
2351
|
_guards = new Map();
|
|
2327
2352
|
_current = null;
|
|
2328
|
-
|
|
2353
|
+
_transitionDepth = 0;
|
|
2329
2354
|
_context;
|
|
2330
2355
|
constructor(context) {
|
|
2331
2356
|
super();
|
|
@@ -2337,7 +2362,7 @@ class StateMachine extends EventEmitter {
|
|
|
2337
2362
|
}
|
|
2338
2363
|
/** Whether a transition is in progress */
|
|
2339
2364
|
get isTransitioning() {
|
|
2340
|
-
return this.
|
|
2365
|
+
return this._transitionDepth > 0;
|
|
2341
2366
|
}
|
|
2342
2367
|
/** State machine context (shared data) */
|
|
2343
2368
|
get context() {
|
|
@@ -2385,9 +2410,8 @@ class StateMachine extends EventEmitter {
|
|
|
2385
2410
|
* @returns true if the transition succeeded, false if blocked by a guard
|
|
2386
2411
|
*/
|
|
2387
2412
|
async transition(to, data) {
|
|
2388
|
-
if (this.
|
|
2389
|
-
|
|
2390
|
-
return false;
|
|
2413
|
+
if (this._transitionDepth >= StateMachine.MAX_TRANSITION_DEPTH) {
|
|
2414
|
+
throw new Error('[StateMachine] Max transition depth exceeded — possible infinite loop');
|
|
2391
2415
|
}
|
|
2392
2416
|
const from = this._current;
|
|
2393
2417
|
// Check guard
|
|
@@ -2402,7 +2426,7 @@ class StateMachine extends EventEmitter {
|
|
|
2402
2426
|
if (!toState) {
|
|
2403
2427
|
throw new Error(`[StateMachine] State "${to}" not registered.`);
|
|
2404
2428
|
}
|
|
2405
|
-
this.
|
|
2429
|
+
this._transitionDepth++;
|
|
2406
2430
|
try {
|
|
2407
2431
|
// Exit current state
|
|
2408
2432
|
if (from !== null) {
|
|
@@ -2419,7 +2443,7 @@ class StateMachine extends EventEmitter {
|
|
|
2419
2443
|
throw err;
|
|
2420
2444
|
}
|
|
2421
2445
|
finally {
|
|
2422
|
-
this.
|
|
2446
|
+
this._transitionDepth--;
|
|
2423
2447
|
}
|
|
2424
2448
|
return true;
|
|
2425
2449
|
}
|
|
@@ -2460,7 +2484,7 @@ class StateMachine extends EventEmitter {
|
|
|
2460
2484
|
await state?.exit?.(this._context);
|
|
2461
2485
|
}
|
|
2462
2486
|
this._current = null;
|
|
2463
|
-
this.
|
|
2487
|
+
this._transitionDepth = 0;
|
|
2464
2488
|
}
|
|
2465
2489
|
/**
|
|
2466
2490
|
* Destroy the state machine.
|