@energy8platform/game-engine 0.17.0 → 0.19.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/dist/audio.cjs.js +15 -5
- package/dist/audio.cjs.js.map +1 -1
- package/dist/audio.d.ts +5 -0
- package/dist/audio.esm.js +15 -5
- package/dist/audio.esm.js.map +1 -1
- package/dist/core.cjs.js +108 -19
- package/dist/core.cjs.js.map +1 -1
- package/dist/core.d.ts +46 -3
- package/dist/core.esm.js +109 -21
- package/dist/core.esm.js.map +1 -1
- package/dist/game-spec.cjs.js +13 -0
- package/dist/game-spec.cjs.js.map +1 -0
- package/dist/game-spec.d.ts +1 -0
- package/dist/game-spec.esm.js +2 -0
- package/dist/game-spec.esm.js.map +1 -0
- package/dist/host.cjs.js +3612 -0
- package/dist/host.cjs.js.map +1 -0
- package/dist/host.d.ts +1000 -0
- package/dist/host.esm.js +3603 -0
- package/dist/host.esm.js.map +1 -0
- package/dist/index.cjs.js +59 -19
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +19 -2
- package/dist/index.esm.js +59 -19
- package/dist/index.esm.js.map +1 -1
- package/dist/react.cjs.js.map +1 -1
- package/dist/react.d.ts +19 -2
- package/dist/react.esm.js.map +1 -1
- package/dist/shell.cjs.js +19 -0
- package/dist/shell.cjs.js.map +1 -0
- package/dist/shell.d.ts +1 -0
- package/dist/shell.esm.js +2 -0
- package/dist/shell.esm.js.map +1 -0
- package/dist/slot.cjs.js +998 -0
- package/dist/slot.cjs.js.map +1 -0
- package/dist/slot.d.ts +333 -0
- package/dist/slot.esm.js +985 -0
- package/dist/slot.esm.js.map +1 -0
- package/package.json +28 -2
- package/src/audio/AudioManager.ts +17 -5
- package/src/core/GameApplication.ts +38 -6
- package/src/core/index.ts +2 -0
- package/src/game-spec/index.ts +1 -0
- package/src/host/autoplay.ts +78 -0
- package/src/host/balanceGate.ts +46 -0
- package/src/host/buildConfig.ts +28 -0
- package/src/host/createSlotGame.ts +543 -0
- package/src/host/fatalError.ts +104 -0
- package/src/host/freeSpinsCounter.ts +44 -0
- package/src/host/index.ts +21 -0
- package/src/host/overlayController.ts +81 -0
- package/src/host/pauseController.ts +21 -0
- package/src/host/playError.ts +64 -0
- package/src/host/preboot.ts +25 -0
- package/src/host/replay.ts +9 -0
- package/src/host/runRound.ts +55 -0
- package/src/host/sceneAudio.ts +14 -0
- package/src/host/sceneController.ts +96 -0
- package/src/host/sceneStart.ts +25 -0
- package/src/host/shellConfig.ts +384 -0
- package/src/host/skipGesture.ts +24 -0
- package/src/host/slotPlay.ts +62 -0
- package/src/host/types.ts +74 -0
- package/src/scenes/IntroScene.ts +66 -0
- package/src/shell/index.ts +20 -0
- package/src/slot/anim/CascadeController.ts +102 -0
- package/src/slot/anim/ReelSpinController.ts +81 -0
- package/src/slot/anim/easing-map.ts +14 -0
- package/src/slot/freeSpins/FreeSpinsSession.ts +40 -0
- package/src/slot/grid/AnimatedSymbol.ts +68 -0
- package/src/slot/grid/ReelGrid.ts +92 -0
- package/src/slot/grid/SymbolCell.ts +127 -0
- package/src/slot/grid/SymbolView.ts +13 -0
- package/src/slot/index.ts +21 -0
- package/src/slot/multiplier/MultiplierAccumulator.ts +29 -0
- package/src/slot/overlay/BigWinOverlay.ts +89 -0
- package/src/slot/overlay/CountUpDisplay.ts +56 -0
- package/src/slot/overlay/tiers.ts +29 -0
- package/src/types.ts +3 -0
- package/src/viewport/ViewportManager.ts +19 -9
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as _energy8platform_platform_core_shell from '@energy8platform/platform-core/shell';
|
|
1
2
|
import { Container, ApplicationOptions, Application, Texture, AnimatedSprite, Spritesheet, TextStyle, ColorSource } from 'pixi.js';
|
|
2
3
|
import { CasinoGameSDK, InitData, GameConfigData, SessionData } from '@energy8platform/game-sdk';
|
|
3
4
|
export { AnywhereWinData, BalanceData, BridgeDestroyedError, BridgeNotReadyError, GameConfigData, InitData, PaylineData, PlayParams, PlayResultData, SDKError, SessionData, SymbolData, TimeoutError, WinLineData } from '@energy8platform/game-sdk';
|
|
@@ -60,6 +61,8 @@ interface GameApplicationConfig {
|
|
|
60
61
|
pixi?: Partial<ApplicationOptions>;
|
|
61
62
|
/** Enable debug overlay (FPS, draw calls) */
|
|
62
63
|
debug?: boolean;
|
|
64
|
+
/** When set, GameApplication mounts the branded game shell after the SDK handshake. */
|
|
65
|
+
shell?: _energy8platform_platform_core_shell.ShellConfig | false;
|
|
63
66
|
}
|
|
64
67
|
interface SceneConstructor {
|
|
65
68
|
new (): IScene;
|
|
@@ -339,6 +342,7 @@ declare class AudioManager {
|
|
|
339
342
|
private _persist;
|
|
340
343
|
private _storageKey;
|
|
341
344
|
private _categories;
|
|
345
|
+
private _masterGain;
|
|
342
346
|
private _currentMusic;
|
|
343
347
|
private _unlocked;
|
|
344
348
|
private _unlockHandler;
|
|
@@ -379,6 +383,10 @@ declare class AudioManager {
|
|
|
379
383
|
* Stop all sounds.
|
|
380
384
|
*/
|
|
381
385
|
stopAll(): void;
|
|
386
|
+
/** Global gain (0..1) folded into every category's effective volume. Driven by the shell's
|
|
387
|
+
* 'master' settingChange. Does not affect the persisted per-category volumes. */
|
|
388
|
+
setMasterVolume(volume: number): void;
|
|
389
|
+
getMasterVolume(): number;
|
|
382
390
|
/**
|
|
383
391
|
* Set volume for a category.
|
|
384
392
|
*/
|
|
@@ -581,6 +589,7 @@ declare class ViewportManager extends EventEmitter<ViewportEvents> {
|
|
|
581
589
|
private _app;
|
|
582
590
|
private _container;
|
|
583
591
|
private _config;
|
|
592
|
+
private _target;
|
|
584
593
|
private _resizeObserver;
|
|
585
594
|
private _currentOrientation;
|
|
586
595
|
private _currentWidth;
|
|
@@ -588,7 +597,7 @@ declare class ViewportManager extends EventEmitter<ViewportEvents> {
|
|
|
588
597
|
private _currentScale;
|
|
589
598
|
private _destroyed;
|
|
590
599
|
private _resizeTimeout;
|
|
591
|
-
constructor(app: Application, container: HTMLElement, config: ViewportConfig);
|
|
600
|
+
constructor(app: Application, container: HTMLElement, config: ViewportConfig, target?: Container);
|
|
592
601
|
/** Current canvas width in game units */
|
|
593
602
|
get width(): number;
|
|
594
603
|
/** Current canvas height in game units */
|
|
@@ -689,6 +698,12 @@ declare class GameApplication extends EventEmitter<GameEngineEvents> {
|
|
|
689
698
|
input: InputManager;
|
|
690
699
|
/** Viewport manager */
|
|
691
700
|
viewport: ViewportManager;
|
|
701
|
+
/** Scaled world root (holds scenes). Transformed by the ViewportManager to fit the design
|
|
702
|
+
* resolution; lives below the UI layer on app.stage. */
|
|
703
|
+
worldRoot: Container;
|
|
704
|
+
/** Unscaled, screen-space UI layer. Sits above {@link worldRoot} and is NOT touched by the
|
|
705
|
+
* viewport transform — children fill the real screen (e.g. the host's shell + overlay). */
|
|
706
|
+
uiLayer: Container;
|
|
692
707
|
/** SDK instance (null in offline mode) */
|
|
693
708
|
sdk: CasinoGameSDK | null;
|
|
694
709
|
/** FPS overlay instance (only when debug: true) */
|
|
@@ -697,6 +712,8 @@ declare class GameApplication extends EventEmitter<GameEngineEvents> {
|
|
|
697
712
|
initData: InitData | null;
|
|
698
713
|
/** Platform session (SDK + optional DevBridge). null until start() runs. */
|
|
699
714
|
platformSession: PlatformSession | null;
|
|
715
|
+
/** Branded game shell (only when config.shell is set). */
|
|
716
|
+
shell?: _energy8platform_platform_core_shell.GameShell;
|
|
700
717
|
/** Configuration */
|
|
701
718
|
readonly config: GameApplicationConfig;
|
|
702
719
|
private _running;
|
|
@@ -723,7 +740,7 @@ declare class GameApplication extends EventEmitter<GameEngineEvents> {
|
|
|
723
740
|
/**
|
|
724
741
|
* Destroy the engine and free all resources.
|
|
725
742
|
*/
|
|
726
|
-
destroy(): void
|
|
743
|
+
destroy(): Promise<void>;
|
|
727
744
|
private resolveContainer;
|
|
728
745
|
private initPixi;
|
|
729
746
|
private initSDK;
|
package/dist/index.esm.js
CHANGED
|
@@ -734,6 +734,7 @@ class AudioManager {
|
|
|
734
734
|
_persist;
|
|
735
735
|
_storageKey;
|
|
736
736
|
_categories;
|
|
737
|
+
_masterGain = 1.0;
|
|
737
738
|
_currentMusic = null;
|
|
738
739
|
_unlocked = false;
|
|
739
740
|
_unlockHandler = null;
|
|
@@ -793,7 +794,7 @@ class AudioManager {
|
|
|
793
794
|
if (this._globalMuted || this._categories[category].muted)
|
|
794
795
|
return;
|
|
795
796
|
const { sound } = this._soundModule;
|
|
796
|
-
const vol = (options?.volume ?? 1) * this._categories[category].volume;
|
|
797
|
+
const vol = (options?.volume ?? 1) * this._categories[category].volume * this._masterGain;
|
|
797
798
|
try {
|
|
798
799
|
sound.play(alias, {
|
|
799
800
|
volume: vol,
|
|
@@ -822,7 +823,7 @@ class AudioManager {
|
|
|
822
823
|
if (this._globalMuted || this._categories.music.muted)
|
|
823
824
|
return;
|
|
824
825
|
// Fade out the previous track
|
|
825
|
-
this.fadeVolume(prevAlias, this._categories.music.volume, 0, fadeDuration, () => {
|
|
826
|
+
this.fadeVolume(prevAlias, this._categories.music.volume * this._masterGain, 0, fadeDuration, () => {
|
|
826
827
|
try {
|
|
827
828
|
sound.stop(prevAlias);
|
|
828
829
|
}
|
|
@@ -834,7 +835,7 @@ class AudioManager {
|
|
|
834
835
|
volume: 0,
|
|
835
836
|
loop: true,
|
|
836
837
|
});
|
|
837
|
-
this.fadeVolume(alias, 0, this._categories.music.volume, fadeDuration);
|
|
838
|
+
this.fadeVolume(alias, 0, this._categories.music.volume * this._masterGain, fadeDuration);
|
|
838
839
|
}
|
|
839
840
|
catch (e) {
|
|
840
841
|
console.warn(`[AudioManager] Failed to play music "${alias}":`, e);
|
|
@@ -853,7 +854,7 @@ class AudioManager {
|
|
|
853
854
|
return;
|
|
854
855
|
try {
|
|
855
856
|
sound.play(alias, {
|
|
856
|
-
volume: this._categories.music.volume,
|
|
857
|
+
volume: this._categories.music.volume * this._masterGain,
|
|
857
858
|
loop: true,
|
|
858
859
|
});
|
|
859
860
|
}
|
|
@@ -887,6 +888,15 @@ class AudioManager {
|
|
|
887
888
|
sound.stopAll();
|
|
888
889
|
this._currentMusic = null;
|
|
889
890
|
}
|
|
891
|
+
/** Global gain (0..1) folded into every category's effective volume. Driven by the shell's
|
|
892
|
+
* 'master' settingChange. Does not affect the persisted per-category volumes. */
|
|
893
|
+
setMasterVolume(volume) {
|
|
894
|
+
this._masterGain = Math.max(0, Math.min(1, volume));
|
|
895
|
+
this.applyVolumes();
|
|
896
|
+
}
|
|
897
|
+
getMasterVolume() {
|
|
898
|
+
return this._masterGain;
|
|
899
|
+
}
|
|
890
900
|
/**
|
|
891
901
|
* Set volume for a category.
|
|
892
902
|
*/
|
|
@@ -1032,7 +1042,7 @@ class AudioManager {
|
|
|
1032
1042
|
const { sound } = this._soundModule;
|
|
1033
1043
|
// Global mute is owned by sound.muteAll()/unmuteAll() (context.muted),
|
|
1034
1044
|
// not by volumeAll — mixing both leaves mute un-undoable after reload.
|
|
1035
|
-
sound.volumeAll =
|
|
1045
|
+
sound.volumeAll = this._masterGain; // master multiplies the global bus
|
|
1036
1046
|
}
|
|
1037
1047
|
setupMobileUnlock() {
|
|
1038
1048
|
if (this._unlocked)
|
|
@@ -1300,6 +1310,7 @@ class ViewportManager extends EventEmitter {
|
|
|
1300
1310
|
_app;
|
|
1301
1311
|
_container;
|
|
1302
1312
|
_config;
|
|
1313
|
+
_target;
|
|
1303
1314
|
_resizeObserver = null;
|
|
1304
1315
|
_currentOrientation = Orientation.LANDSCAPE;
|
|
1305
1316
|
_currentWidth = 0;
|
|
@@ -1307,11 +1318,15 @@ class ViewportManager extends EventEmitter {
|
|
|
1307
1318
|
_currentScale = 1;
|
|
1308
1319
|
_destroyed = false;
|
|
1309
1320
|
_resizeTimeout = null;
|
|
1310
|
-
constructor(app, container, config) {
|
|
1321
|
+
constructor(app, container, config, target) {
|
|
1311
1322
|
super();
|
|
1312
1323
|
this._app = app;
|
|
1313
1324
|
this._container = container;
|
|
1314
1325
|
this._config = config;
|
|
1326
|
+
// The container this manager scales/offsets. Defaults to app.stage for backward
|
|
1327
|
+
// compatibility; the engine passes a dedicated scaled world root so app.stage stays
|
|
1328
|
+
// identity (screen space) for unscaled UI layers.
|
|
1329
|
+
this._target = target ?? app.stage;
|
|
1315
1330
|
this.setupObserver();
|
|
1316
1331
|
}
|
|
1317
1332
|
/** Current canvas width in game units */
|
|
@@ -1400,19 +1415,19 @@ class ViewportManager extends EventEmitter {
|
|
|
1400
1415
|
const stageScale = scaleMode === ScaleMode.STRETCH
|
|
1401
1416
|
? Math.min(containerWidth / designWidth, containerHeight / designHeight)
|
|
1402
1417
|
: scale;
|
|
1403
|
-
this.
|
|
1418
|
+
this._target.scale.set(stageScale);
|
|
1404
1419
|
// Center the stage for FIT mode
|
|
1405
1420
|
if (scaleMode === ScaleMode.FIT) {
|
|
1406
|
-
this.
|
|
1407
|
-
this.
|
|
1421
|
+
this._target.x = Math.round((containerWidth - designWidth * stageScale) / 2);
|
|
1422
|
+
this._target.y = Math.round((containerHeight - designHeight * stageScale) / 2);
|
|
1408
1423
|
}
|
|
1409
1424
|
else if (scaleMode === ScaleMode.FILL) {
|
|
1410
|
-
this.
|
|
1411
|
-
this.
|
|
1425
|
+
this._target.x = Math.round((containerWidth - gameWidth * stageScale) / 2);
|
|
1426
|
+
this._target.y = Math.round((containerHeight - gameHeight * stageScale) / 2);
|
|
1412
1427
|
}
|
|
1413
1428
|
else {
|
|
1414
|
-
this.
|
|
1415
|
-
this.
|
|
1429
|
+
this._target.x = 0;
|
|
1430
|
+
this._target.y = 0;
|
|
1416
1431
|
}
|
|
1417
1432
|
this._currentWidth = gameWidth;
|
|
1418
1433
|
this._currentHeight = gameHeight;
|
|
@@ -1903,6 +1918,12 @@ class GameApplication extends EventEmitter {
|
|
|
1903
1918
|
input;
|
|
1904
1919
|
/** Viewport manager */
|
|
1905
1920
|
viewport;
|
|
1921
|
+
/** Scaled world root (holds scenes). Transformed by the ViewportManager to fit the design
|
|
1922
|
+
* resolution; lives below the UI layer on app.stage. */
|
|
1923
|
+
worldRoot;
|
|
1924
|
+
/** Unscaled, screen-space UI layer. Sits above {@link worldRoot} and is NOT touched by the
|
|
1925
|
+
* viewport transform — children fill the real screen (e.g. the host's shell + overlay). */
|
|
1926
|
+
uiLayer;
|
|
1906
1927
|
/** SDK instance (null in offline mode) */
|
|
1907
1928
|
sdk = null;
|
|
1908
1929
|
/** FPS overlay instance (only when debug: true) */
|
|
@@ -1911,6 +1932,8 @@ class GameApplication extends EventEmitter {
|
|
|
1911
1932
|
initData = null;
|
|
1912
1933
|
/** Platform session (SDK + optional DevBridge). null until start() runs. */
|
|
1913
1934
|
platformSession = null;
|
|
1935
|
+
/** Branded game shell (only when config.shell is set). */
|
|
1936
|
+
shell;
|
|
1914
1937
|
/** Configuration */
|
|
1915
1938
|
config;
|
|
1916
1939
|
// ─── Private state ──────────────────────────────────────
|
|
@@ -1972,6 +1995,11 @@ class GameApplication extends EventEmitter {
|
|
|
1972
1995
|
await this.initPixi();
|
|
1973
1996
|
// 4. Initialize SDK (if enabled)
|
|
1974
1997
|
await this.initSDK();
|
|
1998
|
+
// 4b. Mount the branded game shell after the SDK handshake (optional)
|
|
1999
|
+
if (this.config.shell) {
|
|
2000
|
+
const { createGameShell } = await import('@energy8platform/platform-core/shell');
|
|
2001
|
+
this.shell = createGameShell(this.config.shell);
|
|
2002
|
+
}
|
|
1975
2003
|
// 5. Merge design dimensions from SDK config
|
|
1976
2004
|
this.applySDKConfig();
|
|
1977
2005
|
// 6. Initialize sub-systems
|
|
@@ -1995,11 +2023,16 @@ class GameApplication extends EventEmitter {
|
|
|
1995
2023
|
/**
|
|
1996
2024
|
* Destroy the engine and free all resources.
|
|
1997
2025
|
*/
|
|
1998
|
-
destroy() {
|
|
2026
|
+
async destroy() {
|
|
1999
2027
|
if (this._destroyed)
|
|
2000
2028
|
return;
|
|
2001
2029
|
this._destroyed = true;
|
|
2002
2030
|
this._running = false;
|
|
2031
|
+
if (this.shell) {
|
|
2032
|
+
const { removeGameShell } = await import('@energy8platform/platform-core/shell');
|
|
2033
|
+
await removeGameShell();
|
|
2034
|
+
this.shell = undefined;
|
|
2035
|
+
}
|
|
2003
2036
|
this.scenes?.destroy();
|
|
2004
2037
|
this.input?.destroy();
|
|
2005
2038
|
this.audio?.destroy();
|
|
@@ -2070,20 +2103,27 @@ class GameApplication extends EventEmitter {
|
|
|
2070
2103
|
this.audio = new AudioManager(this.config.audio);
|
|
2071
2104
|
// Input Manager
|
|
2072
2105
|
this.input = new InputManager(this.app.canvas);
|
|
2073
|
-
//
|
|
2106
|
+
// Stage layers: a scaled world root (scenes, transformed to design resolution by the
|
|
2107
|
+
// viewport) below an unscaled UI layer (screen space). app.stage itself stays identity.
|
|
2108
|
+
this.worldRoot = new Container();
|
|
2109
|
+
this.worldRoot.label = 'world';
|
|
2110
|
+
this.uiLayer = new Container();
|
|
2111
|
+
this.uiLayer.label = 'ui';
|
|
2112
|
+
this.app.stage.addChild(this.worldRoot, this.uiLayer);
|
|
2113
|
+
// Viewport Manager — scales worldRoot (NOT app.stage), so the UI layer is unscaled.
|
|
2074
2114
|
this.viewport = new ViewportManager(this.app, this._container, {
|
|
2075
2115
|
designWidth: this.config.designWidth,
|
|
2076
2116
|
designHeight: this.config.designHeight,
|
|
2077
2117
|
scaleMode: this.config.scaleMode,
|
|
2078
2118
|
orientation: this.config.orientation,
|
|
2079
|
-
});
|
|
2080
|
-
// Wire SceneManager to the
|
|
2081
|
-
this.scenes.setRoot(this.
|
|
2119
|
+
}, this.worldRoot);
|
|
2120
|
+
// Wire SceneManager to the scaled world root
|
|
2121
|
+
this.scenes.setRoot(this.worldRoot);
|
|
2082
2122
|
this.scenes.setApp(this);
|
|
2083
2123
|
// Wire viewport resize → scene manager + input manager
|
|
2084
2124
|
this.viewport.on('resize', ({ width, height, scale }) => {
|
|
2085
2125
|
this.scenes.resize(width, height);
|
|
2086
|
-
this.input.setViewportTransform(scale, this.
|
|
2126
|
+
this.input.setViewportTransform(scale, this.worldRoot.x, this.worldRoot.y);
|
|
2087
2127
|
this.emit('resize', { width, height });
|
|
2088
2128
|
});
|
|
2089
2129
|
this.viewport.on('orientationChange', (orientation) => {
|