@energy8platform/game-engine 0.15.2 → 0.16.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 +22 -12
- package/dist/assets.d.ts +2 -14
- package/dist/core.cjs.js +16 -201
- package/dist/core.cjs.js.map +1 -1
- package/dist/core.d.ts +4 -35
- package/dist/core.esm.js +12 -197
- package/dist/core.esm.js.map +1 -1
- package/dist/debug.cjs.js +5 -233
- package/dist/debug.cjs.js.map +1 -1
- package/dist/debug.d.ts +2 -140
- package/dist/debug.esm.js +2 -233
- package/dist/debug.esm.js.map +1 -1
- package/dist/index.cjs.js +21 -432
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +10 -195
- package/dist/index.esm.js +14 -429
- package/dist/index.esm.js.map +1 -1
- package/dist/lua.cjs.js +7 -1493
- package/dist/lua.cjs.js.map +1 -1
- package/dist/lua.d.ts +1 -403
- package/dist/lua.esm.js +1 -1483
- package/dist/lua.esm.js.map +1 -1
- package/dist/react.cjs.js.map +1 -1
- package/dist/react.d.ts +4 -35
- package/dist/react.esm.js.map +1 -1
- package/dist/vite.cjs.js +19 -175
- package/dist/vite.cjs.js.map +1 -1
- package/dist/vite.d.ts +8 -3
- package/dist/vite.esm.js +10 -173
- package/dist/vite.esm.js.map +1 -1
- package/package.json +6 -16
- package/src/core/GameApplication.ts +14 -18
- package/src/debug/index.ts +4 -2
- package/src/index.ts +3 -3
- package/src/loading/LoadingScene.ts +1 -1
- package/src/loading/index.ts +9 -2
- package/src/lua/index.ts +3 -31
- package/src/types.ts +16 -41
- package/src/vite/index.ts +13 -196
- package/bin/simulate.ts +0 -139
- package/scripts/install-simulate.mjs +0 -101
- package/src/debug/DevBridge.ts +0 -305
- package/src/loading/CSSPreloader.ts +0 -129
- package/src/loading/logo.ts +0 -95
- package/src/lua/ActionRouter.ts +0 -132
- package/src/lua/LuaEngine.ts +0 -412
- package/src/lua/LuaEngineAPI.ts +0 -314
- package/src/lua/NativeSimulationRunner.ts +0 -367
- package/src/lua/ParallelSimulationRunner.ts +0 -156
- package/src/lua/PersistentState.ts +0 -80
- package/src/lua/SessionManager.ts +0 -227
- package/src/lua/SimulationRunner.ts +0 -192
- package/src/lua/SimulationWorker.ts +0 -44
- package/src/lua/fengari.d.ts +0 -10
- package/src/lua/types.ts +0 -149
package/dist/index.cjs.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var pixi_js = require('pixi.js');
|
|
4
|
+
var platformCore = require('@energy8platform/platform-core');
|
|
5
|
+
var loading = require('@energy8platform/platform-core/loading');
|
|
4
6
|
var gameSdk = require('@energy8platform/game-sdk');
|
|
7
|
+
var devBridge = require('@energy8platform/platform-core/dev-bridge');
|
|
5
8
|
|
|
6
9
|
// ─── Scale Modes ───────────────────────────────────────────
|
|
7
10
|
exports.ScaleMode = void 0;
|
|
@@ -1499,81 +1502,12 @@ class Scene {
|
|
|
1499
1502
|
}
|
|
1500
1503
|
}
|
|
1501
1504
|
|
|
1502
|
-
/**
|
|
1503
|
-
* Shared Energy8 SVG logo with an embedded loader bar.
|
|
1504
|
-
*
|
|
1505
|
-
* The loader bar fill is controlled via a `<clipPath>` whose `<rect>` width
|
|
1506
|
-
* is animatable. Different consumers customise gradient IDs and the clip
|
|
1507
|
-
* element's ID/class to avoid collisions when both CSSPreloader and
|
|
1508
|
-
* LoadingScene appear in the same DOM.
|
|
1509
|
-
*/
|
|
1510
|
-
/** SVG path data for the Energy8 wordmark — reused across loaders */
|
|
1511
|
-
const WORDMARK_PATHS = `
|
|
1512
|
-
<path d="m241 81.75h-19.28c-1.77 0-6.73 4.98-7.43 6.99l-4.36 12.22c-0.49 1.37 0.05 2.92 1.06 4.32-2.07 1.19-3.69 3.08-4.36 5.43l-3.25 10.41c-0.86 2.89 2.39 6.63 4.31 6.63h19.28c1.96 0 7.4-5.56 7.96-7.51l2.96-10.22c0.63-2.25 0.1-3.98-1.22-4.99 2.55-1.56 3.86-4.14 4.55-6.31l2.77-9.31c0.74-2.57-1.37-7.66-2.99-7.66zm-13.36 28.31-2.27 7.03h-8.28l2.58-8.28h8.28l-0.31 1.25zm4.06-16.97-2.11 6.7h-7.04l2.25-7.34h7.26l-0.36 0.64z" fill="url(#GID0)"/>
|
|
1513
|
-
<path d="m202.5 81.75-9.31 14.97-2.32-14.97h-11.82l4.32 25.15-0.57 4.91-8.64 26.44 15.31-12.76 5.63-16.48 19.96-27.26h-12.56z" fill="url(#GID1)"/>
|
|
1514
|
-
<path d="m174.2 81.75h-19.78l-5.75 5.16-10.79 33.2c-0.77 2.53 2.48 6.93 4.87 6.93h17.38c2.63 0 7.85-5.34 8.32-6.83l5.37-18.14h-15.17l-2.2 7.64h3.78l-2.25 7.2h-8.01l7.1-25.52h7.58l-1.48 8.4 12.78-5.98c1.28-0.63 1.97-3.99 1.61-6.61-0.36-2.34-1.64-5.45-3.36-5.45z" fill="url(#GID2)"/>
|
|
1515
|
-
<path d="m140.6 81.75h-70.6l-5.36 19.37-4.26-19.37h-46.76l2.95 5.88-10.58 39.28h26.84l2.95-9.52-15.63-0.13 2.55-8.34h8.74l8.47-9.81h-14.61l2.11-7.3h15.47l2.54-8.71 2.58 4.74-11.4 39.07h11.05l6.46-21.49 8.84 36.33 19.18-55.67-1.83-3.36 3.68 4.09-12.07 40.1h28.18l3.39-10.31h-17.01l2.67-8.03h9.98l7.58-9.52h-14.28l1.93-6.6h14.61l3.25-9.73 2.81 5.12-11.3 38.89h11.05l5.23-17.81h1.62l1.48 17.6h10.69l-1.48-16.81c4.75-1.28 7.52-5.9 8.64-9.81l2.95-11.3c0.86-2.73-1.43-6.85-3.3-6.85zm-9.8 17.3h-8.69l2.54-7.84h8.35l-2.2 7.84z" fill="url(#GID3)"/>
|
|
1516
|
-
<path d="m205.9 148.9h-122.6l-2.61-3.12h-32.4l-2.51 3.12h-1.59c-5.34 0-7.94 4.88-7.94 7.65v0.03c0 4.2 3.55 7.6 7.74 7.6h103.6l2.11 3.12h36.09l1.82-3.12h18.3c5.25 0 6.64-5.3 6.64-7.35v-0.25c0-4.23-2.9-7.68-6.64-7.68zm-0.7 12.83h-160.6c-3.69 0-6.11-2.58-6.11-5.47v-0.03c0-2.89 2.1-5.47 5.61-5.47h161.1c3.45 0 4.89 3.12 4.89 5.65v0.17c0 2.57-2.11 5.15-4.89 5.15z" fill="url(#GID4)"/>`;
|
|
1517
|
-
/** Gradient definitions template (gradient IDs are replaced per-consumer) */
|
|
1518
|
-
const GRADIENT_DEFS = `
|
|
1519
|
-
<linearGradient id="GID0" x1="223.7" x2="223.7" y1="81.75" y2="127.8" gradientUnits="userSpaceOnUse">
|
|
1520
|
-
<stop stop-color="#663BA6"/><stop stop-color="#7939C2" offset=".349"/><stop stop-color="#8A2FC0" offset=".6615"/><stop stop-color="#791BA3" offset="1"/>
|
|
1521
|
-
</linearGradient>
|
|
1522
|
-
<linearGradient id="GID1" x1="194.6" x2="194.6" y1="81.75" y2="138.3" gradientUnits="userSpaceOnUse">
|
|
1523
|
-
<stop stop-color="#663BA6"/><stop stop-color="#7939C2" offset=".349"/><stop stop-color="#8A2FC0" offset=".6615"/><stop stop-color="#791BA3" offset="1"/>
|
|
1524
|
-
</linearGradient>
|
|
1525
|
-
<linearGradient id="GID2" x1="157.8" x2="157.8" y1="81.75" y2="127" gradientUnits="userSpaceOnUse">
|
|
1526
|
-
<stop stop-color="#663BA6"/><stop stop-color="#7939C2" offset=".349"/><stop stop-color="#8A2FC0" offset=".6615"/><stop stop-color="#791BA3" offset="1"/>
|
|
1527
|
-
</linearGradient>
|
|
1528
|
-
<linearGradient id="GID3" x1="79.96" x2="79.96" y1="81.75" y2="141.8" gradientUnits="userSpaceOnUse">
|
|
1529
|
-
<stop stop-color="#663BA6"/><stop stop-color="#7939C2" offset=".349"/><stop stop-color="#8A2FC0" offset=".6615"/><stop stop-color="#791BA3" offset="1"/>
|
|
1530
|
-
</linearGradient>
|
|
1531
|
-
<linearGradient id="GID4" x1="36.18" x2="212.5" y1="156.6" y2="156.6" gradientUnits="userSpaceOnUse">
|
|
1532
|
-
<stop stop-color="#316FB0"/><stop stop-color="#1FCDE6" offset=".5"/><stop stop-color="#29FEE7" offset="1"/>
|
|
1533
|
-
</linearGradient>
|
|
1534
|
-
<linearGradient id="GID5" x1="40.27" x2="208.2" y1="156.4" y2="156.4" gradientUnits="userSpaceOnUse">
|
|
1535
|
-
<stop stop-color="#316FB0"/><stop stop-color="#1FCDE6" offset=".5"/><stop stop-color="#29FEE7" offset="1"/>
|
|
1536
|
-
</linearGradient>`;
|
|
1537
|
-
/** Max width of the loader bar in SVG units */
|
|
1538
|
-
const LOADER_BAR_MAX_WIDTH = 174;
|
|
1539
|
-
/**
|
|
1540
|
-
* Build the Energy8 SVG logo with a loader bar, using unique IDs.
|
|
1541
|
-
*
|
|
1542
|
-
* @param opts - Configuration to avoid element ID collisions
|
|
1543
|
-
* @returns SVG markup string
|
|
1544
|
-
*/
|
|
1545
|
-
function buildLogoSVG(opts) {
|
|
1546
|
-
const { idPrefix, svgClass, svgStyle, clipRectClass, clipRectId, textId, textContent, textClass } = opts;
|
|
1547
|
-
// Replace gradient ID placeholders with prefixed versions
|
|
1548
|
-
const paths = WORDMARK_PATHS.replace(/GID(\d)/g, `${idPrefix}$1`);
|
|
1549
|
-
const defs = GRADIENT_DEFS.replace(/GID(\d)/g, `${idPrefix}$1`);
|
|
1550
|
-
const clipId = `${idPrefix}-loader-clip`;
|
|
1551
|
-
const fillGradientId = `${idPrefix}5`;
|
|
1552
|
-
const classAttr = svgClass ? ` class="${svgClass}"` : '';
|
|
1553
|
-
const styleAttr = svgStyle ? ` style="${svgStyle}"` : '';
|
|
1554
|
-
const rectClassAttr = clipRectClass ? ` class="${clipRectClass}"` : '';
|
|
1555
|
-
const rectIdAttr = clipRectId ? ` id="${clipRectId}"` : '';
|
|
1556
|
-
const txtIdAttr = textId ? ` id="${textId}"` : '';
|
|
1557
|
-
const txtClassAttr = textClass ? ` class="${textClass}"` : '';
|
|
1558
|
-
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 250 200" fill="none"${classAttr}${styleAttr}>
|
|
1559
|
-
${paths}
|
|
1560
|
-
<clipPath id="${clipId}">
|
|
1561
|
-
<rect${rectIdAttr} x="37" y="148" width="0" height="20"${rectClassAttr}/>
|
|
1562
|
-
</clipPath>
|
|
1563
|
-
<path d="m204.5 152.6h-159.8c-2.78 0-4.45 1.69-4.45 3.99v0.11c0 2.04 1.42 3.43 3.64 3.43h160.6c2.88 0 3.67-2.07 3.67-3.43v-0.25c0-2.04-1.48-3.85-3.67-3.85z" fill="url(#${fillGradientId})" clip-path="url(#${clipId})"/>
|
|
1564
|
-
<text${txtIdAttr} x="125" y="196" text-anchor="middle" fill="rgba(255,255,255,0.6)" font-family="-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif" font-size="8" font-weight="600" letter-spacing="1.5"${txtClassAttr}>${textContent ?? 'Loading...'}</text>
|
|
1565
|
-
<defs>
|
|
1566
|
-
${defs}
|
|
1567
|
-
</defs>
|
|
1568
|
-
</svg>`;
|
|
1569
|
-
}
|
|
1570
|
-
|
|
1571
1505
|
/**
|
|
1572
1506
|
* Build the loading scene variant of the logo SVG.
|
|
1573
1507
|
* Uses unique IDs (prefixed with 'ls') to avoid collisions with CSSPreloader.
|
|
1574
1508
|
*/
|
|
1575
1509
|
function buildLoadingLogoSVG() {
|
|
1576
|
-
return buildLogoSVG({
|
|
1510
|
+
return loading.buildLogoSVG({
|
|
1577
1511
|
idPrefix: 'ls',
|
|
1578
1512
|
svgStyle: 'width:100%;height:auto;',
|
|
1579
1513
|
clipRectId: 'ge-loader-rect',
|
|
@@ -1754,7 +1688,7 @@ class LoadingScene extends Scene {
|
|
|
1754
1688
|
// ─── Progress ──────────────────────────────────────────
|
|
1755
1689
|
updateLoaderBar(progress) {
|
|
1756
1690
|
if (this._loaderRect) {
|
|
1757
|
-
this._loaderRect.setAttribute('width', String(LOADER_BAR_MAX_WIDTH * progress));
|
|
1691
|
+
this._loaderRect.setAttribute('width', String(loading.LOADER_BAR_MAX_WIDTH * progress));
|
|
1758
1692
|
}
|
|
1759
1693
|
if (this._percentEl) {
|
|
1760
1694
|
const pct = Math.round(progress * 100);
|
|
@@ -1836,120 +1770,6 @@ class LoadingScene extends Scene {
|
|
|
1836
1770
|
}
|
|
1837
1771
|
}
|
|
1838
1772
|
|
|
1839
|
-
const PRELOADER_ID = '__ge-css-preloader__';
|
|
1840
|
-
/**
|
|
1841
|
-
* Inline SVG logo with animated loader bar.
|
|
1842
|
-
* The `#loader` path acts as the progress fill — animated via clipPath.
|
|
1843
|
-
*/
|
|
1844
|
-
const LOGO_SVG = buildLogoSVG({
|
|
1845
|
-
idPrefix: 'pl',
|
|
1846
|
-
svgClass: 'ge-logo-svg',
|
|
1847
|
-
clipRectClass: 'ge-clip-rect',
|
|
1848
|
-
textClass: 'ge-preloader-svg-text',
|
|
1849
|
-
});
|
|
1850
|
-
/**
|
|
1851
|
-
* Creates a lightweight CSS-only preloader that appears instantly,
|
|
1852
|
-
* BEFORE PixiJS/WebGL is initialized.
|
|
1853
|
-
*
|
|
1854
|
-
* Displays the Energy8 logo SVG with an animated loader bar.
|
|
1855
|
-
*/
|
|
1856
|
-
function createCSSPreloader(container, config) {
|
|
1857
|
-
if (document.getElementById(PRELOADER_ID))
|
|
1858
|
-
return;
|
|
1859
|
-
const bgColor = typeof config?.backgroundColor === 'string'
|
|
1860
|
-
? config.backgroundColor
|
|
1861
|
-
: typeof config?.backgroundColor === 'number'
|
|
1862
|
-
? `#${config.backgroundColor.toString(16).padStart(6, '0')}`
|
|
1863
|
-
: '#0a0a1a';
|
|
1864
|
-
const bgGradient = config?.backgroundGradient ?? `linear-gradient(135deg, ${bgColor} 0%, #1a1a3e 100%)`;
|
|
1865
|
-
const customHTML = config?.cssPreloaderHTML ?? '';
|
|
1866
|
-
const el = document.createElement('div');
|
|
1867
|
-
el.id = PRELOADER_ID;
|
|
1868
|
-
el.innerHTML = customHTML || `
|
|
1869
|
-
<div class="ge-preloader-content">
|
|
1870
|
-
${LOGO_SVG}
|
|
1871
|
-
</div>
|
|
1872
|
-
`;
|
|
1873
|
-
const style = document.createElement('style');
|
|
1874
|
-
style.textContent = `
|
|
1875
|
-
#${PRELOADER_ID} {
|
|
1876
|
-
position: absolute;
|
|
1877
|
-
top: 0; left: 0;
|
|
1878
|
-
width: 100%; height: 100%;
|
|
1879
|
-
background: ${bgGradient};
|
|
1880
|
-
display: flex;
|
|
1881
|
-
align-items: center;
|
|
1882
|
-
justify-content: center;
|
|
1883
|
-
z-index: 10000;
|
|
1884
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
1885
|
-
transition: opacity 0.4s ease-out;
|
|
1886
|
-
}
|
|
1887
|
-
|
|
1888
|
-
#${PRELOADER_ID}.ge-preloader-hidden {
|
|
1889
|
-
opacity: 0;
|
|
1890
|
-
pointer-events: none;
|
|
1891
|
-
}
|
|
1892
|
-
|
|
1893
|
-
.ge-preloader-content {
|
|
1894
|
-
display: flex;
|
|
1895
|
-
flex-direction: column;
|
|
1896
|
-
align-items: center;
|
|
1897
|
-
width: 80%;
|
|
1898
|
-
max-width: 700px;
|
|
1899
|
-
}
|
|
1900
|
-
|
|
1901
|
-
.ge-logo-svg {
|
|
1902
|
-
width: 100%;
|
|
1903
|
-
height: auto;
|
|
1904
|
-
filter: drop-shadow(0 0 30px rgba(121, 57, 194, 0.4));
|
|
1905
|
-
}
|
|
1906
|
-
|
|
1907
|
-
/* Animate the loader clip-rect to shimmer while waiting */
|
|
1908
|
-
.ge-clip-rect {
|
|
1909
|
-
animation: ge-loader-fill 2s ease-in-out infinite;
|
|
1910
|
-
}
|
|
1911
|
-
|
|
1912
|
-
@keyframes ge-loader-fill {
|
|
1913
|
-
0% { width: 0; }
|
|
1914
|
-
50% { width: 174; }
|
|
1915
|
-
100% { width: 0; }
|
|
1916
|
-
}
|
|
1917
|
-
|
|
1918
|
-
/* Animate the SVG text opacity */
|
|
1919
|
-
.ge-preloader-svg-text {
|
|
1920
|
-
animation: ge-pulse 1.5s ease-in-out infinite;
|
|
1921
|
-
}
|
|
1922
|
-
|
|
1923
|
-
@keyframes ge-pulse {
|
|
1924
|
-
0%, 100% { opacity: 0.4; }
|
|
1925
|
-
50% { opacity: 1; }
|
|
1926
|
-
}
|
|
1927
|
-
`;
|
|
1928
|
-
container.style.position = container.style.position || 'relative';
|
|
1929
|
-
container.appendChild(style);
|
|
1930
|
-
container.appendChild(el);
|
|
1931
|
-
}
|
|
1932
|
-
/**
|
|
1933
|
-
* Remove the CSS preloader with a smooth fade-out transition.
|
|
1934
|
-
*/
|
|
1935
|
-
function removeCSSPreloader(container) {
|
|
1936
|
-
const el = document.getElementById(PRELOADER_ID);
|
|
1937
|
-
if (!el)
|
|
1938
|
-
return;
|
|
1939
|
-
el.classList.add('ge-preloader-hidden');
|
|
1940
|
-
// Remove after transition
|
|
1941
|
-
el.addEventListener('transitionend', () => {
|
|
1942
|
-
el.remove();
|
|
1943
|
-
// Also remove the style element
|
|
1944
|
-
const styles = container.querySelectorAll('style');
|
|
1945
|
-
for (const style of styles) {
|
|
1946
|
-
if (style.textContent?.includes(PRELOADER_ID)) {
|
|
1947
|
-
style.remove();
|
|
1948
|
-
}
|
|
1949
|
-
}
|
|
1950
|
-
});
|
|
1951
|
-
}
|
|
1952
|
-
|
|
1953
1773
|
/**
|
|
1954
1774
|
* FPS overlay for debugging performance.
|
|
1955
1775
|
*
|
|
@@ -2091,6 +1911,8 @@ class GameApplication extends EventEmitter {
|
|
|
2091
1911
|
fpsOverlay = null;
|
|
2092
1912
|
/** Data received from SDK initialization */
|
|
2093
1913
|
initData = null;
|
|
1914
|
+
/** Platform session (SDK + optional DevBridge). null until start() runs. */
|
|
1915
|
+
platformSession = null;
|
|
2094
1916
|
/** Configuration */
|
|
2095
1917
|
config;
|
|
2096
1918
|
// ─── Private state ──────────────────────────────────────
|
|
@@ -2147,7 +1969,7 @@ class GameApplication extends EventEmitter {
|
|
|
2147
1969
|
// 1. Resolve container element
|
|
2148
1970
|
this._container = this.resolveContainer();
|
|
2149
1971
|
// 2. Show CSS preloader immediately (before PixiJS)
|
|
2150
|
-
createCSSPreloader(this._container, this.config.loading);
|
|
1972
|
+
loading.createCSSPreloader(this._container, this.config.loading);
|
|
2151
1973
|
// 3. Initialize PixiJS
|
|
2152
1974
|
await this.initPixi();
|
|
2153
1975
|
// 4. Initialize SDK (if enabled)
|
|
@@ -2158,7 +1980,7 @@ class GameApplication extends EventEmitter {
|
|
|
2158
1980
|
this.initSubSystems();
|
|
2159
1981
|
this.emit('initialized');
|
|
2160
1982
|
// 7. Remove CSS preloader, show Canvas loading screen
|
|
2161
|
-
removeCSSPreloader(this._container);
|
|
1983
|
+
loading.removeCSSPreloader(this._container);
|
|
2162
1984
|
// 8. Load assets with loading screen
|
|
2163
1985
|
await this.loadAssets(firstScene, sceneData);
|
|
2164
1986
|
this.emit('loaded');
|
|
@@ -2184,7 +2006,7 @@ class GameApplication extends EventEmitter {
|
|
|
2184
2006
|
this.input?.destroy();
|
|
2185
2007
|
this.audio?.destroy();
|
|
2186
2008
|
this.viewport?.destroy();
|
|
2187
|
-
this.
|
|
2009
|
+
this.platformSession?.destroy();
|
|
2188
2010
|
this.app?.destroy(true, { children: true, texture: true });
|
|
2189
2011
|
this.emit('destroyed');
|
|
2190
2012
|
this.removeAllListeners();
|
|
@@ -2220,20 +2042,15 @@ class GameApplication extends EventEmitter {
|
|
|
2220
2042
|
this.app.canvas.style.height = '100%';
|
|
2221
2043
|
}
|
|
2222
2044
|
async initSDK() {
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
this.sdk = new gameSdk.CasinoGameSDK(sdkOpts);
|
|
2230
|
-
// Perform the handshake
|
|
2231
|
-
this.initData = await this.sdk.ready();
|
|
2232
|
-
// Forward SDK events
|
|
2233
|
-
this.sdk.on('error', (err) => {
|
|
2045
|
+
// Delegate the SDK handshake (and any optional in-process DevBridge
|
|
2046
|
+
// wiring) to platform-core. The session forwards SDK events upward.
|
|
2047
|
+
this.platformSession = await platformCore.createPlatformSession({ sdk: this.config.sdk });
|
|
2048
|
+
this.sdk = this.platformSession.sdk;
|
|
2049
|
+
this.initData = this.platformSession.initData;
|
|
2050
|
+
this.platformSession.on('error', (err) => {
|
|
2234
2051
|
this.emit('error', err);
|
|
2235
2052
|
});
|
|
2236
|
-
this.
|
|
2053
|
+
this.platformSession.on('balanceUpdate', (data) => {
|
|
2237
2054
|
this.emit('balanceUpdate', data);
|
|
2238
2055
|
});
|
|
2239
2056
|
}
|
|
@@ -5235,237 +5052,6 @@ class ScrollContainer extends pixi_js.Container {
|
|
|
5235
5052
|
}
|
|
5236
5053
|
}
|
|
5237
5054
|
|
|
5238
|
-
const DEFAULT_CONFIG = {
|
|
5239
|
-
balance: 10000,
|
|
5240
|
-
currency: 'USD',
|
|
5241
|
-
gameConfig: {
|
|
5242
|
-
id: 'dev-game',
|
|
5243
|
-
type: 'slot',
|
|
5244
|
-
version: '1.0.0',
|
|
5245
|
-
viewport: { width: 1920, height: 1080 },
|
|
5246
|
-
betLevels: [0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50],
|
|
5247
|
-
},
|
|
5248
|
-
assetsUrl: '/assets/',
|
|
5249
|
-
session: null,
|
|
5250
|
-
onPlay: () => ({}),
|
|
5251
|
-
networkDelay: 200,
|
|
5252
|
-
debug: true,
|
|
5253
|
-
};
|
|
5254
|
-
/**
|
|
5255
|
-
* Mock host bridge for local development.
|
|
5256
|
-
*
|
|
5257
|
-
* Uses the SDK's `Bridge` class in `devMode` to communicate with
|
|
5258
|
-
* `CasinoGameSDK` via a shared in-memory `MemoryChannel`, removing
|
|
5259
|
-
* the need for postMessage and iframes.
|
|
5260
|
-
*
|
|
5261
|
-
* When `luaScript` is set, play requests are sent to the Vite dev server
|
|
5262
|
-
* which runs LuaEngine in Node.js — no fengari in the browser.
|
|
5263
|
-
*
|
|
5264
|
-
* @example
|
|
5265
|
-
* ```ts
|
|
5266
|
-
* import { DevBridge } from '@energy8platform/game-engine/debug';
|
|
5267
|
-
*
|
|
5268
|
-
* const devBridge = new DevBridge({
|
|
5269
|
-
* balance: 5000,
|
|
5270
|
-
* currency: 'EUR',
|
|
5271
|
-
* gameConfig: { id: 'my-slot', type: 'slot', betLevels: [0.2, 0.5, 1, 2] },
|
|
5272
|
-
* onPlay: ({ action, bet }) => ({
|
|
5273
|
-
* totalWin: Math.random() > 0.5 ? bet * (Math.random() * 20) : 0,
|
|
5274
|
-
* data: { matrix: [[1,2,3],[4,5,6],[7,8,9]] },
|
|
5275
|
-
* }),
|
|
5276
|
-
* });
|
|
5277
|
-
* devBridge.start();
|
|
5278
|
-
* ```
|
|
5279
|
-
*/
|
|
5280
|
-
class DevBridge {
|
|
5281
|
-
_config;
|
|
5282
|
-
_balance;
|
|
5283
|
-
_roundCounter = 0;
|
|
5284
|
-
_bridge = null;
|
|
5285
|
-
_useLuaServer;
|
|
5286
|
-
constructor(config = {}) {
|
|
5287
|
-
this._config = { ...DEFAULT_CONFIG, ...config };
|
|
5288
|
-
this._balance = this._config.balance;
|
|
5289
|
-
this._useLuaServer = !!(this._config.luaScript && this._config.gameDefinition);
|
|
5290
|
-
}
|
|
5291
|
-
/** Current mock balance */
|
|
5292
|
-
get balance() {
|
|
5293
|
-
return this._balance;
|
|
5294
|
-
}
|
|
5295
|
-
/** Start listening for SDK messages */
|
|
5296
|
-
start() {
|
|
5297
|
-
if (this._bridge)
|
|
5298
|
-
return;
|
|
5299
|
-
console.debug('[DevBridge] Starting with config:', this._config);
|
|
5300
|
-
this._bridge = new gameSdk.Bridge({ devMode: true, debug: this._config.debug });
|
|
5301
|
-
this._bridge.on('GAME_READY', (_payload, id) => {
|
|
5302
|
-
this.handleGameReady(id);
|
|
5303
|
-
});
|
|
5304
|
-
this._bridge.on('PLAY_REQUEST', (payload, id) => {
|
|
5305
|
-
this.handlePlayRequest(payload, id);
|
|
5306
|
-
});
|
|
5307
|
-
this._bridge.on('PLAY_RESULT_ACK', (payload) => {
|
|
5308
|
-
this.handlePlayAck(payload);
|
|
5309
|
-
});
|
|
5310
|
-
this._bridge.on('GET_BALANCE', (_payload, id) => {
|
|
5311
|
-
this.handleGetBalance(id);
|
|
5312
|
-
});
|
|
5313
|
-
this._bridge.on('GET_STATE', (_payload, id) => {
|
|
5314
|
-
this.handleGetState(id);
|
|
5315
|
-
});
|
|
5316
|
-
this._bridge.on('OPEN_DEPOSIT', () => {
|
|
5317
|
-
this.handleOpenDeposit();
|
|
5318
|
-
});
|
|
5319
|
-
if (this._config.debug) {
|
|
5320
|
-
const mode = this._useLuaServer ? 'Lua (server-side)' : 'onPlay callback';
|
|
5321
|
-
console.log(`[DevBridge] Started — mode: ${mode}`);
|
|
5322
|
-
}
|
|
5323
|
-
}
|
|
5324
|
-
/** Stop listening */
|
|
5325
|
-
stop() {
|
|
5326
|
-
if (this._bridge) {
|
|
5327
|
-
this._bridge.destroy();
|
|
5328
|
-
this._bridge = null;
|
|
5329
|
-
}
|
|
5330
|
-
if (this._config.debug) {
|
|
5331
|
-
console.log('[DevBridge] Stopped');
|
|
5332
|
-
}
|
|
5333
|
-
}
|
|
5334
|
-
/** Set mock balance */
|
|
5335
|
-
setBalance(balance) {
|
|
5336
|
-
this._balance = balance;
|
|
5337
|
-
this._bridge?.send('BALANCE_UPDATE', { balance: this._balance });
|
|
5338
|
-
}
|
|
5339
|
-
/** Destroy the dev bridge */
|
|
5340
|
-
destroy() {
|
|
5341
|
-
this.stop();
|
|
5342
|
-
}
|
|
5343
|
-
// ─── Message Handling ──────────────────────────────────
|
|
5344
|
-
handleGameReady(id) {
|
|
5345
|
-
const initData = {
|
|
5346
|
-
balance: this._balance,
|
|
5347
|
-
currency: this._config.currency,
|
|
5348
|
-
config: this._config.gameConfig,
|
|
5349
|
-
session: this._config.session,
|
|
5350
|
-
assetsUrl: this._config.assetsUrl,
|
|
5351
|
-
};
|
|
5352
|
-
this.delayedSend('INIT', initData, id);
|
|
5353
|
-
}
|
|
5354
|
-
handlePlayRequest(payload, id) {
|
|
5355
|
-
const { action, bet, roundId, params } = payload;
|
|
5356
|
-
this._roundCounter++;
|
|
5357
|
-
if (this._useLuaServer) {
|
|
5358
|
-
// Debit bet (server deducts before Lua execution)
|
|
5359
|
-
// For session actions (free spins), debit is 0 — LuaEngine handles bet from session
|
|
5360
|
-
this._balance -= bet;
|
|
5361
|
-
this.executeLuaOnServer({ action, bet, roundId, params })
|
|
5362
|
-
.then((result) => {
|
|
5363
|
-
this._bridge?.send('PLAY_RESULT', result, id);
|
|
5364
|
-
})
|
|
5365
|
-
.catch((err) => {
|
|
5366
|
-
console.error('[DevBridge] Lua server error:', err);
|
|
5367
|
-
this._balance += bet;
|
|
5368
|
-
this._bridge?.send('PLAY_RESULT', this.buildFallbackResult(action, bet, roundId), id);
|
|
5369
|
-
});
|
|
5370
|
-
}
|
|
5371
|
-
else {
|
|
5372
|
-
// Fallback to onPlay callback
|
|
5373
|
-
const customResult = this._config.onPlay({ action, bet, roundId, params });
|
|
5374
|
-
const totalWin = customResult.totalWin ?? (Math.random() > 0.6 ? bet * (1 + Math.random() * 10) : 0);
|
|
5375
|
-
this._balance += totalWin;
|
|
5376
|
-
const result = {
|
|
5377
|
-
roundId: roundId ?? `dev-round-${this._roundCounter}`,
|
|
5378
|
-
action,
|
|
5379
|
-
balanceAfter: this._balance,
|
|
5380
|
-
totalWin: Math.round(totalWin * 100) / 100,
|
|
5381
|
-
data: customResult.data ?? {},
|
|
5382
|
-
nextActions: customResult.nextActions ?? ['spin'],
|
|
5383
|
-
session: customResult.session ?? null,
|
|
5384
|
-
creditPending: false,
|
|
5385
|
-
bonusFreeSpin: customResult.bonusFreeSpin ?? null,
|
|
5386
|
-
currency: this._config.currency,
|
|
5387
|
-
gameId: this._config.gameConfig?.id ?? 'dev-game',
|
|
5388
|
-
};
|
|
5389
|
-
this.delayedSend('PLAY_RESULT', result, id);
|
|
5390
|
-
}
|
|
5391
|
-
}
|
|
5392
|
-
async executeLuaOnServer(params) {
|
|
5393
|
-
const response = await fetch('/__lua-play', {
|
|
5394
|
-
method: 'POST',
|
|
5395
|
-
headers: { 'Content-Type': 'application/json' },
|
|
5396
|
-
body: JSON.stringify(params),
|
|
5397
|
-
});
|
|
5398
|
-
if (!response.ok) {
|
|
5399
|
-
const err = await response.json().catch(() => ({ error: 'Unknown error' }));
|
|
5400
|
-
throw new Error(err.error ?? `HTTP ${response.status}`);
|
|
5401
|
-
}
|
|
5402
|
-
const luaResult = await response.json();
|
|
5403
|
-
// Server credit logic:
|
|
5404
|
-
// shouldCredit = (no session) OR (session.completed)
|
|
5405
|
-
// creditAmount = result.totalWin
|
|
5406
|
-
const shouldCredit = !luaResult.session || luaResult.session.completed;
|
|
5407
|
-
if (shouldCredit && luaResult.totalWin > 0) {
|
|
5408
|
-
this._balance += luaResult.totalWin;
|
|
5409
|
-
}
|
|
5410
|
-
return {
|
|
5411
|
-
roundId: params.roundId ?? `dev-round-${this._roundCounter}`,
|
|
5412
|
-
action: params.action,
|
|
5413
|
-
balanceAfter: this._balance,
|
|
5414
|
-
totalWin: Math.round(luaResult.totalWin * 100) / 100,
|
|
5415
|
-
data: luaResult.data,
|
|
5416
|
-
nextActions: luaResult.nextActions,
|
|
5417
|
-
session: luaResult.session,
|
|
5418
|
-
creditPending: !shouldCredit,
|
|
5419
|
-
bonusFreeSpin: null,
|
|
5420
|
-
currency: this._config.currency,
|
|
5421
|
-
gameId: this._config.gameConfig?.id ?? 'dev-game',
|
|
5422
|
-
};
|
|
5423
|
-
}
|
|
5424
|
-
buildFallbackResult(action, bet, roundId) {
|
|
5425
|
-
return {
|
|
5426
|
-
roundId: roundId ?? `dev-round-${this._roundCounter}`,
|
|
5427
|
-
action,
|
|
5428
|
-
balanceAfter: this._balance,
|
|
5429
|
-
totalWin: 0,
|
|
5430
|
-
data: { error: 'Lua execution failed' },
|
|
5431
|
-
nextActions: ['spin'],
|
|
5432
|
-
session: null,
|
|
5433
|
-
creditPending: false,
|
|
5434
|
-
bonusFreeSpin: null,
|
|
5435
|
-
currency: this._config.currency,
|
|
5436
|
-
gameId: this._config.gameConfig?.id ?? 'dev-game',
|
|
5437
|
-
};
|
|
5438
|
-
}
|
|
5439
|
-
handlePlayAck(_payload) {
|
|
5440
|
-
if (this._config.debug) {
|
|
5441
|
-
console.log('[DevBridge] Play acknowledged');
|
|
5442
|
-
}
|
|
5443
|
-
}
|
|
5444
|
-
handleGetBalance(id) {
|
|
5445
|
-
this.delayedSend('BALANCE_UPDATE', { balance: this._balance }, id);
|
|
5446
|
-
}
|
|
5447
|
-
handleGetState(id) {
|
|
5448
|
-
this.delayedSend('STATE_RESPONSE', { session: this._config.session ?? null }, id);
|
|
5449
|
-
}
|
|
5450
|
-
handleOpenDeposit() {
|
|
5451
|
-
if (this._config.debug) {
|
|
5452
|
-
console.log('[DevBridge] Open deposit requested (mock: adding 1000)');
|
|
5453
|
-
}
|
|
5454
|
-
this._balance += 1000;
|
|
5455
|
-
this._bridge?.send('BALANCE_UPDATE', { balance: this._balance });
|
|
5456
|
-
}
|
|
5457
|
-
// ─── Communication ─────────────────────────────────────
|
|
5458
|
-
delayedSend(type, payload, id) {
|
|
5459
|
-
const delay = this._config.networkDelay;
|
|
5460
|
-
if (delay > 0) {
|
|
5461
|
-
setTimeout(() => this._bridge?.send(type, payload, id), delay);
|
|
5462
|
-
}
|
|
5463
|
-
else {
|
|
5464
|
-
this._bridge?.send(type, payload, id);
|
|
5465
|
-
}
|
|
5466
|
-
}
|
|
5467
|
-
}
|
|
5468
|
-
|
|
5469
5055
|
Object.defineProperty(exports, "BridgeDestroyedError", {
|
|
5470
5056
|
enumerable: true,
|
|
5471
5057
|
get: function () { return gameSdk.BridgeDestroyedError; }
|
|
@@ -5482,11 +5068,14 @@ Object.defineProperty(exports, "TimeoutError", {
|
|
|
5482
5068
|
enumerable: true,
|
|
5483
5069
|
get: function () { return gameSdk.TimeoutError; }
|
|
5484
5070
|
});
|
|
5071
|
+
Object.defineProperty(exports, "DevBridge", {
|
|
5072
|
+
enumerable: true,
|
|
5073
|
+
get: function () { return devBridge.DevBridge; }
|
|
5074
|
+
});
|
|
5485
5075
|
exports.AssetManager = AssetManager;
|
|
5486
5076
|
exports.AudioManager = AudioManager;
|
|
5487
5077
|
exports.BalanceDisplay = BalanceDisplay;
|
|
5488
5078
|
exports.Button = Button;
|
|
5489
|
-
exports.DevBridge = DevBridge;
|
|
5490
5079
|
exports.Easing = Easing;
|
|
5491
5080
|
exports.EventEmitter = EventEmitter;
|
|
5492
5081
|
exports.FPSOverlay = FPSOverlay;
|