@futdevpro/fsm-dynamo 1.20.103 → 1.20.105
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/build/_models/control-models/data-property-params.control-model.js +1 -1
- package/build/_models/control-models/data-property-params.control-model.js.map +1 -1
- package/build/_models/control-models/data-property-settings.control-model.d.ts +7 -0
- package/build/_models/control-models/data-property-settings.control-model.d.ts.map +1 -1
- package/build/_models/control-models/data-property-settings.control-model.js +7 -0
- package/build/_models/control-models/data-property-settings.control-model.js.map +1 -1
- package/build/_modules/game/_models/narration-player.control-model.d.ts +53 -0
- package/build/_modules/game/_models/narration-player.control-model.d.ts.map +1 -0
- package/build/_modules/game/_models/narration-player.control-model.js +223 -0
- package/build/_modules/game/_models/narration-player.control-model.js.map +1 -0
- package/build/_modules/game/_models/narration-player.interface.d.ts +64 -0
- package/build/_modules/game/_models/narration-player.interface.d.ts.map +1 -0
- package/build/_modules/game/_models/narration-player.interface.js +3 -0
- package/build/_modules/game/_models/narration-player.interface.js.map +1 -0
- package/build/_modules/game/index.d.ts +2 -0
- package/build/_modules/game/index.d.ts.map +1 -1
- package/build/_modules/game/index.js +2 -0
- package/build/_modules/game/index.js.map +1 -1
- package/build-esm/_models/control-models/data-property-params.control-model.js +1 -1
- package/build-esm/_models/control-models/data-property-settings.control-model.js +7 -0
- package/build-esm/_modules/game/_models/narration-player.control-model.js +218 -0
- package/build-esm/_modules/game/_models/narration-player.interface.js +1 -0
- package/build-esm/_modules/game/index.js +2 -0
- package/package.json +1 -1
|
@@ -36,7 +36,7 @@ class DyFM_DataPropertyParams_ControlModel extends data_property_settings_contro
|
|
|
36
36
|
`\n stackLocation: ${(0, stack_util_1.DyFM_getConstructionStackLocation)(2)}`);
|
|
37
37
|
}
|
|
38
38
|
if (set.dependencyDataName) {
|
|
39
|
-
if (set.required === false) {
|
|
39
|
+
if (set.required === false && !set.isOptionalDependency) {
|
|
40
40
|
log_util_1.DyFM_Log.warn('DYNAMO WARNING: ', `\n required is not recommended to be false if dependency is set at "${set.key}" in ` +
|
|
41
41
|
`"${parentDataParams?.dataName}" model.` +
|
|
42
42
|
`\n stackLocation: ${(0, stack_util_1.DyFM_getConstructionStackLocation)(2)}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-property-params.control-model.js","sourceRoot":"","sources":["../../../src/_models/control-models/data-property-params.control-model.ts"],"names":[],"mappings":";;;AAAA,gEAA6D;AAC7D,oEAAwF;AACxF,oFAAgF;AAEhF,iGAAoF;AAUpF,qFAAqF;AAErF;6DAC6D;AAC7D;;;;;;;;;;;GAWG;AACH,MAAa,oCACX,SAAQ,iEAA8C;IACtD;QACE,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED,mEAAmE;IACnE,0DAA0D;IAEjD,oBAAoB,GAA2D,EAAE,CAAC;IAE3F,YACE,GAAmD,EACnD,gBAA6C;QAE7C,KAAK,EAAE,CAAC;QAER,IAAI,GAAG,EAAE,CAAC;YACR,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;gBAChC,mBAAQ,CAAC,KAAK,CACZ,gBAAgB,EAChB,2DAA2D,GAAG,CAAC,GAAG,OAAO;oBACvE,IAAI,gBAAgB,EAAE,QAAQ,UAAU;oBAC1C,qBAAqB,IAAA,8CAAiC,EAAC,CAAC,CAAC,EAAE,CAC5D,CAAC;YACJ,CAAC;YAED,IAAI,GAAG,CAAC,kBAAkB,EAAE,CAAC;gBAC3B,IAAI,GAAG,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"data-property-params.control-model.js","sourceRoot":"","sources":["../../../src/_models/control-models/data-property-params.control-model.ts"],"names":[],"mappings":"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"}
|
|
@@ -26,6 +26,13 @@ export declare class DyFM_DataPropertySettings_ControlModel<T_Property, T_Data>
|
|
|
26
26
|
encrypt?: DyFM_DeprecatedBooleanAlias;
|
|
27
27
|
isEncrypted?: boolean;
|
|
28
28
|
dependencyDataName?: string;
|
|
29
|
+
/**
|
|
30
|
+
* The dependency is DELIBERATELY optional (`required: false` + `dependencyDataName`) — e.g. an anonymous feedback
|
|
31
|
+
* whose owner account may be missing, yet "my feedbacks" still lists by it. Silences the "required is not
|
|
32
|
+
* recommended to be false" warning, which otherwise printed on every boot of every consumer (measured 2026-09-25:
|
|
33
|
+
* every `fdp` command, after the feedback model's owner became optional in BFR-FUTDEVPRO-033).
|
|
34
|
+
*/
|
|
35
|
+
isOptionalDependency?: boolean;
|
|
29
36
|
/** @deprecated Use isArchiveable; archiveable remains the serialized compatibility key. */
|
|
30
37
|
archiveable?: DyFM_DeprecatedBooleanAlias;
|
|
31
38
|
isArchiveable?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-property-settings.control-model.d.ts","sourceRoot":"","sources":["../../../src/_models/control-models/data-property-settings.control-model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAChF,OAAO,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AACrF,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAE3E,+DAA+D;AAC/D,qBAAa,sCAAsC,CAAC,UAAU,EAAE,MAAM;IAKpE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAG,uBAAuB,GAAG,MAAM,CAAC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,UAAU,CAAC;IAErB,iFAAiF;IACjF,MAAM,CAAC,EAAE,2BAA2B,CAAC;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC3B,qFAAqF;IACrF,QAAQ,CAAC,EAAE,2BAA2B,CAAC;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAC;IAC7B,qFAAqF;IACrF,QAAQ,CAAC,EAAE,2BAA2B,CAAC;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAC;IAC7B,iFAAiF;IACjF,KAAK,CAAC,EAAE,2BAA2B,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IAC5B,uFAAuF;IACvF,SAAS,CAAC,EAAE,2BAA2B,CAAC;IAChC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC9B,qFAAqF;IACrF,OAAO,CAAC,EAAE,2BAA2B,CAAC;IAC9B,WAAW,CAAC,EAAE,OAAO,CAAC;IAE9B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,2FAA2F;IAC3F,WAAW,CAAC,EAAE,2BAA2B,CAAC;IAClC,aAAa,CAAC,EAAE,OAAO,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oGAAoG;IACpG,eAAe,CAAC,EAAE,2BAA2B,CAAC;IACtC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IACrC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,mBAAmB,CAAC,GAAG,CAAC,CAAC;IAC3C,oBAAoB,CAAC,EAAE,CAAC,CAAC,aAAa,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC,EAAE,CAAC;CAC9E;AA6BD,gGAAgG;AAChG,OAAO,EAAE,sCAAsC,IAAI,0BAA0B,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"data-property-settings.control-model.d.ts","sourceRoot":"","sources":["../../../src/_models/control-models/data-property-settings.control-model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAChF,OAAO,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AACrF,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAE3E,+DAA+D;AAC/D,qBAAa,sCAAsC,CAAC,UAAU,EAAE,MAAM;IAKpE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAG,uBAAuB,GAAG,MAAM,CAAC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,UAAU,CAAC;IAErB,iFAAiF;IACjF,MAAM,CAAC,EAAE,2BAA2B,CAAC;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC3B,qFAAqF;IACrF,QAAQ,CAAC,EAAE,2BAA2B,CAAC;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAC;IAC7B,qFAAqF;IACrF,QAAQ,CAAC,EAAE,2BAA2B,CAAC;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAC;IAC7B,iFAAiF;IACjF,KAAK,CAAC,EAAE,2BAA2B,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IAC5B,uFAAuF;IACvF,SAAS,CAAC,EAAE,2BAA2B,CAAC;IAChC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC9B,qFAAqF;IACrF,OAAO,CAAC,EAAE,2BAA2B,CAAC;IAC9B,WAAW,CAAC,EAAE,OAAO,CAAC;IAE9B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,2FAA2F;IAC3F,WAAW,CAAC,EAAE,2BAA2B,CAAC;IAClC,aAAa,CAAC,EAAE,OAAO,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oGAAoG;IACpG,eAAe,CAAC,EAAE,2BAA2B,CAAC;IACtC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IACrC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,mBAAmB,CAAC,GAAG,CAAC,CAAC;IAC3C,oBAAoB,CAAC,EAAE,CAAC,CAAC,aAAa,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC,EAAE,CAAC;CAC9E;AA6BD,gGAAgG;AAChG,OAAO,EAAE,sCAAsC,IAAI,0BAA0B,EAAE,CAAC"}
|
|
@@ -23,6 +23,13 @@ class DyFM_DataPropertySettings_ControlModel {
|
|
|
23
23
|
/** @deprecated Use isEncrypted; encrypt remains the serialized compatibility key. */
|
|
24
24
|
encrypt;
|
|
25
25
|
dependencyDataName;
|
|
26
|
+
/**
|
|
27
|
+
* The dependency is DELIBERATELY optional (`required: false` + `dependencyDataName`) — e.g. an anonymous feedback
|
|
28
|
+
* whose owner account may be missing, yet "my feedbacks" still lists by it. Silences the "required is not
|
|
29
|
+
* recommended to be false" warning, which otherwise printed on every boot of every consumer (measured 2026-09-25:
|
|
30
|
+
* every `fdp` command, after the feedback model's owner became optional in BFR-FUTDEVPRO-033).
|
|
31
|
+
*/
|
|
32
|
+
isOptionalDependency;
|
|
26
33
|
/** @deprecated Use isArchiveable; archiveable remains the serialized compatibility key. */
|
|
27
34
|
archiveable;
|
|
28
35
|
archiveListAfter;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-property-settings.control-model.js","sourceRoot":"","sources":["../../../src/_models/control-models/data-property-settings.control-model.ts"],"names":[],"mappings":";;;AAIA,+DAA+D;AAC/D,MAAa,sCAAsC;IACjD;QACE,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,4BAA4B,EAAE,CAAC,CAAC;IAC/E,CAAC;IAED,GAAG,CAAU;IACb,IAAI,CAAoC;IACxC,YAAY,CAAU;IACtB,OAAO,CAAc;IAErB,iFAAiF;IACjF,MAAM,CAA+B;IAErC,qFAAqF;IACrF,QAAQ,CAA+B;IAEvC,qFAAqF;IACrF,QAAQ,CAA+B;IAEvC,iFAAiF;IACjF,KAAK,CAA+B;IAEpC,uFAAuF;IACvF,SAAS,CAA+B;IAExC,qFAAqF;IACrF,OAAO,CAA+B;IAGtC,kBAAkB,CAAU;IAC5B,2FAA2F;IAC3F,WAAW,CAA+B;IAE1C,gBAAgB,CAAU;IAC1B,cAAc,CAAY;IAC1B,cAAc,CAAU;IACxB,oGAAoG;IACpG,eAAe,CAA+B;IAE9C,iBAAiB,CAAU;IAC3B,SAAS,CAAU;IACnB,SAAS,CAAU;IACnB,eAAe,CAA4B;IAC3C,oBAAoB,CAAyD;CAC9E;
|
|
1
|
+
{"version":3,"file":"data-property-settings.control-model.js","sourceRoot":"","sources":["../../../src/_models/control-models/data-property-settings.control-model.ts"],"names":[],"mappings":";;;AAIA,+DAA+D;AAC/D,MAAa,sCAAsC;IACjD;QACE,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,4BAA4B,EAAE,CAAC,CAAC;IAC/E,CAAC;IAED,GAAG,CAAU;IACb,IAAI,CAAoC;IACxC,YAAY,CAAU;IACtB,OAAO,CAAc;IAErB,iFAAiF;IACjF,MAAM,CAA+B;IAErC,qFAAqF;IACrF,QAAQ,CAA+B;IAEvC,qFAAqF;IACrF,QAAQ,CAA+B;IAEvC,iFAAiF;IACjF,KAAK,CAA+B;IAEpC,uFAAuF;IACvF,SAAS,CAA+B;IAExC,qFAAqF;IACrF,OAAO,CAA+B;IAGtC,kBAAkB,CAAU;IAC5B;;;;;OAKG;IACH,oBAAoB,CAAW;IAC/B,2FAA2F;IAC3F,WAAW,CAA+B;IAE1C,gBAAgB,CAAU;IAC1B,cAAc,CAAY;IAC1B,cAAc,CAAU;IACxB,oGAAoG;IACpG,eAAe,CAA+B;IAE9C,iBAAiB,CAAU;IAC3B,SAAS,CAAU;IACnB,SAAS,CAAU;IACnB,eAAe,CAA4B;IAC3C,oBAAoB,CAAyD;CAC9E;AAnDD,wFAmDC;AA8BkD,4EAA0B;AA5B7E,MAAM,cAAc,GAA2C;IAC7D,CAAE,QAAQ,EAAE,UAAU,CAAE;IACxB,CAAE,UAAU,EAAE,YAAY,CAAE;IAC5B,CAAE,UAAU,EAAE,YAAY,CAAE;IAC5B,CAAE,OAAO,EAAE,WAAW,CAAE;IACxB,CAAE,WAAW,EAAE,aAAa,CAAE;IAC9B,CAAE,SAAS,EAAE,aAAa,CAAE;IAC5B,CAAE,aAAa,EAAE,eAAe,CAAE;IAClC,CAAE,iBAAiB,EAAE,oBAAoB,CAAE;CAC5C,CAAC;AAEF,cAAc,CAAC,OAAO,CAAC,CAAC,YAAuC,EAAQ,EAAE;IACvE,MAAM,UAAU,GAAW,YAAY,CAAC,CAAC,CAAC,CAAC;IAC3C,MAAM,aAAa,GAAW,YAAY,CAAC,CAAC,CAAC,CAAC;IAE9C,MAAM,CAAC,cAAc,CAAC,sCAAsC,CAAC,SAAS,EAAE,aAAa,EAAE;QACrF,YAAY,EAAE,IAAI;QAClB,UAAU,EAAE,KAAK;QACjB,GAAG,EAAE;YACH,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC;QAC1B,CAAC;QACD,GAAG,EAAE,UAAU,OAA4B;YACzC,IAAI,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC;QAC7B,CAAC;KACF,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { DyFM_NarrationLine, DyFM_NarrationPlayer_Options, DyFM_NarrationState } from './narration-player.interface';
|
|
2
|
+
/**
|
|
3
|
+
* BFR-WARFACTORY-014 — the narration adapter canon (war-factory `Tutorial_Narration_Service` + portalhold voice lines):
|
|
4
|
+
*
|
|
5
|
+
* - **asset-id core**, catalog as an optional layer (`playLine` / `playCatalog`);
|
|
6
|
+
* - `Promise<boolean>` — a refusal is REPORTED, with its reason in `lastRefusal` (disabled · muted · no-gesture ·
|
|
7
|
+
* autoplay-blocked · error · unknown-line) — a narration that silently does not play is undiagnosable;
|
|
8
|
+
* - optional **gesture gate with exposed state** (`sessionActivated`);
|
|
9
|
+
* - **exactly one active line** — every play stops the previous one;
|
|
10
|
+
* - a **staleness guard** (revision counter): a late `ended` / `error` / `play()` rejection of a replaced line never
|
|
11
|
+
* touches the current one;
|
|
12
|
+
* - **`blocked` ≠ `failed`**: a `NotAllowedError` (browser autoplay block) is the case the player must be told about;
|
|
13
|
+
* - `replay()`; optional settings persistence; the subtitle stays available while blocked / failed (text fallback).
|
|
14
|
+
*
|
|
15
|
+
* Framework-agnostic: the audio comes from a factory (`(src) => new Audio(src)` in a browser); a UI layer mirrors
|
|
16
|
+
* `getState()` via `onChange`.
|
|
17
|
+
*/
|
|
18
|
+
export declare class DyFM_NarrationPlayer_ControlModel {
|
|
19
|
+
private readonly options;
|
|
20
|
+
private readonly listeners;
|
|
21
|
+
private audio;
|
|
22
|
+
private revision;
|
|
23
|
+
private lastLine;
|
|
24
|
+
private state;
|
|
25
|
+
constructor(options: DyFM_NarrationPlayer_Options);
|
|
26
|
+
/** A copy of the current state. */
|
|
27
|
+
getState(): DyFM_NarrationState;
|
|
28
|
+
/** Subscribe to state changes; returns the unsubscribe. A throwing listener is logged and isolated. */
|
|
29
|
+
onChange(listener: (state: DyFM_NarrationState) => void): () => void;
|
|
30
|
+
/** Marks a user gesture — from now on automatic narration may play. */
|
|
31
|
+
activate(): void;
|
|
32
|
+
/** Plays a line (automatic path: respects the gesture gate). */
|
|
33
|
+
playLine(line: DyFM_NarrationLine): Promise<boolean>;
|
|
34
|
+
/** Plays a catalog entry; an unknown key refuses with `unknown-line`. */
|
|
35
|
+
playCatalog(key: string): Promise<boolean>;
|
|
36
|
+
/** From a user gesture: activates the session, then plays. */
|
|
37
|
+
activateAndPlay(line: DyFM_NarrationLine): Promise<boolean>;
|
|
38
|
+
/** Replays the last requested line (a replay button is a gesture). */
|
|
39
|
+
replay(): Promise<boolean>;
|
|
40
|
+
/** Stops the active line (or clears a blocked / failed one). */
|
|
41
|
+
stop(): void;
|
|
42
|
+
setEnabled(enabled: boolean): void;
|
|
43
|
+
setVolume(volume: number): void;
|
|
44
|
+
/** Re-applies the effective volume (call it when the game's master volume / mute changes); 0 stops the line. */
|
|
45
|
+
applyVolume(): void;
|
|
46
|
+
private play;
|
|
47
|
+
private detach;
|
|
48
|
+
private effectiveVolume;
|
|
49
|
+
private set;
|
|
50
|
+
private loadSettings;
|
|
51
|
+
private saveSettings;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=narration-player.control-model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"narration-player.control-model.d.ts","sourceRoot":"","sources":["../../../../src/_modules/game/_models/narration-player.control-model.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,kBAAkB,EAClB,4BAA4B,EAE5B,mBAAmB,EACpB,MAAM,8BAA8B,CAAC;AAEtC;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,iCAAiC;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;IACvD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgD;IAC1E,OAAO,CAAC,KAAK,CAA8C;IAC3D,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,KAAK,CAGX;gBAEU,OAAO,EAAE,4BAA4B;IAKjD,mCAAmC;IACnC,QAAQ,IAAI,mBAAmB;IAI/B,uGAAuG;IACvG,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,GAAG,MAAM,IAAI;IAYpE,uEAAuE;IACvE,QAAQ,IAAI,IAAI;IAMhB,gEAAgE;IAC1D,QAAQ,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;IAI1D,yEAAyE;IACnE,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYhD,8DAA8D;IACxD,eAAe,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;IAMjE,sEAAsE;IAChE,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAShC,gEAAgE;IAChE,IAAI,IAAI,IAAI;IAMZ,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAQlC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAM/B,gHAAgH;IAChH,WAAW,IAAI,IAAI;YAWL,IAAI;IA4DlB,OAAO,CAAC,MAAM;IAgBd,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,GAAG;IAcX,OAAO,CAAC,YAAY;IAsBpB,OAAO,CAAC,YAAY;CAYrB"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DyFM_NarrationPlayer_ControlModel = void 0;
|
|
4
|
+
const log_util_1 = require("../../../_collections/utils/log.util");
|
|
5
|
+
/**
|
|
6
|
+
* BFR-WARFACTORY-014 — the narration adapter canon (war-factory `Tutorial_Narration_Service` + portalhold voice lines):
|
|
7
|
+
*
|
|
8
|
+
* - **asset-id core**, catalog as an optional layer (`playLine` / `playCatalog`);
|
|
9
|
+
* - `Promise<boolean>` — a refusal is REPORTED, with its reason in `lastRefusal` (disabled · muted · no-gesture ·
|
|
10
|
+
* autoplay-blocked · error · unknown-line) — a narration that silently does not play is undiagnosable;
|
|
11
|
+
* - optional **gesture gate with exposed state** (`sessionActivated`);
|
|
12
|
+
* - **exactly one active line** — every play stops the previous one;
|
|
13
|
+
* - a **staleness guard** (revision counter): a late `ended` / `error` / `play()` rejection of a replaced line never
|
|
14
|
+
* touches the current one;
|
|
15
|
+
* - **`blocked` ≠ `failed`**: a `NotAllowedError` (browser autoplay block) is the case the player must be told about;
|
|
16
|
+
* - `replay()`; optional settings persistence; the subtitle stays available while blocked / failed (text fallback).
|
|
17
|
+
*
|
|
18
|
+
* Framework-agnostic: the audio comes from a factory (`(src) => new Audio(src)` in a browser); a UI layer mirrors
|
|
19
|
+
* `getState()` via `onChange`.
|
|
20
|
+
*/
|
|
21
|
+
class DyFM_NarrationPlayer_ControlModel {
|
|
22
|
+
options;
|
|
23
|
+
listeners = [];
|
|
24
|
+
audio = null;
|
|
25
|
+
revision = 0;
|
|
26
|
+
lastLine = null;
|
|
27
|
+
state = {
|
|
28
|
+
playback: 'idle', activeLineId: null, subtitle: null, enabled: true, volume: 0.85, sessionActivated: false,
|
|
29
|
+
lastRefusal: null,
|
|
30
|
+
};
|
|
31
|
+
constructor(options) {
|
|
32
|
+
this.options = options;
|
|
33
|
+
this.loadSettings();
|
|
34
|
+
}
|
|
35
|
+
/** A copy of the current state. */
|
|
36
|
+
getState() {
|
|
37
|
+
return { ...this.state };
|
|
38
|
+
}
|
|
39
|
+
/** Subscribe to state changes; returns the unsubscribe. A throwing listener is logged and isolated. */
|
|
40
|
+
onChange(listener) {
|
|
41
|
+
this.listeners.push(listener);
|
|
42
|
+
return () => {
|
|
43
|
+
const index = this.listeners.indexOf(listener);
|
|
44
|
+
if (index >= 0) {
|
|
45
|
+
this.listeners.splice(index, 1);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/** Marks a user gesture — from now on automatic narration may play. */
|
|
50
|
+
activate() {
|
|
51
|
+
if (!this.state.sessionActivated) {
|
|
52
|
+
this.set({ sessionActivated: true });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Plays a line (automatic path: respects the gesture gate). */
|
|
56
|
+
async playLine(line) {
|
|
57
|
+
return this.play(line);
|
|
58
|
+
}
|
|
59
|
+
/** Plays a catalog entry; an unknown key refuses with `unknown-line`. */
|
|
60
|
+
async playCatalog(key) {
|
|
61
|
+
const line = this.options.catalog?.[key];
|
|
62
|
+
if (!line) {
|
|
63
|
+
this.set({ lastRefusal: 'unknown-line' });
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
return this.play(line);
|
|
67
|
+
}
|
|
68
|
+
/** From a user gesture: activates the session, then plays. */
|
|
69
|
+
async activateAndPlay(line) {
|
|
70
|
+
this.activate();
|
|
71
|
+
return this.play(line);
|
|
72
|
+
}
|
|
73
|
+
/** Replays the last requested line (a replay button is a gesture). */
|
|
74
|
+
async replay() {
|
|
75
|
+
if (!this.lastLine) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
this.activate();
|
|
79
|
+
return this.play(this.lastLine);
|
|
80
|
+
}
|
|
81
|
+
/** Stops the active line (or clears a blocked / failed one). */
|
|
82
|
+
stop() {
|
|
83
|
+
this.revision++;
|
|
84
|
+
this.detach();
|
|
85
|
+
this.set({ playback: 'idle', activeLineId: null, subtitle: null });
|
|
86
|
+
}
|
|
87
|
+
setEnabled(enabled) {
|
|
88
|
+
this.set({ enabled: enabled });
|
|
89
|
+
this.saveSettings();
|
|
90
|
+
if (!enabled && this.audio) {
|
|
91
|
+
this.stop();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
setVolume(volume) {
|
|
95
|
+
this.set({ volume: Math.min(1, Math.max(0, Number.isFinite(volume) ? volume : 0)) });
|
|
96
|
+
this.saveSettings();
|
|
97
|
+
this.applyVolume();
|
|
98
|
+
}
|
|
99
|
+
/** Re-applies the effective volume (call it when the game's master volume / mute changes); 0 stops the line. */
|
|
100
|
+
applyVolume() {
|
|
101
|
+
const effective = this.effectiveVolume();
|
|
102
|
+
if (this.audio) {
|
|
103
|
+
this.audio.volume = effective;
|
|
104
|
+
if (effective <= 0) {
|
|
105
|
+
this.stop();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async play(line) {
|
|
110
|
+
this.lastLine = line;
|
|
111
|
+
const refusal = !this.state.enabled
|
|
112
|
+
? 'disabled'
|
|
113
|
+
: this.effectiveVolume() <= 0
|
|
114
|
+
? 'muted'
|
|
115
|
+
: this.options.requireGesture && !this.state.sessionActivated ? 'no-gesture' : null;
|
|
116
|
+
if (refusal) {
|
|
117
|
+
this.set({ lastRefusal: refusal });
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
// exactly one active line: the previous one is stopped and its late callbacks become stale
|
|
121
|
+
const revision = ++this.revision;
|
|
122
|
+
this.detach();
|
|
123
|
+
let audio;
|
|
124
|
+
try {
|
|
125
|
+
audio = this.options.audioFactory(line.src);
|
|
126
|
+
audio.volume = this.effectiveVolume();
|
|
127
|
+
audio.onended = () => {
|
|
128
|
+
if (revision === this.revision) {
|
|
129
|
+
this.audio = null;
|
|
130
|
+
this.set({ playback: 'idle', activeLineId: null, subtitle: null });
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
audio.onerror = () => {
|
|
134
|
+
if (revision === this.revision) {
|
|
135
|
+
this.audio = null;
|
|
136
|
+
this.set({ playback: 'failed', lastRefusal: 'error' });
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
this.audio = audio;
|
|
140
|
+
this.set({ activeLineId: line.lineId, subtitle: line.subtitle ?? null, lastRefusal: null });
|
|
141
|
+
await audio.play();
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
if (revision !== this.revision) {
|
|
145
|
+
return false; // a newer line replaced this one while play() was pending
|
|
146
|
+
}
|
|
147
|
+
this.audio = null;
|
|
148
|
+
const blocked = error?.name === 'NotAllowedError';
|
|
149
|
+
this.set({ playback: blocked ? 'blocked' : 'failed', lastRefusal: blocked ? 'autoplay-blocked' : 'error' });
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
if (revision !== this.revision) {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
this.set({ playback: 'playing' });
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
detach() {
|
|
159
|
+
if (this.audio) {
|
|
160
|
+
const audio = this.audio;
|
|
161
|
+
this.audio = null;
|
|
162
|
+
audio.onended = null;
|
|
163
|
+
audio.onerror = null;
|
|
164
|
+
try {
|
|
165
|
+
audio.pause();
|
|
166
|
+
audio.currentTime = 0;
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
log_util_1.DyFM_Log.error('DyFM_NarrationPlayer: stopping the previous line failed', error);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
effectiveVolume() {
|
|
174
|
+
const master = this.options.masterVolume ? this.options.masterVolume() : 1;
|
|
175
|
+
return Math.min(1, Math.max(0, this.state.volume * (Number.isFinite(master) ? master : 0)));
|
|
176
|
+
}
|
|
177
|
+
set(patch) {
|
|
178
|
+
this.state = { ...this.state, ...patch };
|
|
179
|
+
const snapshot = this.getState();
|
|
180
|
+
for (const listener of [...this.listeners]) {
|
|
181
|
+
try {
|
|
182
|
+
listener(snapshot);
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
log_util_1.DyFM_Log.error('DyFM_NarrationPlayer: an onChange listener threw', error);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
loadSettings() {
|
|
190
|
+
const settings = this.options.settings;
|
|
191
|
+
if (!settings) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
const stored = settings.store.getItem(settings.key);
|
|
196
|
+
const parsed = stored ? JSON.parse(stored) : {};
|
|
197
|
+
if (typeof parsed.enabled === 'boolean') {
|
|
198
|
+
this.state.enabled = parsed.enabled;
|
|
199
|
+
}
|
|
200
|
+
if (typeof parsed.volume === 'number' && Number.isFinite(parsed.volume)) {
|
|
201
|
+
this.state.volume = Math.min(1, Math.max(0, parsed.volume));
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
// a broken stored value falls back to the defaults (the session still works)
|
|
206
|
+
log_util_1.DyFM_Log.error(`DyFM_NarrationPlayer: unreadable settings under '${settings.key}' — defaults used`, error);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
saveSettings() {
|
|
210
|
+
const settings = this.options.settings;
|
|
211
|
+
if (!settings) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
try {
|
|
215
|
+
settings.store.setItem(settings.key, JSON.stringify({ enabled: this.state.enabled, volume: this.state.volume }));
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
log_util_1.DyFM_Log.error(`DyFM_NarrationPlayer: settings could not be saved under '${settings.key}'`, error);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
exports.DyFM_NarrationPlayer_ControlModel = DyFM_NarrationPlayer_ControlModel;
|
|
223
|
+
//# sourceMappingURL=narration-player.control-model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"narration-player.control-model.js","sourceRoot":"","sources":["../../../../src/_modules/game/_models/narration-player.control-model.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/** BFR-WARFACTORY-014 — one narration line: the asset is the core address, the subtitle the always-available fallback. */
|
|
2
|
+
export interface DyFM_NarrationLine {
|
|
3
|
+
/** Stable id (a catalog key or an asset id). */
|
|
4
|
+
lineId: string;
|
|
5
|
+
/** The audio source (URL / path) — resolved by the audio factory. */
|
|
6
|
+
src: string;
|
|
7
|
+
/** Shown while it plays AND when it cannot play (blocked / failed): the text is never lost. */
|
|
8
|
+
subtitle?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The audio element surface the player uses — structural, so an `HTMLAudioElement` fits it and specs can use a fake.
|
|
12
|
+
* `play()` rejects with a `NotAllowedError`-named error when the browser blocks autoplay.
|
|
13
|
+
*/
|
|
14
|
+
export interface DyFM_NarrationAudio_Interface {
|
|
15
|
+
volume: number;
|
|
16
|
+
currentTime: number;
|
|
17
|
+
onended: (() => void) | null;
|
|
18
|
+
onerror: (() => void) | null;
|
|
19
|
+
play(): Promise<void>;
|
|
20
|
+
pause(): void;
|
|
21
|
+
}
|
|
22
|
+
/** A persisted-settings store (e.g. `localStorage`); optional. */
|
|
23
|
+
export interface DyFM_NarrationSettingsStore_Interface {
|
|
24
|
+
getItem(key: string): string | null;
|
|
25
|
+
setItem(key: string, value: string): void;
|
|
26
|
+
}
|
|
27
|
+
export interface DyFM_NarrationPlayer_Options {
|
|
28
|
+
/** Creates the audio for a source — in a browser: `(src) => new Audio(src)`. */
|
|
29
|
+
audioFactory: (src: string) => DyFM_NarrationAudio_Interface;
|
|
30
|
+
/**
|
|
31
|
+
* When true, `play()` only plays after `activate()` (a user gesture) — automatic narration then refuses with
|
|
32
|
+
* `no-gesture` instead of hitting the browser's autoplay block. `activateAndPlay()` / `replay()` count as a gesture.
|
|
33
|
+
*/
|
|
34
|
+
requireGesture?: boolean;
|
|
35
|
+
/** The game's master volume 0..1 (and mute as 0) — multiplied into the narration volume. Default: 1. */
|
|
36
|
+
masterVolume?: () => number;
|
|
37
|
+
/** Optional catalog: `playCatalog(key)` resolves through it (an asset-id layer on top of the core). */
|
|
38
|
+
catalog?: Record<string, DyFM_NarrationLine>;
|
|
39
|
+
/** Optional settings persistence (enabled + volume). */
|
|
40
|
+
settings?: {
|
|
41
|
+
store: DyFM_NarrationSettingsStore_Interface;
|
|
42
|
+
key: string;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export type DyFM_NarrationPlayback_Type = 'idle' | 'playing' | 'blocked' | 'failed';
|
|
46
|
+
/**
|
|
47
|
+
* Why the last `play` did not play — the diagnosis a silent narration otherwise lacks.
|
|
48
|
+
* `autoplay-blocked` is the one the UI must tell the player about ("click to enable sound").
|
|
49
|
+
*/
|
|
50
|
+
export type DyFM_NarrationRefusal_Type = 'disabled' | 'muted' | 'no-gesture' | 'autoplay-blocked' | 'error' | 'unknown-line';
|
|
51
|
+
/** Everything a UI needs (the five WF signals + the subtitle + the refusal reason). */
|
|
52
|
+
export interface DyFM_NarrationState {
|
|
53
|
+
playback: DyFM_NarrationPlayback_Type;
|
|
54
|
+
/** The line playing, or the one that could not play (blocked / failed) — null when idle. */
|
|
55
|
+
activeLineId: string | null;
|
|
56
|
+
/** The active line's subtitle (also while blocked / failed — the text fallback). */
|
|
57
|
+
subtitle: string | null;
|
|
58
|
+
enabled: boolean;
|
|
59
|
+
/** The narration's own volume 0..1 (before the master volume). */
|
|
60
|
+
volume: number;
|
|
61
|
+
sessionActivated: boolean;
|
|
62
|
+
lastRefusal: DyFM_NarrationRefusal_Type | null;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=narration-player.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"narration-player.interface.d.ts","sourceRoot":"","sources":["../../../../src/_modules/game/_models/narration-player.interface.ts"],"names":[],"mappings":"AAAA,0HAA0H;AAC1H,MAAM,WAAW,kBAAkB;IACjC,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAC;IACZ,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,6BAA6B;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC;IAC7B,OAAO,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC;IAC7B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,KAAK,IAAI,IAAI,CAAC;CACf;AAED,kEAAkE;AAClE,MAAM,WAAW,qCAAqC;IACpD,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACpC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAED,MAAM,WAAW,4BAA4B;IAC3C,gFAAgF;IAChF,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,6BAA6B,CAAC;IAC7D;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wGAAwG;IACxG,YAAY,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,uGAAuG;IACvG,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,wDAAwD;IACxD,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,qCAAqC,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1E;AAED,MAAM,MAAM,2BAA2B,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEpF;;;GAGG;AACH,MAAM,MAAM,0BAA0B,GAAG,UAAU,GAAG,OAAO,GAAG,YAAY,GAAG,kBAAkB,GAAG,OAAO,GAAG,cAAc,CAAC;AAE7H,uFAAuF;AACvF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,2BAA2B,CAAC;IACtC,4FAA4F;IAC5F,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,oFAAoF;IACpF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,OAAO,CAAC;IAC1B,WAAW,EAAE,0BAA0B,GAAG,IAAI,CAAC;CAChD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"narration-player.interface.js","sourceRoot":"","sources":["../../../../src/_modules/game/_models/narration-player.interface.ts"],"names":[],"mappings":""}
|
|
@@ -22,6 +22,8 @@ export * from './_models/input-action.interface';
|
|
|
22
22
|
export * from './_models/input-action-registry.control-model';
|
|
23
23
|
export * from './_models/guided-onboarding.interface';
|
|
24
24
|
export * from './_models/guided-onboarding.control-model';
|
|
25
|
+
export * from './_models/narration-player.interface';
|
|
26
|
+
export * from './_models/narration-player.control-model';
|
|
25
27
|
export * from './_collections/audio-mixer.util';
|
|
26
28
|
export * from './_collections/audio-scale.util';
|
|
27
29
|
export * from './_collections/game-save.util';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/_modules/game/index.ts"],"names":[],"mappings":"AACA,cAAc,6BAA6B,CAAC;AAG5C,cAAc,wCAAwC,CAAC;AACvD,cAAc,0CAA0C,CAAC;AACzD,cAAc,uCAAuC,CAAC;AACtD,cAAc,qCAAqC,CAAC;AACpD,cAAc,iCAAiC,CAAC;AAChD,cAAc,yCAAyC,CAAC;AACxD,cAAc,uCAAuC,CAAC;AACtD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,mCAAmC,CAAC;AAClD,cAAc,uCAAuC,CAAC;AACtD,cAAc,sCAAsC,CAAC;AACrD,cAAc,0CAA0C,CAAC;AACzD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0CAA0C,CAAC;AACzD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,uCAAuC,CAAC;AACtD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kCAAkC,CAAC;AACjD,cAAc,kCAAkC,CAAC;AACjD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,uCAAuC,CAAC;AACtD,cAAc,2CAA2C,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/_modules/game/index.ts"],"names":[],"mappings":"AACA,cAAc,6BAA6B,CAAC;AAG5C,cAAc,wCAAwC,CAAC;AACvD,cAAc,0CAA0C,CAAC;AACzD,cAAc,uCAAuC,CAAC;AACtD,cAAc,qCAAqC,CAAC;AACpD,cAAc,iCAAiC,CAAC;AAChD,cAAc,yCAAyC,CAAC;AACxD,cAAc,uCAAuC,CAAC;AACtD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,mCAAmC,CAAC;AAClD,cAAc,uCAAuC,CAAC;AACtD,cAAc,sCAAsC,CAAC;AACrD,cAAc,0CAA0C,CAAC;AACzD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0CAA0C,CAAC;AACzD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,uCAAuC,CAAC;AACtD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kCAAkC,CAAC;AACjD,cAAc,kCAAkC,CAAC;AACjD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,uCAAuC,CAAC;AACtD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,sCAAsC,CAAC;AACrD,cAAc,0CAA0C,CAAC;AAGzD,cAAc,iCAAiC,CAAC;AAChD,cAAc,iCAAiC,CAAC;AAChD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uCAAuC,CAAC"}
|
|
@@ -27,6 +27,8 @@ tslib_1.__exportStar(require("./_models/input-action.interface"), exports);
|
|
|
27
27
|
tslib_1.__exportStar(require("./_models/input-action-registry.control-model"), exports);
|
|
28
28
|
tslib_1.__exportStar(require("./_models/guided-onboarding.interface"), exports);
|
|
29
29
|
tslib_1.__exportStar(require("./_models/guided-onboarding.control-model"), exports);
|
|
30
|
+
tslib_1.__exportStar(require("./_models/narration-player.interface"), exports);
|
|
31
|
+
tslib_1.__exportStar(require("./_models/narration-player.control-model"), exports);
|
|
30
32
|
// COLLECTIONS
|
|
31
33
|
tslib_1.__exportStar(require("./_collections/audio-mixer.util"), exports);
|
|
32
34
|
tslib_1.__exportStar(require("./_collections/audio-scale.util"), exports);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/_modules/game/index.ts"],"names":[],"mappings":";;;AAAA,QAAQ;AACR,sEAA4C;AAE5C,SAAS;AACT,iFAAuD;AACvD,mFAAyD;AACzD,gFAAsD;AACtD,8EAAoD;AACpD,0EAAgD;AAChD,kFAAwD;AACxD,gFAAsD;AACtD,qFAA2D;AAC3D,yFAA+D;AAC/D,4EAAkD;AAClD,gFAAsD;AACtD,+EAAqD;AACrD,mFAAyD;AACzD,wEAA8C;AAC9C,mFAAyD;AACzD,uFAA6D;AAC7D,gFAAsD;AACtD,uEAA6C;AAC7C,2EAAiD;AACjD,2EAAiD;AACjD,wFAA8D;AAC9D,gFAAsD;AACtD,oFAA0D;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/_modules/game/index.ts"],"names":[],"mappings":";;;AAAA,QAAQ;AACR,sEAA4C;AAE5C,SAAS;AACT,iFAAuD;AACvD,mFAAyD;AACzD,gFAAsD;AACtD,8EAAoD;AACpD,0EAAgD;AAChD,kFAAwD;AACxD,gFAAsD;AACtD,qFAA2D;AAC3D,yFAA+D;AAC/D,4EAAkD;AAClD,gFAAsD;AACtD,+EAAqD;AACrD,mFAAyD;AACzD,wEAA8C;AAC9C,mFAAyD;AACzD,uFAA6D;AAC7D,gFAAsD;AACtD,uEAA6C;AAC7C,2EAAiD;AACjD,2EAAiD;AACjD,wFAA8D;AAC9D,gFAAsD;AACtD,oFAA0D;AAC1D,+EAAqD;AACrD,mFAAyD;AAEzD,cAAc;AACd,0EAAgD;AAChD,0EAAgD;AAChD,wEAA8C;AAC9C,gFAAsD"}
|
|
@@ -33,7 +33,7 @@ export class DyFM_DataPropertyParams_ControlModel extends DyFM_DataProperty_Sett
|
|
|
33
33
|
`\n stackLocation: ${DyFM_getConstructionStackLocation(2)}`);
|
|
34
34
|
}
|
|
35
35
|
if (set.dependencyDataName) {
|
|
36
|
-
if (set.required === false) {
|
|
36
|
+
if (set.required === false && !set.isOptionalDependency) {
|
|
37
37
|
DyFM_Log.warn('DYNAMO WARNING: ', `\n required is not recommended to be false if dependency is set at "${set.key}" in ` +
|
|
38
38
|
`"${parentDataParams?.dataName}" model.` +
|
|
39
39
|
`\n stackLocation: ${DyFM_getConstructionStackLocation(2)}`);
|
|
@@ -20,6 +20,13 @@ export class DyFM_DataPropertySettings_ControlModel {
|
|
|
20
20
|
/** @deprecated Use isEncrypted; encrypt remains the serialized compatibility key. */
|
|
21
21
|
encrypt;
|
|
22
22
|
dependencyDataName;
|
|
23
|
+
/**
|
|
24
|
+
* The dependency is DELIBERATELY optional (`required: false` + `dependencyDataName`) — e.g. an anonymous feedback
|
|
25
|
+
* whose owner account may be missing, yet "my feedbacks" still lists by it. Silences the "required is not
|
|
26
|
+
* recommended to be false" warning, which otherwise printed on every boot of every consumer (measured 2026-09-25:
|
|
27
|
+
* every `fdp` command, after the feedback model's owner became optional in BFR-FUTDEVPRO-033).
|
|
28
|
+
*/
|
|
29
|
+
isOptionalDependency;
|
|
23
30
|
/** @deprecated Use isArchiveable; archiveable remains the serialized compatibility key. */
|
|
24
31
|
archiveable;
|
|
25
32
|
archiveListAfter;
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { DyFM_Log } from '../../../_collections/utils/log.util';
|
|
2
|
+
/**
|
|
3
|
+
* BFR-WARFACTORY-014 — the narration adapter canon (war-factory `Tutorial_Narration_Service` + portalhold voice lines):
|
|
4
|
+
*
|
|
5
|
+
* - **asset-id core**, catalog as an optional layer (`playLine` / `playCatalog`);
|
|
6
|
+
* - `Promise<boolean>` — a refusal is REPORTED, with its reason in `lastRefusal` (disabled · muted · no-gesture ·
|
|
7
|
+
* autoplay-blocked · error · unknown-line) — a narration that silently does not play is undiagnosable;
|
|
8
|
+
* - optional **gesture gate with exposed state** (`sessionActivated`);
|
|
9
|
+
* - **exactly one active line** — every play stops the previous one;
|
|
10
|
+
* - a **staleness guard** (revision counter): a late `ended` / `error` / `play()` rejection of a replaced line never
|
|
11
|
+
* touches the current one;
|
|
12
|
+
* - **`blocked` ≠ `failed`**: a `NotAllowedError` (browser autoplay block) is the case the player must be told about;
|
|
13
|
+
* - `replay()`; optional settings persistence; the subtitle stays available while blocked / failed (text fallback).
|
|
14
|
+
*
|
|
15
|
+
* Framework-agnostic: the audio comes from a factory (`(src) => new Audio(src)` in a browser); a UI layer mirrors
|
|
16
|
+
* `getState()` via `onChange`.
|
|
17
|
+
*/
|
|
18
|
+
export class DyFM_NarrationPlayer_ControlModel {
|
|
19
|
+
options;
|
|
20
|
+
listeners = [];
|
|
21
|
+
audio = null;
|
|
22
|
+
revision = 0;
|
|
23
|
+
lastLine = null;
|
|
24
|
+
state = {
|
|
25
|
+
playback: 'idle', activeLineId: null, subtitle: null, enabled: true, volume: 0.85, sessionActivated: false,
|
|
26
|
+
lastRefusal: null,
|
|
27
|
+
};
|
|
28
|
+
constructor(options) {
|
|
29
|
+
this.options = options;
|
|
30
|
+
this.loadSettings();
|
|
31
|
+
}
|
|
32
|
+
/** A copy of the current state. */
|
|
33
|
+
getState() {
|
|
34
|
+
return { ...this.state };
|
|
35
|
+
}
|
|
36
|
+
/** Subscribe to state changes; returns the unsubscribe. A throwing listener is logged and isolated. */
|
|
37
|
+
onChange(listener) {
|
|
38
|
+
this.listeners.push(listener);
|
|
39
|
+
return () => {
|
|
40
|
+
const index = this.listeners.indexOf(listener);
|
|
41
|
+
if (index >= 0) {
|
|
42
|
+
this.listeners.splice(index, 1);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/** Marks a user gesture — from now on automatic narration may play. */
|
|
47
|
+
activate() {
|
|
48
|
+
if (!this.state.sessionActivated) {
|
|
49
|
+
this.set({ sessionActivated: true });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** Plays a line (automatic path: respects the gesture gate). */
|
|
53
|
+
async playLine(line) {
|
|
54
|
+
return this.play(line);
|
|
55
|
+
}
|
|
56
|
+
/** Plays a catalog entry; an unknown key refuses with `unknown-line`. */
|
|
57
|
+
async playCatalog(key) {
|
|
58
|
+
const line = this.options.catalog?.[key];
|
|
59
|
+
if (!line) {
|
|
60
|
+
this.set({ lastRefusal: 'unknown-line' });
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
return this.play(line);
|
|
64
|
+
}
|
|
65
|
+
/** From a user gesture: activates the session, then plays. */
|
|
66
|
+
async activateAndPlay(line) {
|
|
67
|
+
this.activate();
|
|
68
|
+
return this.play(line);
|
|
69
|
+
}
|
|
70
|
+
/** Replays the last requested line (a replay button is a gesture). */
|
|
71
|
+
async replay() {
|
|
72
|
+
if (!this.lastLine) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
this.activate();
|
|
76
|
+
return this.play(this.lastLine);
|
|
77
|
+
}
|
|
78
|
+
/** Stops the active line (or clears a blocked / failed one). */
|
|
79
|
+
stop() {
|
|
80
|
+
this.revision++;
|
|
81
|
+
this.detach();
|
|
82
|
+
this.set({ playback: 'idle', activeLineId: null, subtitle: null });
|
|
83
|
+
}
|
|
84
|
+
setEnabled(enabled) {
|
|
85
|
+
this.set({ enabled: enabled });
|
|
86
|
+
this.saveSettings();
|
|
87
|
+
if (!enabled && this.audio) {
|
|
88
|
+
this.stop();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
setVolume(volume) {
|
|
92
|
+
this.set({ volume: Math.min(1, Math.max(0, Number.isFinite(volume) ? volume : 0)) });
|
|
93
|
+
this.saveSettings();
|
|
94
|
+
this.applyVolume();
|
|
95
|
+
}
|
|
96
|
+
/** Re-applies the effective volume (call it when the game's master volume / mute changes); 0 stops the line. */
|
|
97
|
+
applyVolume() {
|
|
98
|
+
const effective = this.effectiveVolume();
|
|
99
|
+
if (this.audio) {
|
|
100
|
+
this.audio.volume = effective;
|
|
101
|
+
if (effective <= 0) {
|
|
102
|
+
this.stop();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async play(line) {
|
|
107
|
+
this.lastLine = line;
|
|
108
|
+
const refusal = !this.state.enabled
|
|
109
|
+
? 'disabled'
|
|
110
|
+
: this.effectiveVolume() <= 0
|
|
111
|
+
? 'muted'
|
|
112
|
+
: this.options.requireGesture && !this.state.sessionActivated ? 'no-gesture' : null;
|
|
113
|
+
if (refusal) {
|
|
114
|
+
this.set({ lastRefusal: refusal });
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
// exactly one active line: the previous one is stopped and its late callbacks become stale
|
|
118
|
+
const revision = ++this.revision;
|
|
119
|
+
this.detach();
|
|
120
|
+
let audio;
|
|
121
|
+
try {
|
|
122
|
+
audio = this.options.audioFactory(line.src);
|
|
123
|
+
audio.volume = this.effectiveVolume();
|
|
124
|
+
audio.onended = () => {
|
|
125
|
+
if (revision === this.revision) {
|
|
126
|
+
this.audio = null;
|
|
127
|
+
this.set({ playback: 'idle', activeLineId: null, subtitle: null });
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
audio.onerror = () => {
|
|
131
|
+
if (revision === this.revision) {
|
|
132
|
+
this.audio = null;
|
|
133
|
+
this.set({ playback: 'failed', lastRefusal: 'error' });
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
this.audio = audio;
|
|
137
|
+
this.set({ activeLineId: line.lineId, subtitle: line.subtitle ?? null, lastRefusal: null });
|
|
138
|
+
await audio.play();
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
if (revision !== this.revision) {
|
|
142
|
+
return false; // a newer line replaced this one while play() was pending
|
|
143
|
+
}
|
|
144
|
+
this.audio = null;
|
|
145
|
+
const blocked = error?.name === 'NotAllowedError';
|
|
146
|
+
this.set({ playback: blocked ? 'blocked' : 'failed', lastRefusal: blocked ? 'autoplay-blocked' : 'error' });
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
if (revision !== this.revision) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
this.set({ playback: 'playing' });
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
detach() {
|
|
156
|
+
if (this.audio) {
|
|
157
|
+
const audio = this.audio;
|
|
158
|
+
this.audio = null;
|
|
159
|
+
audio.onended = null;
|
|
160
|
+
audio.onerror = null;
|
|
161
|
+
try {
|
|
162
|
+
audio.pause();
|
|
163
|
+
audio.currentTime = 0;
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
DyFM_Log.error('DyFM_NarrationPlayer: stopping the previous line failed', error);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
effectiveVolume() {
|
|
171
|
+
const master = this.options.masterVolume ? this.options.masterVolume() : 1;
|
|
172
|
+
return Math.min(1, Math.max(0, this.state.volume * (Number.isFinite(master) ? master : 0)));
|
|
173
|
+
}
|
|
174
|
+
set(patch) {
|
|
175
|
+
this.state = { ...this.state, ...patch };
|
|
176
|
+
const snapshot = this.getState();
|
|
177
|
+
for (const listener of [...this.listeners]) {
|
|
178
|
+
try {
|
|
179
|
+
listener(snapshot);
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
DyFM_Log.error('DyFM_NarrationPlayer: an onChange listener threw', error);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
loadSettings() {
|
|
187
|
+
const settings = this.options.settings;
|
|
188
|
+
if (!settings) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
try {
|
|
192
|
+
const stored = settings.store.getItem(settings.key);
|
|
193
|
+
const parsed = stored ? JSON.parse(stored) : {};
|
|
194
|
+
if (typeof parsed.enabled === 'boolean') {
|
|
195
|
+
this.state.enabled = parsed.enabled;
|
|
196
|
+
}
|
|
197
|
+
if (typeof parsed.volume === 'number' && Number.isFinite(parsed.volume)) {
|
|
198
|
+
this.state.volume = Math.min(1, Math.max(0, parsed.volume));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
// a broken stored value falls back to the defaults (the session still works)
|
|
203
|
+
DyFM_Log.error(`DyFM_NarrationPlayer: unreadable settings under '${settings.key}' — defaults used`, error);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
saveSettings() {
|
|
207
|
+
const settings = this.options.settings;
|
|
208
|
+
if (!settings) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
try {
|
|
212
|
+
settings.store.setItem(settings.key, JSON.stringify({ enabled: this.state.enabled, volume: this.state.volume }));
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
DyFM_Log.error(`DyFM_NarrationPlayer: settings could not be saved under '${settings.key}'`, error);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -24,6 +24,8 @@ export * from './_models/input-action.interface';
|
|
|
24
24
|
export * from './_models/input-action-registry.control-model';
|
|
25
25
|
export * from './_models/guided-onboarding.interface';
|
|
26
26
|
export * from './_models/guided-onboarding.control-model';
|
|
27
|
+
export * from './_models/narration-player.interface';
|
|
28
|
+
export * from './_models/narration-player.control-model';
|
|
27
29
|
// COLLECTIONS
|
|
28
30
|
export * from './_collections/audio-mixer.util';
|
|
29
31
|
export * from './_collections/audio-scale.util';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@futdevpro/fsm-dynamo",
|
|
3
|
-
"version": "1.20.
|
|
3
|
+
"version": "1.20.105",
|
|
4
4
|
"description": "Full Stack Model Collection for Dynamic (NodeJS-Typescript) Framework called Dynamo, by Future Development Ltd.",
|
|
5
5
|
"DyBu_settings": {
|
|
6
6
|
"packageType": "full-stack-package",
|