@energy8platform/game-engine 0.43.3 → 0.43.5
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/host.cjs.js +62 -22
- package/dist/host.cjs.js.map +1 -1
- package/dist/host.esm.js +62 -22
- package/dist/host.esm.js.map +1 -1
- package/package.json +2 -2
- package/src/host/autoplay.ts +58 -17
- package/src/host/connectionRecovery.ts +21 -7
- package/src/host/createSlotGame.ts +19 -3
- package/src/host/shellConfig.ts +1 -1
package/dist/host.esm.js
CHANGED
|
@@ -2852,6 +2852,8 @@ async function createSlotGame(opts) {
|
|
|
2852
2852
|
let playErrorOpen = false;
|
|
2853
2853
|
let stopAutoplay = () => { }; // wired to the autoplay loop once it's created (below)
|
|
2854
2854
|
let haltAutoplay = () => { }; // ditto — stops the run but KEEPS its counter
|
|
2855
|
+
let holdAutoplay = () => { }; // ditto — pauses the run, owing it a resume
|
|
2856
|
+
let releaseAutoplay = () => { }; // ditto — gives back a run that hold() paused
|
|
2855
2857
|
const reload = () => {
|
|
2856
2858
|
try {
|
|
2857
2859
|
window.location.reload();
|
|
@@ -2895,6 +2897,9 @@ async function createSlotGame(opts) {
|
|
|
2895
2897
|
const { createConnectionRecovery } = await Promise.resolve().then(function () { return connectionRecovery; });
|
|
2896
2898
|
const connection = createConnectionRecovery({
|
|
2897
2899
|
haltAutoplay: () => haltAutoplay(),
|
|
2900
|
+
// A reconnect ends the run for good (Artube): the counter the halt preserved while the link
|
|
2901
|
+
// was down is cleared here, and the disc goes back to a plain SPIN.
|
|
2902
|
+
resetAutoplay: () => stopAutoplay(),
|
|
2898
2903
|
showReconnecting: () => shell.openModal({
|
|
2899
2904
|
availableClose: false,
|
|
2900
2905
|
title: shell.t('Reconnecting…'),
|
|
@@ -2936,8 +2941,10 @@ async function createSlotGame(opts) {
|
|
|
2936
2941
|
game.scenes.root.eventMode = 'static';
|
|
2937
2942
|
game.scenes.root.on('pointertap', () => skip.tap(performance.now()));
|
|
2938
2943
|
// Full auto-pause: on tab blur, freeze the ticker (stops tweens/onUpdate/in-flight onSpin),
|
|
2939
|
-
// duck music to silence, hold autoplay, and notify the scene. On focus, reverse it all
|
|
2940
|
-
//
|
|
2944
|
+
// duck music to silence, hold autoplay, and notify the scene. On focus, reverse it all —
|
|
2945
|
+
// autoplay included: a tab switch is not the player pressing STOP.
|
|
2946
|
+
// `holdAutoplay`/`releaseAutoplay` are reassigned in the base-mode block below — the closures
|
|
2947
|
+
// read them live.
|
|
2941
2948
|
const { createPauseController } = await Promise.resolve().then(function () { return pauseController; });
|
|
2942
2949
|
createPauseController({
|
|
2943
2950
|
isHidden: () => typeof document !== 'undefined' && document.hidden,
|
|
@@ -2950,12 +2957,19 @@ async function createSlotGame(opts) {
|
|
|
2950
2957
|
onHidden: () => {
|
|
2951
2958
|
game.app.ticker.stop(); // freezes tweens, onUpdate, in-flight onSpin animation
|
|
2952
2959
|
game.audio.duckMusic(0); // silence music (ducked to 0; restored on resume)
|
|
2953
|
-
|
|
2960
|
+
// Hold, don't stop. No auto-round may start while the tab is hidden (the ticker is frozen,
|
|
2961
|
+
// so an animation would never finish, and a play fired here spends the player's money out
|
|
2962
|
+
// of sight) — but the run is owed back: the lab reads "the autoplay sequence stops when the
|
|
2963
|
+
// Stop button is pressed" as ONLY the Stop button, and stopAutoplay() here ended the run and
|
|
2964
|
+
// zeroed its counter on every alt-tab. `hold()` forgets itself if anything else ends the run
|
|
2965
|
+
// meanwhile (a lost connection, a failed round), so those don't come back on the way in.
|
|
2966
|
+
holdAutoplay();
|
|
2954
2967
|
gameScene()?.onPause?.();
|
|
2955
2968
|
},
|
|
2956
2969
|
onVisible: () => {
|
|
2957
2970
|
game.app.ticker.start();
|
|
2958
2971
|
game.audio.unduckMusic();
|
|
2972
|
+
releaseAutoplay(); // the run the blur paused picks up where it left off
|
|
2959
2973
|
gameScene()?.onResume?.();
|
|
2960
2974
|
},
|
|
2961
2975
|
});
|
|
@@ -3172,6 +3186,8 @@ async function createSlotGame(opts) {
|
|
|
3172
3186
|
});
|
|
3173
3187
|
stopAutoplay = () => autoplay$1.stop();
|
|
3174
3188
|
haltAutoplay = () => autoplay$1.halt();
|
|
3189
|
+
holdAutoplay = () => autoplay$1.hold();
|
|
3190
|
+
releaseAutoplay = () => autoplay$1.release();
|
|
3175
3191
|
shell.on('autoplayStart', (o) => autoplay$1.start(o?.remaining ?? 0));
|
|
3176
3192
|
shell.on('autoplayStop', () => autoplay$1.stop());
|
|
3177
3193
|
// Resume offer: when the game scene is (or becomes) current on a reload, ask the host whether
|
|
@@ -3397,7 +3413,7 @@ const DISCLAIMER_TITLE = 'DISCLAIMER';
|
|
|
3397
3413
|
/** The copyright/brand line ("TM and © {year} Engine.") is shown verbatim; the legal body
|
|
3398
3414
|
* lines localize. Detecting the brand keeps " Engine" out of the translation lookup entirely. */
|
|
3399
3415
|
function isBrandLine(line) {
|
|
3400
|
-
return /
|
|
3416
|
+
return /engine/i.test(line);
|
|
3401
3417
|
}
|
|
3402
3418
|
/** A disclaimer section from initData's disclaimer lines; null when none supplied. The legal body is
|
|
3403
3419
|
* run through `t` so it localizes per language, EXCEPT the brand line, which stays verbatim. The
|
|
@@ -4225,6 +4241,9 @@ function createConnectionRecovery(deps) {
|
|
|
4225
4241
|
if (!linkLost)
|
|
4226
4242
|
return; // nothing of ours is on screen; nothing of ours to recover
|
|
4227
4243
|
linkLost = false;
|
|
4244
|
+
// The run does not resume across a reconnect. Like the halt above, this runs even when a
|
|
4245
|
+
// modal owns the screen — the counter must not outlive the drop that ended the run.
|
|
4246
|
+
deps.resetAutoplay();
|
|
4228
4247
|
if (!blocked())
|
|
4229
4248
|
deps.dismiss();
|
|
4230
4249
|
await recover();
|
|
@@ -4394,7 +4413,9 @@ function createAutoplayLoop(deps) {
|
|
|
4394
4413
|
let active = false;
|
|
4395
4414
|
let remaining = 0;
|
|
4396
4415
|
let running = false; // guards against a second concurrent loop
|
|
4416
|
+
let held = false; // a hold() is outstanding — the tab is hidden and the run is owed a resume
|
|
4397
4417
|
const stop = () => {
|
|
4418
|
+
held = false;
|
|
4398
4419
|
if (!active && remaining === 0)
|
|
4399
4420
|
return;
|
|
4400
4421
|
active = false;
|
|
@@ -4402,6 +4423,7 @@ function createAutoplayLoop(deps) {
|
|
|
4402
4423
|
deps.onState({ active: false, remaining: 0 });
|
|
4403
4424
|
};
|
|
4404
4425
|
const halt = () => {
|
|
4426
|
+
held = false; // whatever is halting the run outranks a pending hold — see hold()'s doc comment
|
|
4405
4427
|
if (!active)
|
|
4406
4428
|
return; // nothing running — nothing to preserve
|
|
4407
4429
|
active = false;
|
|
@@ -4438,27 +4460,45 @@ function createAutoplayLoop(deps) {
|
|
|
4438
4460
|
running = false;
|
|
4439
4461
|
}
|
|
4440
4462
|
}
|
|
4463
|
+
const start = (count) => {
|
|
4464
|
+
if (active || count <= 0)
|
|
4465
|
+
return;
|
|
4466
|
+
held = false; // a run that is starting is no longer one that owes a resume
|
|
4467
|
+
active = true;
|
|
4468
|
+
remaining = count;
|
|
4469
|
+
deps.onState({ active: true, remaining });
|
|
4470
|
+
// `running` bars a SECOND loop, not a new run. After stop(), the round already in flight keeps
|
|
4471
|
+
// animating and the loop stays parked on `await playRound`, so `running` is still true for as
|
|
4472
|
+
// long as that takes — several seconds through a win. Bailing here made the restart a silent
|
|
4473
|
+
// no-op, and silent is what hurt: ShellController.startAutoplay has already lit the disc with
|
|
4474
|
+
// the chosen count, so the player saw autoplay running with a counter that never moved.
|
|
4475
|
+
// The parked loop re-reads `active`/`remaining` on its next turn and simply carries on with
|
|
4476
|
+
// the new budget — no second loop, nothing dropped.
|
|
4477
|
+
if (!running)
|
|
4478
|
+
void loop();
|
|
4479
|
+
};
|
|
4441
4480
|
return {
|
|
4442
|
-
start
|
|
4443
|
-
if (active || count <= 0)
|
|
4444
|
-
return;
|
|
4445
|
-
active = true;
|
|
4446
|
-
remaining = count;
|
|
4447
|
-
deps.onState({ active: true, remaining });
|
|
4448
|
-
// `running` bars a SECOND loop, not a new run. After stop(), the round already in flight keeps
|
|
4449
|
-
// animating and the loop stays parked on `await playRound`, so `running` is still true for as
|
|
4450
|
-
// long as that takes — several seconds through a win. Bailing here made the restart a silent
|
|
4451
|
-
// no-op, and silent is what hurt: ShellController.startAutoplay has already lit the disc with
|
|
4452
|
-
// the chosen count, so the player saw autoplay running with a counter that never moved.
|
|
4453
|
-
// The parked loop re-reads `active`/`remaining` on its next turn and simply carries on with
|
|
4454
|
-
// the new budget — no second loop, nothing dropped.
|
|
4455
|
-
if (!running)
|
|
4456
|
-
void loop();
|
|
4457
|
-
},
|
|
4481
|
+
start,
|
|
4458
4482
|
stop,
|
|
4459
4483
|
halt,
|
|
4460
|
-
|
|
4461
|
-
|
|
4484
|
+
hold() {
|
|
4485
|
+
if (!active)
|
|
4486
|
+
return; // nothing running — nothing to hold, and nothing to bring back
|
|
4487
|
+
halt(); // clears `held`; we set it again below, so only a hold() ever leaves it set
|
|
4488
|
+
held = true;
|
|
4489
|
+
},
|
|
4490
|
+
release() {
|
|
4491
|
+
if (!held)
|
|
4492
|
+
return;
|
|
4493
|
+
held = false;
|
|
4494
|
+
start(remaining); // no-op when the remainder is gone (something retired it while hidden)
|
|
4495
|
+
},
|
|
4496
|
+
get active() {
|
|
4497
|
+
return active;
|
|
4498
|
+
},
|
|
4499
|
+
get remaining() {
|
|
4500
|
+
return remaining;
|
|
4501
|
+
},
|
|
4462
4502
|
};
|
|
4463
4503
|
}
|
|
4464
4504
|
|