@combos-fun/plugin-sound 0.0.46 → 0.0.48

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/agent-skill.md CHANGED
@@ -14,7 +14,7 @@ import { Sound, SoundSystem } from '@combos-fun/plugin-sound';
14
14
 
15
15
  `Sound` params: required `resource`; optional `autoplay`, `loop`, `muted`, `volume` (`0..1`), `seek`, `duration`, and `onEnd`. Its `play()`, `pause()`, and `stop()` methods return `void`; `muted`, `volume`, `loop`, `autoplay`, and `resource` are writable.
16
16
 
17
- `SoundSystem` accepts optional `onError` and `autoPauseAndStart` (default `true`). It exposes `resumeAll()`, `pauseAll()`, `stopAll()`, global `muted` / `volume`, and `audioLocked`.
17
+ `SoundSystem` accepts optional `onError`, `autoPauseAndStart` (default `true`), `postMessageOrigin`, and `allowedMessageOrigins`. It exposes `resumeAll()`, `pauseAll()`, `stopAll()`, `setMuted()`, global `muted` / `volume`, and `audioLocked`.
18
18
 
19
19
  Parameter interfaces are not exported from the package entry; pass object literals.
20
20
 
@@ -35,6 +35,14 @@ resource.addResource([{
35
35
 
36
36
  Decoded buffers are cached by resource. Each `play()` replaces the current `AudioBufferSourceNode`; `muted` and `volume` update gain immediately. With `autoPauseAndStart`, game pause/resume calls `pauseAll()` / `resumeAll()`.
37
37
 
38
+ Host mute (2D and 3D) is owned here. Plugin host types stay on `combos-development-tool:*` (only engine may use `combos-game:*`):
39
+
40
+ - Parent → iframe: `combos-development-tool:set-muted` `{ muted }`
41
+ - iframe → parent: `combos-development-tool:state-changed` `{ muted }`
42
+ - Same command via `window` CustomEvent, `game.emit`, or `SoundSystem.setMuted` / `SoundSystem.muted`
43
+
44
+ Inbound `postMessage` is origin-checked with the engine defaults (`knoffice.tech`, `converge.ai`). Pass `allowedMessageOrigins: ['localhost']` for local hosts; `['*']` disables the check. Outbound `targetOrigin` follows `postMessageOrigin`, then `Game.pluginInitNotifyTargetOrigin`, then `'*'`.
45
+
38
46
  ## Common pitfalls
39
47
 
40
48
  - Autoplay can be blocked; start from a touch/click path.
@@ -7,5 +7,10 @@
7
7
  "keywords": ["sound", "audio", "playback", "volume", "web-audio", "sfx", "bgm"],
8
8
  "agentSkill": "./agent-skill.md",
9
9
  "requires": ["@combos-fun/engine"],
10
- "exports": ["Sound", "SoundSystem"]
10
+ "exports": [
11
+ "Sound",
12
+ "SoundSystem",
13
+ "COMBOS_DEVELOPMENT_TOOL_SET_MUTED",
14
+ "COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED"
15
+ ]
11
16
  }
@@ -4,14 +4,52 @@ var tslib = require('tslib');
4
4
  var engine = require('@combos-fun/engine');
5
5
  var inspectorDecorator = require('@combos-fun/inspector-decorator');
6
6
 
7
+ /** Parent → iframe (also `window` CustomEvent / `game.emit`): mute or unmute. Payload: `{ muted: boolean }`. */
8
+ const COMBOS_DEVELOPMENT_TOOL_SET_MUTED = 'combos-development-tool:set-muted';
9
+ /** iframe → parent (and `game.emit`): current mute snapshot after a successful change. */
10
+ const COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED = 'combos-development-tool:state-changed';
11
+ function parseSetMutedMessage(data) {
12
+ if (!data || typeof data !== 'object')
13
+ return null;
14
+ const d = data;
15
+ if (d.type !== COMBOS_DEVELOPMENT_TOOL_SET_MUTED)
16
+ return null;
17
+ if (typeof d.muted !== 'boolean')
18
+ return null;
19
+ return d.muted;
20
+ }
21
+ function parseSetMutedCustomEvent(event) {
22
+ const d = event.detail;
23
+ if (!d || typeof d !== 'object' || typeof d.muted !== 'boolean')
24
+ return null;
25
+ return d.muted;
26
+ }
27
+ function postToParent(payload, targetOrigin) {
28
+ if (typeof window === 'undefined')
29
+ return;
30
+ if (!window.parent || window.parent === window)
31
+ return;
32
+ try {
33
+ window.parent.postMessage(payload, targetOrigin);
34
+ }
35
+ catch {
36
+ /* ignore cross-origin or detached frame */
37
+ }
38
+ }
39
+ /** Notifies the embedding page (and `game.emit`) of the current mute flag. */
40
+ function postParentSoundMuted(muted, targetOrigin, emit) {
41
+ const state = { muted };
42
+ postToParent({ type: COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED, ...state }, targetOrigin);
43
+ emit?.(COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED, state);
44
+ }
45
+
7
46
  let SoundSystem$1 = class SoundSystem extends engine.System {
8
47
  static { this.systemName = 'SoundSystem'; }
9
48
  get muted() {
10
49
  return this._muted;
11
50
  }
12
51
  set muted(v) {
13
- this._muted = v;
14
- this.applyGain();
52
+ this.setMuted(v);
15
53
  }
16
54
  get volume() {
17
55
  return this._volume;
@@ -55,7 +93,50 @@ let SoundSystem$1 = class SoundSystem extends engine.System {
55
93
  /** Desired mute/volume are the source of truth; the gain node is derived. */
56
94
  this._muted = false;
57
95
  this._volume = 1;
58
- Object.assign(this, obj);
96
+ this.postMessageOrigin = '*';
97
+ this.allowedMessageOrigins = engine.mergeAllowedMessageOrigins();
98
+ this.hostMuteBound = false;
99
+ this.onWindowSetMuted = (e) => {
100
+ const muted = parseSetMutedCustomEvent(e);
101
+ if (muted === null)
102
+ return;
103
+ this.setMuted(muted);
104
+ };
105
+ this.onGameSetMuted = (payload) => {
106
+ if (payload && typeof payload.muted === 'boolean') {
107
+ this.setMuted(payload.muted);
108
+ }
109
+ };
110
+ this.onWindowMessage = (e) => {
111
+ if (!engine.isAllowedMessageOrigin(e.origin, this.allowedMessageOrigins)) {
112
+ return;
113
+ }
114
+ const muted = parseSetMutedMessage(e.data);
115
+ if (muted === null)
116
+ return;
117
+ this.setMuted(muted);
118
+ };
119
+ if (!obj)
120
+ return;
121
+ if (typeof obj.autoPauseAndStart === 'boolean') {
122
+ this.autoPauseAndStart = obj.autoPauseAndStart;
123
+ }
124
+ if (obj.onError) {
125
+ this.onError = obj.onError;
126
+ }
127
+ }
128
+ /**
129
+ * Mute or unmute the master gain and notify the embedding host.
130
+ * Same effect as `postMessage({ type: 'combos-development-tool:set-muted', muted })`.
131
+ */
132
+ setMuted(muted) {
133
+ const next = !!muted;
134
+ if (this._muted === next) {
135
+ return;
136
+ }
137
+ this._muted = next;
138
+ this.applyGain();
139
+ this.postMuteStateChanged();
59
140
  }
60
141
  /**
61
142
  * Resume playback of all paused audio.
@@ -98,7 +179,11 @@ let SoundSystem$1 = class SoundSystem extends engine.System {
98
179
  /**
99
180
  * System init: configure params before the game starts.
100
181
  */
101
- init() {
182
+ init(params) {
183
+ this.postMessageOrigin =
184
+ params?.postMessageOrigin ?? this.game?.pluginInitNotifyTargetOrigin ?? '*';
185
+ this.allowedMessageOrigins = engine.mergeAllowedMessageOrigins(params?.allowedMessageOrigins);
186
+ this.bindHostMute();
102
187
  this.setupAudioContext();
103
188
  }
104
189
  update() {
@@ -129,6 +214,7 @@ let SoundSystem$1 = class SoundSystem extends engine.System {
129
214
  * Called when the system is destroyed.
130
215
  */
131
216
  onDestroy() {
217
+ this.unbindHostMute();
132
218
  this.components.forEach(component => {
133
219
  component.onDestroy();
134
220
  });
@@ -140,6 +226,31 @@ let SoundSystem$1 = class SoundSystem extends engine.System {
140
226
  this.ctx = null;
141
227
  }
142
228
  }
229
+ bindHostMute() {
230
+ if (this.hostMuteBound)
231
+ return;
232
+ this.hostMuteBound = true;
233
+ if (typeof window !== 'undefined') {
234
+ window.addEventListener(COMBOS_DEVELOPMENT_TOOL_SET_MUTED, this.onWindowSetMuted);
235
+ window.addEventListener('message', this.onWindowMessage);
236
+ }
237
+ this.game.on(COMBOS_DEVELOPMENT_TOOL_SET_MUTED, this.onGameSetMuted);
238
+ }
239
+ unbindHostMute() {
240
+ if (!this.hostMuteBound)
241
+ return;
242
+ this.hostMuteBound = false;
243
+ if (typeof window !== 'undefined') {
244
+ window.removeEventListener(COMBOS_DEVELOPMENT_TOOL_SET_MUTED, this.onWindowSetMuted);
245
+ window.removeEventListener('message', this.onWindowMessage);
246
+ }
247
+ this.game?.off(COMBOS_DEVELOPMENT_TOOL_SET_MUTED, this.onGameSetMuted);
248
+ }
249
+ postMuteStateChanged() {
250
+ postParentSoundMuted(this._muted, this.postMessageOrigin, (type, payload) => {
251
+ this.game?.emit(type, payload);
252
+ });
253
+ }
143
254
  async componentChanged(changed) {
144
255
  if (changed.componentName !== 'Sound')
145
256
  return;
@@ -253,7 +364,7 @@ var SoundSystem = SoundSystem$1;
253
364
  /** Auto-generated by scripts/build-package.mjs — do not edit. */
254
365
  Object.assign(SoundSystem, {
255
366
  packageName: "@combos-fun/plugin-sound",
256
- packageVersion: "0.0.46",
367
+ packageVersion: "0.0.48",
257
368
  });
258
369
 
259
370
  class Sound extends engine.Component {
@@ -487,6 +598,10 @@ tslib.__decorate([
487
598
  })
488
599
  ], Sound.prototype, "resource", null);
489
600
 
601
+ exports.COMBOS_DEVELOPMENT_TOOL_SET_MUTED = COMBOS_DEVELOPMENT_TOOL_SET_MUTED;
602
+ exports.COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED = COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED;
490
603
  exports.Sound = Sound;
491
604
  exports.SoundSystem = SoundSystem;
605
+ exports.parseSetMutedMessage = parseSetMutedMessage;
606
+ exports.postParentSoundMuted = postParentSoundMuted;
492
607
  //# sourceMappingURL=plugin-sound.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-sound.cjs.js","sources":["../lib/SoundSystem.ts","../lib/__combosPackageMeta.gen.ts","../lib/Sound.ts"],"sourcesContent":["import { System, decorators, ComponentChanged, OBSERVER_TYPE, resource } from '@combos-fun/engine';\nimport SoundComponent from './Sound';\n\ninterface SoundSystemParams {\n autoPauseAndStart?: boolean;\n onError?: (error: any) => void;\n}\n\n@decorators.componentObserver({\n Sound: [],\n})\nclass SoundSystem extends System {\n static systemName = 'SoundSystem';\n\n private ctx: AudioContext;\n\n private gainNode: GainNode;\n\n /** Whether to pause/resume in sync with the game. */\n private autoPauseAndStart = true;\n\n private onError: (error: any) => void;\n\n private components: SoundComponent[] = [];\n\n private pausedComponents: SoundComponent[] = [];\n\n private audioBufferCache = {};\n\n private decodeAudioPromiseMap = {};\n\n /** Desired mute/volume are the source of truth; the gain node is derived. */\n private _muted = false;\n\n private _volume = 1;\n\n get muted(): boolean {\n return this._muted;\n }\n\n set muted(v: boolean) {\n this._muted = v;\n this.applyGain();\n }\n\n get volume(): number {\n return this._volume;\n }\n\n set volume(v: number) {\n if (typeof v !== 'number' || v < 0 || v > 1) {\n return;\n }\n this._volume = v;\n this.applyGain();\n }\n\n /**\n * Apply the effective gain (`muted ? 0 : volume`) to the gain node.\n *\n * Assigns `gain.value` directly rather than `setValueAtTime`: `.value` updates\n * the AudioParam's intrinsic value synchronously, so the `muted` / `volume`\n * getters reflect the change immediately. `setValueAtTime` only schedules an\n * event on the automation timeline and leaves `.value` stale until the next\n * render quantum, which made `muted` report the pre-change value.\n */\n private applyGain() {\n if (!this.gainNode) {\n return;\n }\n this.gainNode.gain.value = this._muted ? 0 : this._volume;\n }\n\n get audioLocked(): boolean {\n if (!this.ctx) {\n return true;\n }\n return this.ctx.state !== 'running';\n }\n\n constructor(obj?: SoundSystemParams) {\n super();\n Object.assign(this, obj);\n }\n\n /**\n * Resume playback of all paused audio.\n */\n resumeAll() {\n const handleResume = () => {\n this.pausedComponents.forEach(component => {\n component.play();\n });\n // Clear the previously cached paused list.\n this.pausedComponents = [];\n };\n this.ctx.resume().then(handleResume, handleResume);\n }\n\n /**\n * Pause all currently playing audio.\n */\n pauseAll() {\n this.components.forEach(component => {\n if (component.playing) {\n this.pausedComponents.push(component);\n component.pause();\n }\n });\n this.ctx.suspend().then();\n }\n\n /**\n * Stop all currently playing audio.\n */\n stopAll() {\n this.components.forEach(component => {\n if (component.playing) {\n component.stop();\n }\n });\n // Clear the previously cached paused list.\n this.pausedComponents = [];\n this.ctx.suspend().then();\n }\n\n /**\n * System init: configure params before the game starts.\n */\n init() {\n this.setupAudioContext();\n }\n\n update() {\n const changes = this.componentObserver.clear();\n for (const changed of changes) {\n this.componentChanged(changed);\n }\n }\n\n /**\n * Called when the game starts or resumes playing after a pause.\n */\n onResume() {\n if (!this.autoPauseAndStart) {\n return;\n }\n this.resumeAll();\n }\n\n /**\n * Called when the game is paused.\n */\n onPause() {\n if (!this.autoPauseAndStart) {\n return;\n }\n this.pauseAll();\n }\n\n /**\n * Called when the system is destroyed.\n */\n onDestroy() {\n this.components.forEach(component => {\n component.onDestroy();\n });\n this.components = [];\n if (this.ctx) {\n this.gainNode.disconnect();\n this.gainNode = null;\n this.ctx.close();\n this.ctx = null;\n }\n }\n\n async componentChanged(changed: ComponentChanged) {\n if (changed.componentName !== 'Sound') return;\n\n if (changed.type === OBSERVER_TYPE.ADD) {\n this.add(changed);\n }\n }\n\n private setupAudioContext() {\n try {\n const AudioContext = window.AudioContext || (window as any).webkitAudioContext;\n this.ctx = new AudioContext();\n } catch (error) {\n console.error(error);\n if (this.onError) {\n this.onError(error);\n }\n }\n\n if (!this.ctx) {\n return;\n }\n this.gainNode =\n typeof this.ctx.createGain === 'undefined' ? (this.ctx as any).createGainNode() : this.ctx.createGain();\n this.applyGain();\n this.gainNode.connect(this.ctx.destination);\n this.unlockAudio();\n }\n\n private unlockAudio() {\n if (!this.ctx || !this.audioLocked) {\n return;\n }\n\n const unlock = () => {\n if (this.ctx) {\n const removeListenerFn = () => {\n document.body.removeEventListener('touchstart', unlock);\n document.body.removeEventListener('touchend', unlock);\n document.body.removeEventListener('click', unlock);\n };\n this.ctx.resume().then(removeListenerFn, removeListenerFn);\n }\n };\n document.body.addEventListener('touchstart', unlock);\n document.body.addEventListener('touchend', unlock);\n document.body.addEventListener('click', unlock);\n }\n\n private async add(changed: ComponentChanged) {\n const component = changed.component as SoundComponent;\n this.components.push(component);\n try {\n const { config } = component;\n component.state = 'loading';\n\n const audio = await resource.getResource(config.resource);\n if (!this.audioBufferCache[audio.name] && audio?.data?.audio) {\n this.audioBufferCache[audio.name] = await this.decodeAudioData(audio.data.audio, audio.name);\n }\n if (this.audioBufferCache[audio.name]) {\n component.systemContext = this.ctx;\n component.systemDestination = this.gainNode;\n component.onload(this.audioBufferCache[audio.name]);\n }\n } catch (error) {\n if (this.onError) {\n this.onError(error);\n }\n }\n }\n\n private decodeAudioData(arraybuffer: ArrayBuffer, name: string) {\n if (this.decodeAudioPromiseMap[name]) {\n return this.decodeAudioPromiseMap[name];\n }\n\n const promise = new Promise<AudioBuffer>((resolve, reject) => {\n if (!this.ctx) {\n reject(new Error('No audio support'));\n }\n\n const success = (decodedData: AudioBuffer) => {\n if (this.decodeAudioPromiseMap[name]) {\n delete this.decodeAudioPromiseMap[name];\n }\n if (decodedData) {\n resolve(decodedData);\n } else {\n reject(new Error(`Error decoding audio ${name}`));\n }\n };\n\n const error = (err: DOMException) => {\n if (this.decodeAudioPromiseMap[name]) {\n delete this.decodeAudioPromiseMap[name];\n }\n reject(new Error(`${err}. arrayBuffer byteLength: ${arraybuffer ? arraybuffer.byteLength : 0}`));\n };\n\n const promise = this.ctx.decodeAudioData(arraybuffer, success, error)\n if (promise instanceof Promise) {\n promise.catch((err) => {\n reject(new Error(`catch ${err}, arrayBuffer byteLength: ${arraybuffer ? arraybuffer.byteLength : 0}`));\n });\n }\n });\n\n this.decodeAudioPromiseMap[name] = promise;\n return promise;\n }\n}\n\nexport default SoundSystem;\n","/** Auto-generated by scripts/build-package.mjs — do not edit. */\n\nimport SoundSystem from './SoundSystem';\n\nObject.assign(SoundSystem, {\n packageName: \"@combos-fun/plugin-sound\",\n packageVersion: \"0.0.46\",\n});\n","import { Component } from '@combos-fun/engine';\nimport { Field } from '@combos-fun/inspector-decorator';\n\nexport interface SoundParams {\n resource: string;\n autoplay?: boolean;\n muted?: boolean;\n volume?: number;\n loop?: boolean;\n seek?: number;\n duration?: number;\n onEnd?: () => void;\n}\n\nclass Sound extends Component<SoundParams> {\n static componentName = 'Sound';\n\n systemContext: AudioContext;\n\n systemDestination: GainNode;\n\n playing: boolean;\n\n state: 'unloaded' | 'loading' | 'loaded' = 'unloaded';\n\n config: SoundParams = {\n resource: '',\n autoplay: false,\n muted: false,\n volume: 1,\n loop: false,\n seek: 0,\n };\n\n private buffer: AudioBuffer;\n\n private sourceNode: AudioBufferSourceNode;\n\n private gainNode: GainNode;\n\n private paused: boolean;\n\n private playTime: number = 0;\n\n private startTime: number = 0;\n\n private duration: number = 0;\n\n private actionQueue: (() => void)[] = [];\n\n private endedListener: () => void;\n\n @Field({\n type: 'boolean',\n group: 'Sound',\n label: 'Muted',\n description: 'Silence this sound without changing its volume setting.',\n editor: 'toggle',\n })\n get muted(): boolean {\n return this.config.muted ?? false;\n }\n\n set muted(v: boolean) {\n this.config.muted = v;\n this.applyGain();\n }\n\n @Field({\n type: 'number',\n min: 0,\n max: 1,\n step: 0.01,\n group: 'Sound',\n label: 'Volume',\n description: 'Loudness of this sound from 0 (silent) to 1 (full).',\n editor: 'volume-slider',\n })\n get volume(): number {\n return this.config.volume ?? 1;\n }\n\n set volume(v: number) {\n if (typeof v !== 'number' || v < 0 || v > 1) {\n return;\n }\n this.config.volume = v;\n this.applyGain();\n }\n\n @Field({\n type: 'boolean',\n group: 'Sound',\n label: 'Loop',\n description: 'Replay the sound continuously when it reaches the end.',\n editor: 'toggle',\n })\n get loop(): boolean {\n return this.config.loop ?? false;\n }\n\n set loop(v: boolean) {\n this.config.loop = v;\n if (this.sourceNode) {\n this.sourceNode.loop = v;\n }\n }\n\n @Field({\n type: 'boolean',\n group: 'Sound',\n label: 'Autoplay',\n description: 'Start playing automatically once the audio has loaded.',\n editor: 'toggle',\n })\n get autoplay(): boolean {\n return this.config.autoplay ?? false;\n }\n\n set autoplay(v: boolean) {\n this.config.autoplay = v;\n }\n\n @Field({\n type: 'string',\n group: 'Sound',\n label: 'Resource',\n description: 'Audio resource id used by the sound system.',\n editor: 'text',\n })\n get resource(): string {\n return this.config.resource ?? '';\n }\n\n set resource(v: string) {\n this.config.resource = v;\n }\n\n /**\n * Apply the effective gain (`muted ? 0 : volume`) to the gain node.\n *\n * `config` is the source of truth and the gain is assigned via `gain.value`\n * (updates the AudioParam intrinsic value synchronously) so the `muted` /\n * `volume` getters — and anything reading them back, e.g. the scene-edit\n * volume slider — reflect the change immediately. `setValueAtTime` only\n * schedules on the automation timeline and leaves `.value` stale.\n */\n private applyGain() {\n if (!this.gainNode) {\n return;\n }\n this.gainNode.gain.value = this.config.muted ? 0 : (this.config.volume ?? 1);\n }\n\n init(obj?: SoundParams) {\n if (!obj) {\n return;\n }\n\n Object.assign(this.config, obj);\n if (this.config.autoplay) {\n this.actionQueue.push(this.play.bind(this));\n }\n }\n\n play() {\n if (this.state !== 'loaded') {\n this.actionQueue.push(this.play.bind(this));\n }\n this.destroySource();\n this.createSource();\n\n if (!this.sourceNode) {\n return;\n }\n const when = this.systemContext.currentTime;\n const offset = this.config.seek;\n const duration = this.config.duration;\n\n this.sourceNode.start(0, offset, duration);\n\n this.startTime = when;\n this.playTime = when - offset;\n this.paused = false;\n this.playing = true;\n this.resetConfig();\n this.endedListener = () => {\n if (!this.sourceNode) {\n return;\n }\n if (this.config.onEnd) {\n this.config.onEnd();\n }\n // Release resources once non-interactive playback finishes.\n if (this.playing) {\n this.destroySource();\n }\n };\n this.sourceNode.addEventListener('ended', this.endedListener);\n }\n\n pause() {\n if (this.state !== 'loaded') {\n this.actionQueue.push(this.pause.bind(this));\n }\n if (this.paused || !this.playing) {\n return;\n }\n this.paused = true;\n this.playing = false;\n this.config.seek = this.getCurrentTime();\n this.destroySource();\n }\n\n stop() {\n if (this.state !== 'loaded') {\n this.actionQueue.push(this.stop.bind(this));\n }\n if (!this.paused && !this.playing) {\n return;\n }\n this.playing = false;\n this.paused = false;\n this.destroySource();\n this.resetConfig();\n }\n\n onload(buffer: AudioBuffer) {\n this.state = 'loaded';\n this.buffer = buffer;\n this.duration = this.buffer.duration;\n this.actionQueue.forEach(action => action());\n this.actionQueue.length = 0;\n }\n\n onDestroy() {\n this.actionQueue.length = 0;\n this.destroySource();\n }\n\n private resetConfig() {\n this.config.seek = 0;\n }\n\n private getCurrentTime() {\n if (this.config.loop && this.duration > 0) {\n return (this.systemContext.currentTime - this.playTime) % this.duration;\n }\n\n return this.systemContext.currentTime - this.playTime;\n }\n\n private createSource() {\n if (!this.systemContext || this.state !== 'loaded') {\n return;\n }\n this.sourceNode = this.systemContext.createBufferSource();\n this.sourceNode.buffer = this.buffer;\n this.sourceNode.loop = this.config.loop;\n\n if (!this.gainNode) {\n this.gainNode = this.systemContext.createGain();\n this.gainNode.connect(this.systemDestination);\n Object.assign(this, this.config);\n }\n this.sourceNode.connect(this.gainNode);\n }\n\n private destroySource() {\n if (!this.sourceNode) return;\n this.sourceNode.removeEventListener('ended', this.endedListener);\n this.sourceNode.stop();\n this.sourceNode.disconnect();\n this.sourceNode = null;\n\n this.startTime = 0;\n this.playTime = 0;\n this.playing = false;\n }\n}\n\nexport default Sound;\n"],"names":["SoundSystem","System","OBSERVER_TYPE","resource","__decorate","decorators","Component","Field"],"mappings":"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"}
1
+ {"version":3,"file":"plugin-sound.cjs.js","sources":["../lib/hostMessages.ts","../lib/SoundSystem.ts","../lib/__combosPackageMeta.gen.ts","../lib/Sound.ts"],"sourcesContent":["/** Parent → iframe (also `window` CustomEvent / `game.emit`): mute or unmute. Payload: `{ muted: boolean }`. */\nexport const COMBOS_DEVELOPMENT_TOOL_SET_MUTED =\n 'combos-development-tool:set-muted' as const;\n\n/** iframe → parent (and `game.emit`): current mute snapshot after a successful change. */\nexport const COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED =\n 'combos-development-tool:state-changed' as const;\n\nexport interface CombosSoundSetMutedMessage {\n type: typeof COMBOS_DEVELOPMENT_TOOL_SET_MUTED;\n muted: boolean;\n}\n\nexport interface CombosSoundStateChangedMessage {\n type: typeof COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED;\n muted: boolean;\n}\n\nexport function parseSetMutedMessage(data: unknown): boolean | null {\n if (!data || typeof data !== 'object') return null;\n const d = data as { type?: unknown; muted?: unknown };\n if (d.type !== COMBOS_DEVELOPMENT_TOOL_SET_MUTED) return null;\n if (typeof d.muted !== 'boolean') return null;\n return d.muted;\n}\n\nexport function parseSetMutedCustomEvent(event: Event): boolean | null {\n const d = (event as CustomEvent<{ muted?: unknown }>).detail;\n if (!d || typeof d !== 'object' || typeof d.muted !== 'boolean') return null;\n return d.muted;\n}\n\nfunction postToParent(payload: object, targetOrigin: string): void {\n if (typeof window === 'undefined') return;\n if (!window.parent || window.parent === window) return;\n try {\n window.parent.postMessage(payload, targetOrigin);\n } catch {\n /* ignore cross-origin or detached frame */\n }\n}\n\n/** Notifies the embedding page (and `game.emit`) of the current mute flag. */\nexport function postParentSoundMuted(\n muted: boolean,\n targetOrigin: string,\n emit?: (type: string, payload: { muted: boolean }) => void,\n): void {\n const state = { muted };\n postToParent({ type: COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED, ...state }, targetOrigin);\n emit?.(COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED, state);\n}\n","import {\n System,\n decorators,\n ComponentChanged,\n OBSERVER_TYPE,\n resource,\n isAllowedMessageOrigin,\n mergeAllowedMessageOrigins,\n} from '@combos-fun/engine';\nimport SoundComponent from './Sound';\nimport {\n COMBOS_DEVELOPMENT_TOOL_SET_MUTED,\n parseSetMutedCustomEvent,\n parseSetMutedMessage,\n postParentSoundMuted,\n} from './hostMessages';\n\ninterface SoundSystemParams {\n autoPauseAndStart?: boolean;\n onError?: (error: any) => void;\n /** postMessage `targetOrigin` when notifying parent (default: Game `pluginInitNotifyTargetOrigin` or `'*'`). */\n postMessageOrigin?: string;\n /**\n * Extra inbound `postMessage` origins merged with engine defaults (`knoffice.tech`, `converge.ai`).\n * Each entry is a host suffix (e.g. `localhost`) or a full origin. Pass `['*']` to accept any origin.\n */\n allowedMessageOrigins?: string[];\n}\n\n@decorators.componentObserver({\n Sound: [],\n})\nclass SoundSystem extends System {\n static systemName = 'SoundSystem';\n\n private ctx: AudioContext;\n\n private gainNode: GainNode;\n\n /** Whether to pause/resume in sync with the game. */\n private autoPauseAndStart = true;\n\n private onError: (error: any) => void;\n\n private components: SoundComponent[] = [];\n\n private pausedComponents: SoundComponent[] = [];\n\n private audioBufferCache = {};\n\n private decodeAudioPromiseMap = {};\n\n /** Desired mute/volume are the source of truth; the gain node is derived. */\n private _muted = false;\n\n private _volume = 1;\n\n private postMessageOrigin = '*';\n\n private allowedMessageOrigins = mergeAllowedMessageOrigins();\n\n private hostMuteBound = false;\n\n get muted(): boolean {\n return this._muted;\n }\n\n set muted(v: boolean) {\n this.setMuted(v);\n }\n\n get volume(): number {\n return this._volume;\n }\n\n set volume(v: number) {\n if (typeof v !== 'number' || v < 0 || v > 1) {\n return;\n }\n this._volume = v;\n this.applyGain();\n }\n\n /**\n * Apply the effective gain (`muted ? 0 : volume`) to the gain node.\n *\n * Assigns `gain.value` directly rather than `setValueAtTime`: `.value` updates\n * the AudioParam's intrinsic value synchronously, so the `muted` / `volume`\n * getters reflect the change immediately. `setValueAtTime` only schedules an\n * event on the automation timeline and leaves `.value` stale until the next\n * render quantum, which made `muted` report the pre-change value.\n */\n private applyGain() {\n if (!this.gainNode) {\n return;\n }\n this.gainNode.gain.value = this._muted ? 0 : this._volume;\n }\n\n get audioLocked(): boolean {\n if (!this.ctx) {\n return true;\n }\n return this.ctx.state !== 'running';\n }\n\n constructor(obj?: SoundSystemParams) {\n super();\n if (!obj) return;\n if (typeof obj.autoPauseAndStart === 'boolean') {\n this.autoPauseAndStart = obj.autoPauseAndStart;\n }\n if (obj.onError) {\n this.onError = obj.onError;\n }\n }\n\n /**\n * Mute or unmute the master gain and notify the embedding host.\n * Same effect as `postMessage({ type: 'combos-development-tool:set-muted', muted })`.\n */\n setMuted(muted: boolean) {\n const next = !!muted;\n if (this._muted === next) {\n return;\n }\n this._muted = next;\n this.applyGain();\n this.postMuteStateChanged();\n }\n\n /**\n * Resume playback of all paused audio.\n */\n resumeAll() {\n const handleResume = () => {\n this.pausedComponents.forEach(component => {\n component.play();\n });\n // Clear the previously cached paused list.\n this.pausedComponents = [];\n };\n this.ctx.resume().then(handleResume, handleResume);\n }\n\n /**\n * Pause all currently playing audio.\n */\n pauseAll() {\n this.components.forEach(component => {\n if (component.playing) {\n this.pausedComponents.push(component);\n component.pause();\n }\n });\n this.ctx.suspend().then();\n }\n\n /**\n * Stop all currently playing audio.\n */\n stopAll() {\n this.components.forEach(component => {\n if (component.playing) {\n component.stop();\n }\n });\n // Clear the previously cached paused list.\n this.pausedComponents = [];\n this.ctx.suspend().then();\n }\n\n /**\n * System init: configure params before the game starts.\n */\n init(params?: SoundSystemParams) {\n this.postMessageOrigin =\n params?.postMessageOrigin ?? this.game?.pluginInitNotifyTargetOrigin ?? '*';\n this.allowedMessageOrigins = mergeAllowedMessageOrigins(params?.allowedMessageOrigins);\n this.bindHostMute();\n this.setupAudioContext();\n }\n\n update() {\n const changes = this.componentObserver.clear();\n for (const changed of changes) {\n this.componentChanged(changed);\n }\n }\n\n /**\n * Called when the game starts or resumes playing after a pause.\n */\n onResume() {\n if (!this.autoPauseAndStart) {\n return;\n }\n this.resumeAll();\n }\n\n /**\n * Called when the game is paused.\n */\n onPause() {\n if (!this.autoPauseAndStart) {\n return;\n }\n this.pauseAll();\n }\n\n /**\n * Called when the system is destroyed.\n */\n onDestroy() {\n this.unbindHostMute();\n this.components.forEach(component => {\n component.onDestroy();\n });\n this.components = [];\n if (this.ctx) {\n this.gainNode.disconnect();\n this.gainNode = null;\n this.ctx.close();\n this.ctx = null;\n }\n }\n\n private readonly onWindowSetMuted = (e: Event) => {\n const muted = parseSetMutedCustomEvent(e);\n if (muted === null) return;\n this.setMuted(muted);\n };\n\n private readonly onGameSetMuted = (payload: { muted?: boolean }) => {\n if (payload && typeof payload.muted === 'boolean') {\n this.setMuted(payload.muted);\n }\n };\n\n private readonly onWindowMessage = (e: MessageEvent) => {\n if (!isAllowedMessageOrigin(e.origin, this.allowedMessageOrigins)) {\n return;\n }\n const muted = parseSetMutedMessage(e.data);\n if (muted === null) return;\n this.setMuted(muted);\n };\n\n private bindHostMute() {\n if (this.hostMuteBound) return;\n this.hostMuteBound = true;\n if (typeof window !== 'undefined') {\n window.addEventListener(COMBOS_DEVELOPMENT_TOOL_SET_MUTED, this.onWindowSetMuted);\n window.addEventListener('message', this.onWindowMessage);\n }\n this.game.on(COMBOS_DEVELOPMENT_TOOL_SET_MUTED, this.onGameSetMuted);\n }\n\n private unbindHostMute() {\n if (!this.hostMuteBound) return;\n this.hostMuteBound = false;\n if (typeof window !== 'undefined') {\n window.removeEventListener(COMBOS_DEVELOPMENT_TOOL_SET_MUTED, this.onWindowSetMuted);\n window.removeEventListener('message', this.onWindowMessage);\n }\n this.game?.off(COMBOS_DEVELOPMENT_TOOL_SET_MUTED, this.onGameSetMuted);\n }\n\n private postMuteStateChanged() {\n postParentSoundMuted(this._muted, this.postMessageOrigin, (type, payload) => {\n this.game?.emit(type, payload);\n });\n }\n\n async componentChanged(changed: ComponentChanged) {\n if (changed.componentName !== 'Sound') return;\n\n if (changed.type === OBSERVER_TYPE.ADD) {\n this.add(changed);\n }\n }\n\n private setupAudioContext() {\n try {\n const AudioContext = window.AudioContext || (window as any).webkitAudioContext;\n this.ctx = new AudioContext();\n } catch (error) {\n console.error(error);\n if (this.onError) {\n this.onError(error);\n }\n }\n\n if (!this.ctx) {\n return;\n }\n this.gainNode =\n typeof this.ctx.createGain === 'undefined' ? (this.ctx as any).createGainNode() : this.ctx.createGain();\n this.applyGain();\n this.gainNode.connect(this.ctx.destination);\n this.unlockAudio();\n }\n\n private unlockAudio() {\n if (!this.ctx || !this.audioLocked) {\n return;\n }\n\n const unlock = () => {\n if (this.ctx) {\n const removeListenerFn = () => {\n document.body.removeEventListener('touchstart', unlock);\n document.body.removeEventListener('touchend', unlock);\n document.body.removeEventListener('click', unlock);\n };\n this.ctx.resume().then(removeListenerFn, removeListenerFn);\n }\n };\n document.body.addEventListener('touchstart', unlock);\n document.body.addEventListener('touchend', unlock);\n document.body.addEventListener('click', unlock);\n }\n\n private async add(changed: ComponentChanged) {\n const component = changed.component as SoundComponent;\n this.components.push(component);\n try {\n const { config } = component;\n component.state = 'loading';\n\n const audio = await resource.getResource(config.resource);\n if (!this.audioBufferCache[audio.name] && audio?.data?.audio) {\n this.audioBufferCache[audio.name] = await this.decodeAudioData(audio.data.audio, audio.name);\n }\n if (this.audioBufferCache[audio.name]) {\n component.systemContext = this.ctx;\n component.systemDestination = this.gainNode;\n component.onload(this.audioBufferCache[audio.name]);\n }\n } catch (error) {\n if (this.onError) {\n this.onError(error);\n }\n }\n }\n\n private decodeAudioData(arraybuffer: ArrayBuffer, name: string) {\n if (this.decodeAudioPromiseMap[name]) {\n return this.decodeAudioPromiseMap[name];\n }\n\n const promise = new Promise<AudioBuffer>((resolve, reject) => {\n if (!this.ctx) {\n reject(new Error('No audio support'));\n }\n\n const success = (decodedData: AudioBuffer) => {\n if (this.decodeAudioPromiseMap[name]) {\n delete this.decodeAudioPromiseMap[name];\n }\n if (decodedData) {\n resolve(decodedData);\n } else {\n reject(new Error(`Error decoding audio ${name}`));\n }\n };\n\n const error = (err: DOMException) => {\n if (this.decodeAudioPromiseMap[name]) {\n delete this.decodeAudioPromiseMap[name];\n }\n reject(new Error(`${err}. arrayBuffer byteLength: ${arraybuffer ? arraybuffer.byteLength : 0}`));\n };\n\n const promise = this.ctx.decodeAudioData(arraybuffer, success, error)\n if (promise instanceof Promise) {\n promise.catch((err) => {\n reject(new Error(`catch ${err}, arrayBuffer byteLength: ${arraybuffer ? arraybuffer.byteLength : 0}`));\n });\n }\n });\n\n this.decodeAudioPromiseMap[name] = promise;\n return promise;\n }\n}\n\nexport default SoundSystem;\n","/** Auto-generated by scripts/build-package.mjs — do not edit. */\n\nimport SoundSystem from './SoundSystem';\n\nObject.assign(SoundSystem, {\n packageName: \"@combos-fun/plugin-sound\",\n packageVersion: \"0.0.48\",\n});\n","import { Component } from '@combos-fun/engine';\nimport { Field } from '@combos-fun/inspector-decorator';\n\nexport interface SoundParams {\n resource: string;\n autoplay?: boolean;\n muted?: boolean;\n volume?: number;\n loop?: boolean;\n seek?: number;\n duration?: number;\n onEnd?: () => void;\n}\n\nclass Sound extends Component<SoundParams> {\n static componentName = 'Sound';\n\n systemContext: AudioContext;\n\n systemDestination: GainNode;\n\n playing: boolean;\n\n state: 'unloaded' | 'loading' | 'loaded' = 'unloaded';\n\n config: SoundParams = {\n resource: '',\n autoplay: false,\n muted: false,\n volume: 1,\n loop: false,\n seek: 0,\n };\n\n private buffer: AudioBuffer;\n\n private sourceNode: AudioBufferSourceNode;\n\n private gainNode: GainNode;\n\n private paused: boolean;\n\n private playTime: number = 0;\n\n private startTime: number = 0;\n\n private duration: number = 0;\n\n private actionQueue: (() => void)[] = [];\n\n private endedListener: () => void;\n\n @Field({\n type: 'boolean',\n group: 'Sound',\n label: 'Muted',\n description: 'Silence this sound without changing its volume setting.',\n editor: 'toggle',\n })\n get muted(): boolean {\n return this.config.muted ?? false;\n }\n\n set muted(v: boolean) {\n this.config.muted = v;\n this.applyGain();\n }\n\n @Field({\n type: 'number',\n min: 0,\n max: 1,\n step: 0.01,\n group: 'Sound',\n label: 'Volume',\n description: 'Loudness of this sound from 0 (silent) to 1 (full).',\n editor: 'volume-slider',\n })\n get volume(): number {\n return this.config.volume ?? 1;\n }\n\n set volume(v: number) {\n if (typeof v !== 'number' || v < 0 || v > 1) {\n return;\n }\n this.config.volume = v;\n this.applyGain();\n }\n\n @Field({\n type: 'boolean',\n group: 'Sound',\n label: 'Loop',\n description: 'Replay the sound continuously when it reaches the end.',\n editor: 'toggle',\n })\n get loop(): boolean {\n return this.config.loop ?? false;\n }\n\n set loop(v: boolean) {\n this.config.loop = v;\n if (this.sourceNode) {\n this.sourceNode.loop = v;\n }\n }\n\n @Field({\n type: 'boolean',\n group: 'Sound',\n label: 'Autoplay',\n description: 'Start playing automatically once the audio has loaded.',\n editor: 'toggle',\n })\n get autoplay(): boolean {\n return this.config.autoplay ?? false;\n }\n\n set autoplay(v: boolean) {\n this.config.autoplay = v;\n }\n\n @Field({\n type: 'string',\n group: 'Sound',\n label: 'Resource',\n description: 'Audio resource id used by the sound system.',\n editor: 'text',\n })\n get resource(): string {\n return this.config.resource ?? '';\n }\n\n set resource(v: string) {\n this.config.resource = v;\n }\n\n /**\n * Apply the effective gain (`muted ? 0 : volume`) to the gain node.\n *\n * `config` is the source of truth and the gain is assigned via `gain.value`\n * (updates the AudioParam intrinsic value synchronously) so the `muted` /\n * `volume` getters — and anything reading them back, e.g. the scene-edit\n * volume slider — reflect the change immediately. `setValueAtTime` only\n * schedules on the automation timeline and leaves `.value` stale.\n */\n private applyGain() {\n if (!this.gainNode) {\n return;\n }\n this.gainNode.gain.value = this.config.muted ? 0 : (this.config.volume ?? 1);\n }\n\n init(obj?: SoundParams) {\n if (!obj) {\n return;\n }\n\n Object.assign(this.config, obj);\n if (this.config.autoplay) {\n this.actionQueue.push(this.play.bind(this));\n }\n }\n\n play() {\n if (this.state !== 'loaded') {\n this.actionQueue.push(this.play.bind(this));\n }\n this.destroySource();\n this.createSource();\n\n if (!this.sourceNode) {\n return;\n }\n const when = this.systemContext.currentTime;\n const offset = this.config.seek;\n const duration = this.config.duration;\n\n this.sourceNode.start(0, offset, duration);\n\n this.startTime = when;\n this.playTime = when - offset;\n this.paused = false;\n this.playing = true;\n this.resetConfig();\n this.endedListener = () => {\n if (!this.sourceNode) {\n return;\n }\n if (this.config.onEnd) {\n this.config.onEnd();\n }\n // Release resources once non-interactive playback finishes.\n if (this.playing) {\n this.destroySource();\n }\n };\n this.sourceNode.addEventListener('ended', this.endedListener);\n }\n\n pause() {\n if (this.state !== 'loaded') {\n this.actionQueue.push(this.pause.bind(this));\n }\n if (this.paused || !this.playing) {\n return;\n }\n this.paused = true;\n this.playing = false;\n this.config.seek = this.getCurrentTime();\n this.destroySource();\n }\n\n stop() {\n if (this.state !== 'loaded') {\n this.actionQueue.push(this.stop.bind(this));\n }\n if (!this.paused && !this.playing) {\n return;\n }\n this.playing = false;\n this.paused = false;\n this.destroySource();\n this.resetConfig();\n }\n\n onload(buffer: AudioBuffer) {\n this.state = 'loaded';\n this.buffer = buffer;\n this.duration = this.buffer.duration;\n this.actionQueue.forEach(action => action());\n this.actionQueue.length = 0;\n }\n\n onDestroy() {\n this.actionQueue.length = 0;\n this.destroySource();\n }\n\n private resetConfig() {\n this.config.seek = 0;\n }\n\n private getCurrentTime() {\n if (this.config.loop && this.duration > 0) {\n return (this.systemContext.currentTime - this.playTime) % this.duration;\n }\n\n return this.systemContext.currentTime - this.playTime;\n }\n\n private createSource() {\n if (!this.systemContext || this.state !== 'loaded') {\n return;\n }\n this.sourceNode = this.systemContext.createBufferSource();\n this.sourceNode.buffer = this.buffer;\n this.sourceNode.loop = this.config.loop;\n\n if (!this.gainNode) {\n this.gainNode = this.systemContext.createGain();\n this.gainNode.connect(this.systemDestination);\n Object.assign(this, this.config);\n }\n this.sourceNode.connect(this.gainNode);\n }\n\n private destroySource() {\n if (!this.sourceNode) return;\n this.sourceNode.removeEventListener('ended', this.endedListener);\n this.sourceNode.stop();\n this.sourceNode.disconnect();\n this.sourceNode = null;\n\n this.startTime = 0;\n this.playTime = 0;\n this.playing = false;\n }\n}\n\nexport default Sound;\n"],"names":["SoundSystem","System","mergeAllowedMessageOrigins","isAllowedMessageOrigin","OBSERVER_TYPE","resource","__decorate","decorators","Component","Field"],"mappings":"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"}
@@ -1 +1 @@
1
- "use strict";var t=require("tslib"),e=require("@combos-fun/engine"),o=require("@combos-fun/inspector-decorator");let s=class extends e.System{static{this.systemName="SoundSystem"}get muted(){return this._muted}set muted(t){this._muted=t,this.applyGain()}get volume(){return this._volume}set volume(t){"number"!=typeof t||t<0||t>1||(this._volume=t,this.applyGain())}applyGain(){this.gainNode&&(this.gainNode.gain.value=this._muted?0:this._volume)}get audioLocked(){return!this.ctx||"running"!==this.ctx.state}constructor(t){super(),this.autoPauseAndStart=!0,this.components=[],this.pausedComponents=[],this.audioBufferCache={},this.decodeAudioPromiseMap={},this._muted=!1,this._volume=1,Object.assign(this,t)}resumeAll(){const t=()=>{this.pausedComponents.forEach(t=>{t.play()}),this.pausedComponents=[]};this.ctx.resume().then(t,t)}pauseAll(){this.components.forEach(t=>{t.playing&&(this.pausedComponents.push(t),t.pause())}),this.ctx.suspend().then()}stopAll(){this.components.forEach(t=>{t.playing&&t.stop()}),this.pausedComponents=[],this.ctx.suspend().then()}init(){this.setupAudioContext()}update(){const t=this.componentObserver.clear();for(const e of t)this.componentChanged(e)}onResume(){this.autoPauseAndStart&&this.resumeAll()}onPause(){this.autoPauseAndStart&&this.pauseAll()}onDestroy(){this.components.forEach(t=>{t.onDestroy()}),this.components=[],this.ctx&&(this.gainNode.disconnect(),this.gainNode=null,this.ctx.close(),this.ctx=null)}async componentChanged(t){"Sound"===t.componentName&&t.type===e.OBSERVER_TYPE.ADD&&this.add(t)}setupAudioContext(){try{const t=window.AudioContext||window.webkitAudioContext;this.ctx=new t}catch(t){console.error(t),this.onError&&this.onError(t)}this.ctx&&(this.gainNode=void 0===this.ctx.createGain?this.ctx.createGainNode():this.ctx.createGain(),this.applyGain(),this.gainNode.connect(this.ctx.destination),this.unlockAudio())}unlockAudio(){if(!this.ctx||!this.audioLocked)return;const t=()=>{if(this.ctx){const e=()=>{document.body.removeEventListener("touchstart",t),document.body.removeEventListener("touchend",t),document.body.removeEventListener("click",t)};this.ctx.resume().then(e,e)}};document.body.addEventListener("touchstart",t),document.body.addEventListener("touchend",t),document.body.addEventListener("click",t)}async add(t){const o=t.component;this.components.push(o);try{const{config:t}=o;o.state="loading";const s=await e.resource.getResource(t.resource);!this.audioBufferCache[s.name]&&s?.data?.audio&&(this.audioBufferCache[s.name]=await this.decodeAudioData(s.data.audio,s.name)),this.audioBufferCache[s.name]&&(o.systemContext=this.ctx,o.systemDestination=this.gainNode,o.onload(this.audioBufferCache[s.name]))}catch(t){this.onError&&this.onError(t)}}decodeAudioData(t,e){if(this.decodeAudioPromiseMap[e])return this.decodeAudioPromiseMap[e];const o=new Promise((o,s)=>{this.ctx||s(new Error("No audio support"));const i=this.ctx.decodeAudioData(t,t=>{this.decodeAudioPromiseMap[e]&&delete this.decodeAudioPromiseMap[e],t?o(t):s(new Error(`Error decoding audio ${e}`))},o=>{this.decodeAudioPromiseMap[e]&&delete this.decodeAudioPromiseMap[e],s(new Error(`${o}. arrayBuffer byteLength: ${t?t.byteLength:0}`))});i instanceof Promise&&i.catch(e=>{s(new Error(`catch ${e}, arrayBuffer byteLength: ${t?t.byteLength:0}`))})});return this.decodeAudioPromiseMap[e]=o,o}};s=t.__decorate([e.decorators.componentObserver({Sound:[]})],s);var i=s;Object.assign(i,{packageName:"@combos-fun/plugin-sound",packageVersion:"0.0.46"});class n extends e.Component{constructor(){super(...arguments),this.state="unloaded",this.config={resource:"",autoplay:!1,muted:!1,volume:1,loop:!1,seek:0},this.playTime=0,this.startTime=0,this.duration=0,this.actionQueue=[]}static{this.componentName="Sound"}get muted(){return this.config.muted??!1}set muted(t){this.config.muted=t,this.applyGain()}get volume(){return this.config.volume??1}set volume(t){"number"!=typeof t||t<0||t>1||(this.config.volume=t,this.applyGain())}get loop(){return this.config.loop??!1}set loop(t){this.config.loop=t,this.sourceNode&&(this.sourceNode.loop=t)}get autoplay(){return this.config.autoplay??!1}set autoplay(t){this.config.autoplay=t}get resource(){return this.config.resource??""}set resource(t){this.config.resource=t}applyGain(){this.gainNode&&(this.gainNode.gain.value=this.config.muted?0:this.config.volume??1)}init(t){t&&(Object.assign(this.config,t),this.config.autoplay&&this.actionQueue.push(this.play.bind(this)))}play(){if("loaded"!==this.state&&this.actionQueue.push(this.play.bind(this)),this.destroySource(),this.createSource(),!this.sourceNode)return;const t=this.systemContext.currentTime,e=this.config.seek,o=this.config.duration;this.sourceNode.start(0,e,o),this.startTime=t,this.playTime=t-e,this.paused=!1,this.playing=!0,this.resetConfig(),this.endedListener=()=>{this.sourceNode&&(this.config.onEnd&&this.config.onEnd(),this.playing&&this.destroySource())},this.sourceNode.addEventListener("ended",this.endedListener)}pause(){"loaded"!==this.state&&this.actionQueue.push(this.pause.bind(this)),!this.paused&&this.playing&&(this.paused=!0,this.playing=!1,this.config.seek=this.getCurrentTime(),this.destroySource())}stop(){"loaded"!==this.state&&this.actionQueue.push(this.stop.bind(this)),(this.paused||this.playing)&&(this.playing=!1,this.paused=!1,this.destroySource(),this.resetConfig())}onload(t){this.state="loaded",this.buffer=t,this.duration=this.buffer.duration,this.actionQueue.forEach(t=>t()),this.actionQueue.length=0}onDestroy(){this.actionQueue.length=0,this.destroySource()}resetConfig(){this.config.seek=0}getCurrentTime(){return this.config.loop&&this.duration>0?(this.systemContext.currentTime-this.playTime)%this.duration:this.systemContext.currentTime-this.playTime}createSource(){this.systemContext&&"loaded"===this.state&&(this.sourceNode=this.systemContext.createBufferSource(),this.sourceNode.buffer=this.buffer,this.sourceNode.loop=this.config.loop,this.gainNode||(this.gainNode=this.systemContext.createGain(),this.gainNode.connect(this.systemDestination),Object.assign(this,this.config)),this.sourceNode.connect(this.gainNode))}destroySource(){this.sourceNode&&(this.sourceNode.removeEventListener("ended",this.endedListener),this.sourceNode.stop(),this.sourceNode.disconnect(),this.sourceNode=null,this.startTime=0,this.playTime=0,this.playing=!1)}}t.__decorate([o.Field({type:"boolean",group:"Sound",label:"Muted",description:"Silence this sound without changing its volume setting.",editor:"toggle"})],n.prototype,"muted",null),t.__decorate([o.Field({type:"number",min:0,max:1,step:.01,group:"Sound",label:"Volume",description:"Loudness of this sound from 0 (silent) to 1 (full).",editor:"volume-slider"})],n.prototype,"volume",null),t.__decorate([o.Field({type:"boolean",group:"Sound",label:"Loop",description:"Replay the sound continuously when it reaches the end.",editor:"toggle"})],n.prototype,"loop",null),t.__decorate([o.Field({type:"boolean",group:"Sound",label:"Autoplay",description:"Start playing automatically once the audio has loaded.",editor:"toggle"})],n.prototype,"autoplay",null),t.__decorate([o.Field({type:"string",group:"Sound",label:"Resource",description:"Audio resource id used by the sound system.",editor:"text"})],n.prototype,"resource",null),exports.Sound=n,exports.SoundSystem=i;
1
+ "use strict";var t=require("tslib"),e=require("@combos-fun/engine"),o=require("@combos-fun/inspector-decorator");const s="combos-development-tool:set-muted",i="combos-development-tool:state-changed";function n(t){if(!t||"object"!=typeof t)return null;const e=t;return e.type!==s||"boolean"!=typeof e.muted?null:e.muted}function u(t,e,o){const s={muted:t};!function(t,e){if("undefined"!=typeof window&&window.parent&&window.parent!==window)try{window.parent.postMessage(t,e)}catch{}}({type:i,...s},e),o?.(i,s)}let d=class extends e.System{static{this.systemName="SoundSystem"}get muted(){return this._muted}set muted(t){this.setMuted(t)}get volume(){return this._volume}set volume(t){"number"!=typeof t||t<0||t>1||(this._volume=t,this.applyGain())}applyGain(){this.gainNode&&(this.gainNode.gain.value=this._muted?0:this._volume)}get audioLocked(){return!this.ctx||"running"!==this.ctx.state}constructor(t){super(),this.autoPauseAndStart=!0,this.components=[],this.pausedComponents=[],this.audioBufferCache={},this.decodeAudioPromiseMap={},this._muted=!1,this._volume=1,this.postMessageOrigin="*",this.allowedMessageOrigins=e.mergeAllowedMessageOrigins(),this.hostMuteBound=!1,this.onWindowSetMuted=t=>{const e=function(t){const e=t.detail;return e&&"object"==typeof e&&"boolean"==typeof e.muted?e.muted:null}(t);null!==e&&this.setMuted(e)},this.onGameSetMuted=t=>{t&&"boolean"==typeof t.muted&&this.setMuted(t.muted)},this.onWindowMessage=t=>{if(!e.isAllowedMessageOrigin(t.origin,this.allowedMessageOrigins))return;const o=n(t.data);null!==o&&this.setMuted(o)},t&&("boolean"==typeof t.autoPauseAndStart&&(this.autoPauseAndStart=t.autoPauseAndStart),t.onError&&(this.onError=t.onError))}setMuted(t){const e=!!t;this._muted!==e&&(this._muted=e,this.applyGain(),this.postMuteStateChanged())}resumeAll(){const t=()=>{this.pausedComponents.forEach(t=>{t.play()}),this.pausedComponents=[]};this.ctx.resume().then(t,t)}pauseAll(){this.components.forEach(t=>{t.playing&&(this.pausedComponents.push(t),t.pause())}),this.ctx.suspend().then()}stopAll(){this.components.forEach(t=>{t.playing&&t.stop()}),this.pausedComponents=[],this.ctx.suspend().then()}init(t){this.postMessageOrigin=t?.postMessageOrigin??this.game?.pluginInitNotifyTargetOrigin??"*",this.allowedMessageOrigins=e.mergeAllowedMessageOrigins(t?.allowedMessageOrigins),this.bindHostMute(),this.setupAudioContext()}update(){const t=this.componentObserver.clear();for(const e of t)this.componentChanged(e)}onResume(){this.autoPauseAndStart&&this.resumeAll()}onPause(){this.autoPauseAndStart&&this.pauseAll()}onDestroy(){this.unbindHostMute(),this.components.forEach(t=>{t.onDestroy()}),this.components=[],this.ctx&&(this.gainNode.disconnect(),this.gainNode=null,this.ctx.close(),this.ctx=null)}bindHostMute(){this.hostMuteBound||(this.hostMuteBound=!0,"undefined"!=typeof window&&(window.addEventListener(s,this.onWindowSetMuted),window.addEventListener("message",this.onWindowMessage)),this.game.on(s,this.onGameSetMuted))}unbindHostMute(){this.hostMuteBound&&(this.hostMuteBound=!1,"undefined"!=typeof window&&(window.removeEventListener(s,this.onWindowSetMuted),window.removeEventListener("message",this.onWindowMessage)),this.game?.off(s,this.onGameSetMuted))}postMuteStateChanged(){u(this._muted,this.postMessageOrigin,(t,e)=>{this.game?.emit(t,e)})}async componentChanged(t){"Sound"===t.componentName&&t.type===e.OBSERVER_TYPE.ADD&&this.add(t)}setupAudioContext(){try{const t=window.AudioContext||window.webkitAudioContext;this.ctx=new t}catch(t){console.error(t),this.onError&&this.onError(t)}this.ctx&&(this.gainNode=void 0===this.ctx.createGain?this.ctx.createGainNode():this.ctx.createGain(),this.applyGain(),this.gainNode.connect(this.ctx.destination),this.unlockAudio())}unlockAudio(){if(!this.ctx||!this.audioLocked)return;const t=()=>{if(this.ctx){const e=()=>{document.body.removeEventListener("touchstart",t),document.body.removeEventListener("touchend",t),document.body.removeEventListener("click",t)};this.ctx.resume().then(e,e)}};document.body.addEventListener("touchstart",t),document.body.addEventListener("touchend",t),document.body.addEventListener("click",t)}async add(t){const o=t.component;this.components.push(o);try{const{config:t}=o;o.state="loading";const s=await e.resource.getResource(t.resource);!this.audioBufferCache[s.name]&&s?.data?.audio&&(this.audioBufferCache[s.name]=await this.decodeAudioData(s.data.audio,s.name)),this.audioBufferCache[s.name]&&(o.systemContext=this.ctx,o.systemDestination=this.gainNode,o.onload(this.audioBufferCache[s.name]))}catch(t){this.onError&&this.onError(t)}}decodeAudioData(t,e){if(this.decodeAudioPromiseMap[e])return this.decodeAudioPromiseMap[e];const o=new Promise((o,s)=>{this.ctx||s(new Error("No audio support"));const i=this.ctx.decodeAudioData(t,t=>{this.decodeAudioPromiseMap[e]&&delete this.decodeAudioPromiseMap[e],t?o(t):s(new Error(`Error decoding audio ${e}`))},o=>{this.decodeAudioPromiseMap[e]&&delete this.decodeAudioPromiseMap[e],s(new Error(`${o}. arrayBuffer byteLength: ${t?t.byteLength:0}`))});i instanceof Promise&&i.catch(e=>{s(new Error(`catch ${e}, arrayBuffer byteLength: ${t?t.byteLength:0}`))})});return this.decodeAudioPromiseMap[e]=o,o}};d=t.__decorate([e.decorators.componentObserver({Sound:[]})],d);var a=d;Object.assign(a,{packageName:"@combos-fun/plugin-sound",packageVersion:"0.0.48"});class r extends e.Component{constructor(){super(...arguments),this.state="unloaded",this.config={resource:"",autoplay:!1,muted:!1,volume:1,loop:!1,seek:0},this.playTime=0,this.startTime=0,this.duration=0,this.actionQueue=[]}static{this.componentName="Sound"}get muted(){return this.config.muted??!1}set muted(t){this.config.muted=t,this.applyGain()}get volume(){return this.config.volume??1}set volume(t){"number"!=typeof t||t<0||t>1||(this.config.volume=t,this.applyGain())}get loop(){return this.config.loop??!1}set loop(t){this.config.loop=t,this.sourceNode&&(this.sourceNode.loop=t)}get autoplay(){return this.config.autoplay??!1}set autoplay(t){this.config.autoplay=t}get resource(){return this.config.resource??""}set resource(t){this.config.resource=t}applyGain(){this.gainNode&&(this.gainNode.gain.value=this.config.muted?0:this.config.volume??1)}init(t){t&&(Object.assign(this.config,t),this.config.autoplay&&this.actionQueue.push(this.play.bind(this)))}play(){if("loaded"!==this.state&&this.actionQueue.push(this.play.bind(this)),this.destroySource(),this.createSource(),!this.sourceNode)return;const t=this.systemContext.currentTime,e=this.config.seek,o=this.config.duration;this.sourceNode.start(0,e,o),this.startTime=t,this.playTime=t-e,this.paused=!1,this.playing=!0,this.resetConfig(),this.endedListener=()=>{this.sourceNode&&(this.config.onEnd&&this.config.onEnd(),this.playing&&this.destroySource())},this.sourceNode.addEventListener("ended",this.endedListener)}pause(){"loaded"!==this.state&&this.actionQueue.push(this.pause.bind(this)),!this.paused&&this.playing&&(this.paused=!0,this.playing=!1,this.config.seek=this.getCurrentTime(),this.destroySource())}stop(){"loaded"!==this.state&&this.actionQueue.push(this.stop.bind(this)),(this.paused||this.playing)&&(this.playing=!1,this.paused=!1,this.destroySource(),this.resetConfig())}onload(t){this.state="loaded",this.buffer=t,this.duration=this.buffer.duration,this.actionQueue.forEach(t=>t()),this.actionQueue.length=0}onDestroy(){this.actionQueue.length=0,this.destroySource()}resetConfig(){this.config.seek=0}getCurrentTime(){return this.config.loop&&this.duration>0?(this.systemContext.currentTime-this.playTime)%this.duration:this.systemContext.currentTime-this.playTime}createSource(){this.systemContext&&"loaded"===this.state&&(this.sourceNode=this.systemContext.createBufferSource(),this.sourceNode.buffer=this.buffer,this.sourceNode.loop=this.config.loop,this.gainNode||(this.gainNode=this.systemContext.createGain(),this.gainNode.connect(this.systemDestination),Object.assign(this,this.config)),this.sourceNode.connect(this.gainNode))}destroySource(){this.sourceNode&&(this.sourceNode.removeEventListener("ended",this.endedListener),this.sourceNode.stop(),this.sourceNode.disconnect(),this.sourceNode=null,this.startTime=0,this.playTime=0,this.playing=!1)}}t.__decorate([o.Field({type:"boolean",group:"Sound",label:"Muted",description:"Silence this sound without changing its volume setting.",editor:"toggle"})],r.prototype,"muted",null),t.__decorate([o.Field({type:"number",min:0,max:1,step:.01,group:"Sound",label:"Volume",description:"Loudness of this sound from 0 (silent) to 1 (full).",editor:"volume-slider"})],r.prototype,"volume",null),t.__decorate([o.Field({type:"boolean",group:"Sound",label:"Loop",description:"Replay the sound continuously when it reaches the end.",editor:"toggle"})],r.prototype,"loop",null),t.__decorate([o.Field({type:"boolean",group:"Sound",label:"Autoplay",description:"Start playing automatically once the audio has loaded.",editor:"toggle"})],r.prototype,"autoplay",null),t.__decorate([o.Field({type:"string",group:"Sound",label:"Resource",description:"Audio resource id used by the sound system.",editor:"text"})],r.prototype,"resource",null),exports.COMBOS_DEVELOPMENT_TOOL_SET_MUTED=s,exports.COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED=i,exports.Sound=r,exports.SoundSystem=a,exports.parseSetMutedMessage=n,exports.postParentSoundMuted=u;
@@ -3,6 +3,13 @@ import { System, ComponentChanged, Component } from '@combos-fun/engine';
3
3
  interface SoundSystemParams {
4
4
  autoPauseAndStart?: boolean;
5
5
  onError?: (error: any) => void;
6
+ /** postMessage `targetOrigin` when notifying parent (default: Game `pluginInitNotifyTargetOrigin` or `'*'`). */
7
+ postMessageOrigin?: string;
8
+ /**
9
+ * Extra inbound `postMessage` origins merged with engine defaults (`knoffice.tech`, `converge.ai`).
10
+ * Each entry is a host suffix (e.g. `localhost`) or a full origin. Pass `['*']` to accept any origin.
11
+ */
12
+ allowedMessageOrigins?: string[];
6
13
  }
7
14
  declare class SoundSystem extends System {
8
15
  static systemName: string;
@@ -18,6 +25,9 @@ declare class SoundSystem extends System {
18
25
  /** Desired mute/volume are the source of truth; the gain node is derived. */
19
26
  private _muted;
20
27
  private _volume;
28
+ private postMessageOrigin;
29
+ private allowedMessageOrigins;
30
+ private hostMuteBound;
21
31
  get muted(): boolean;
22
32
  set muted(v: boolean);
23
33
  get volume(): number;
@@ -34,6 +44,11 @@ declare class SoundSystem extends System {
34
44
  private applyGain;
35
45
  get audioLocked(): boolean;
36
46
  constructor(obj?: SoundSystemParams);
47
+ /**
48
+ * Mute or unmute the master gain and notify the embedding host.
49
+ * Same effect as `postMessage({ type: 'combos-development-tool:set-muted', muted })`.
50
+ */
51
+ setMuted(muted: boolean): void;
37
52
  /**
38
53
  * Resume playback of all paused audio.
39
54
  */
@@ -49,7 +64,7 @@ declare class SoundSystem extends System {
49
64
  /**
50
65
  * System init: configure params before the game starts.
51
66
  */
52
- init(): void;
67
+ init(params?: SoundSystemParams): void;
53
68
  update(): void;
54
69
  /**
55
70
  * Called when the game starts or resumes playing after a pause.
@@ -63,6 +78,12 @@ declare class SoundSystem extends System {
63
78
  * Called when the system is destroyed.
64
79
  */
65
80
  onDestroy(): void;
81
+ private readonly onWindowSetMuted;
82
+ private readonly onGameSetMuted;
83
+ private readonly onWindowMessage;
84
+ private bindHostMute;
85
+ private unbindHostMute;
86
+ private postMuteStateChanged;
66
87
  componentChanged(changed: ComponentChanged): Promise<void>;
67
88
  private setupAudioContext;
68
89
  private unlockAudio;
@@ -128,4 +149,23 @@ declare class Sound extends Component<SoundParams> {
128
149
  private destroySource;
129
150
  }
130
151
 
131
- export { Sound, SoundSystem };
152
+ /** Parent → iframe (also `window` CustomEvent / `game.emit`): mute or unmute. Payload: `{ muted: boolean }`. */
153
+ declare const COMBOS_DEVELOPMENT_TOOL_SET_MUTED: "combos-development-tool:set-muted";
154
+ /** iframe → parent (and `game.emit`): current mute snapshot after a successful change. */
155
+ declare const COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED: "combos-development-tool:state-changed";
156
+ interface CombosSoundSetMutedMessage {
157
+ type: typeof COMBOS_DEVELOPMENT_TOOL_SET_MUTED;
158
+ muted: boolean;
159
+ }
160
+ interface CombosSoundStateChangedMessage {
161
+ type: typeof COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED;
162
+ muted: boolean;
163
+ }
164
+ declare function parseSetMutedMessage(data: unknown): boolean | null;
165
+ /** Notifies the embedding page (and `game.emit`) of the current mute flag. */
166
+ declare function postParentSoundMuted(muted: boolean, targetOrigin: string, emit?: (type: string, payload: {
167
+ muted: boolean;
168
+ }) => void): void;
169
+
170
+ export { COMBOS_DEVELOPMENT_TOOL_SET_MUTED, COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED, Sound, SoundSystem, parseSetMutedMessage, postParentSoundMuted };
171
+ export type { CombosSoundSetMutedMessage, CombosSoundStateChangedMessage };
@@ -1,15 +1,53 @@
1
1
  import { __decorate } from 'tslib';
2
- import { System, OBSERVER_TYPE, resource, decorators, Component } from '@combos-fun/engine';
2
+ import { System, mergeAllowedMessageOrigins, isAllowedMessageOrigin, OBSERVER_TYPE, resource, decorators, Component } from '@combos-fun/engine';
3
3
  import { Field } from '@combos-fun/inspector-decorator';
4
4
 
5
+ /** Parent → iframe (also `window` CustomEvent / `game.emit`): mute or unmute. Payload: `{ muted: boolean }`. */
6
+ const COMBOS_DEVELOPMENT_TOOL_SET_MUTED = 'combos-development-tool:set-muted';
7
+ /** iframe → parent (and `game.emit`): current mute snapshot after a successful change. */
8
+ const COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED = 'combos-development-tool:state-changed';
9
+ function parseSetMutedMessage(data) {
10
+ if (!data || typeof data !== 'object')
11
+ return null;
12
+ const d = data;
13
+ if (d.type !== COMBOS_DEVELOPMENT_TOOL_SET_MUTED)
14
+ return null;
15
+ if (typeof d.muted !== 'boolean')
16
+ return null;
17
+ return d.muted;
18
+ }
19
+ function parseSetMutedCustomEvent(event) {
20
+ const d = event.detail;
21
+ if (!d || typeof d !== 'object' || typeof d.muted !== 'boolean')
22
+ return null;
23
+ return d.muted;
24
+ }
25
+ function postToParent(payload, targetOrigin) {
26
+ if (typeof window === 'undefined')
27
+ return;
28
+ if (!window.parent || window.parent === window)
29
+ return;
30
+ try {
31
+ window.parent.postMessage(payload, targetOrigin);
32
+ }
33
+ catch {
34
+ /* ignore cross-origin or detached frame */
35
+ }
36
+ }
37
+ /** Notifies the embedding page (and `game.emit`) of the current mute flag. */
38
+ function postParentSoundMuted(muted, targetOrigin, emit) {
39
+ const state = { muted };
40
+ postToParent({ type: COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED, ...state }, targetOrigin);
41
+ emit?.(COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED, state);
42
+ }
43
+
5
44
  let SoundSystem = class SoundSystem extends System {
6
45
  static { this.systemName = 'SoundSystem'; }
7
46
  get muted() {
8
47
  return this._muted;
9
48
  }
10
49
  set muted(v) {
11
- this._muted = v;
12
- this.applyGain();
50
+ this.setMuted(v);
13
51
  }
14
52
  get volume() {
15
53
  return this._volume;
@@ -53,7 +91,50 @@ let SoundSystem = class SoundSystem extends System {
53
91
  /** Desired mute/volume are the source of truth; the gain node is derived. */
54
92
  this._muted = false;
55
93
  this._volume = 1;
56
- Object.assign(this, obj);
94
+ this.postMessageOrigin = '*';
95
+ this.allowedMessageOrigins = mergeAllowedMessageOrigins();
96
+ this.hostMuteBound = false;
97
+ this.onWindowSetMuted = (e) => {
98
+ const muted = parseSetMutedCustomEvent(e);
99
+ if (muted === null)
100
+ return;
101
+ this.setMuted(muted);
102
+ };
103
+ this.onGameSetMuted = (payload) => {
104
+ if (payload && typeof payload.muted === 'boolean') {
105
+ this.setMuted(payload.muted);
106
+ }
107
+ };
108
+ this.onWindowMessage = (e) => {
109
+ if (!isAllowedMessageOrigin(e.origin, this.allowedMessageOrigins)) {
110
+ return;
111
+ }
112
+ const muted = parseSetMutedMessage(e.data);
113
+ if (muted === null)
114
+ return;
115
+ this.setMuted(muted);
116
+ };
117
+ if (!obj)
118
+ return;
119
+ if (typeof obj.autoPauseAndStart === 'boolean') {
120
+ this.autoPauseAndStart = obj.autoPauseAndStart;
121
+ }
122
+ if (obj.onError) {
123
+ this.onError = obj.onError;
124
+ }
125
+ }
126
+ /**
127
+ * Mute or unmute the master gain and notify the embedding host.
128
+ * Same effect as `postMessage({ type: 'combos-development-tool:set-muted', muted })`.
129
+ */
130
+ setMuted(muted) {
131
+ const next = !!muted;
132
+ if (this._muted === next) {
133
+ return;
134
+ }
135
+ this._muted = next;
136
+ this.applyGain();
137
+ this.postMuteStateChanged();
57
138
  }
58
139
  /**
59
140
  * Resume playback of all paused audio.
@@ -96,7 +177,11 @@ let SoundSystem = class SoundSystem extends System {
96
177
  /**
97
178
  * System init: configure params before the game starts.
98
179
  */
99
- init() {
180
+ init(params) {
181
+ this.postMessageOrigin =
182
+ params?.postMessageOrigin ?? this.game?.pluginInitNotifyTargetOrigin ?? '*';
183
+ this.allowedMessageOrigins = mergeAllowedMessageOrigins(params?.allowedMessageOrigins);
184
+ this.bindHostMute();
100
185
  this.setupAudioContext();
101
186
  }
102
187
  update() {
@@ -127,6 +212,7 @@ let SoundSystem = class SoundSystem extends System {
127
212
  * Called when the system is destroyed.
128
213
  */
129
214
  onDestroy() {
215
+ this.unbindHostMute();
130
216
  this.components.forEach(component => {
131
217
  component.onDestroy();
132
218
  });
@@ -138,6 +224,31 @@ let SoundSystem = class SoundSystem extends System {
138
224
  this.ctx = null;
139
225
  }
140
226
  }
227
+ bindHostMute() {
228
+ if (this.hostMuteBound)
229
+ return;
230
+ this.hostMuteBound = true;
231
+ if (typeof window !== 'undefined') {
232
+ window.addEventListener(COMBOS_DEVELOPMENT_TOOL_SET_MUTED, this.onWindowSetMuted);
233
+ window.addEventListener('message', this.onWindowMessage);
234
+ }
235
+ this.game.on(COMBOS_DEVELOPMENT_TOOL_SET_MUTED, this.onGameSetMuted);
236
+ }
237
+ unbindHostMute() {
238
+ if (!this.hostMuteBound)
239
+ return;
240
+ this.hostMuteBound = false;
241
+ if (typeof window !== 'undefined') {
242
+ window.removeEventListener(COMBOS_DEVELOPMENT_TOOL_SET_MUTED, this.onWindowSetMuted);
243
+ window.removeEventListener('message', this.onWindowMessage);
244
+ }
245
+ this.game?.off(COMBOS_DEVELOPMENT_TOOL_SET_MUTED, this.onGameSetMuted);
246
+ }
247
+ postMuteStateChanged() {
248
+ postParentSoundMuted(this._muted, this.postMessageOrigin, (type, payload) => {
249
+ this.game?.emit(type, payload);
250
+ });
251
+ }
141
252
  async componentChanged(changed) {
142
253
  if (changed.componentName !== 'Sound')
143
254
  return;
@@ -251,7 +362,7 @@ var SoundSystem$1 = SoundSystem;
251
362
  /** Auto-generated by scripts/build-package.mjs — do not edit. */
252
363
  Object.assign(SoundSystem$1, {
253
364
  packageName: "@combos-fun/plugin-sound",
254
- packageVersion: "0.0.46",
365
+ packageVersion: "0.0.48",
255
366
  });
256
367
 
257
368
  class Sound extends Component {
@@ -485,5 +596,5 @@ __decorate([
485
596
  })
486
597
  ], Sound.prototype, "resource", null);
487
598
 
488
- export { Sound, SoundSystem$1 as SoundSystem };
599
+ export { COMBOS_DEVELOPMENT_TOOL_SET_MUTED, COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED, Sound, SoundSystem$1 as SoundSystem, parseSetMutedMessage, postParentSoundMuted };
489
600
  //# sourceMappingURL=plugin-sound.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-sound.esm.js","sources":["../lib/SoundSystem.ts","../lib/__combosPackageMeta.gen.ts","../lib/Sound.ts"],"sourcesContent":["import { System, decorators, ComponentChanged, OBSERVER_TYPE, resource } from '@combos-fun/engine';\nimport SoundComponent from './Sound';\n\ninterface SoundSystemParams {\n autoPauseAndStart?: boolean;\n onError?: (error: any) => void;\n}\n\n@decorators.componentObserver({\n Sound: [],\n})\nclass SoundSystem extends System {\n static systemName = 'SoundSystem';\n\n private ctx: AudioContext;\n\n private gainNode: GainNode;\n\n /** Whether to pause/resume in sync with the game. */\n private autoPauseAndStart = true;\n\n private onError: (error: any) => void;\n\n private components: SoundComponent[] = [];\n\n private pausedComponents: SoundComponent[] = [];\n\n private audioBufferCache = {};\n\n private decodeAudioPromiseMap = {};\n\n /** Desired mute/volume are the source of truth; the gain node is derived. */\n private _muted = false;\n\n private _volume = 1;\n\n get muted(): boolean {\n return this._muted;\n }\n\n set muted(v: boolean) {\n this._muted = v;\n this.applyGain();\n }\n\n get volume(): number {\n return this._volume;\n }\n\n set volume(v: number) {\n if (typeof v !== 'number' || v < 0 || v > 1) {\n return;\n }\n this._volume = v;\n this.applyGain();\n }\n\n /**\n * Apply the effective gain (`muted ? 0 : volume`) to the gain node.\n *\n * Assigns `gain.value` directly rather than `setValueAtTime`: `.value` updates\n * the AudioParam's intrinsic value synchronously, so the `muted` / `volume`\n * getters reflect the change immediately. `setValueAtTime` only schedules an\n * event on the automation timeline and leaves `.value` stale until the next\n * render quantum, which made `muted` report the pre-change value.\n */\n private applyGain() {\n if (!this.gainNode) {\n return;\n }\n this.gainNode.gain.value = this._muted ? 0 : this._volume;\n }\n\n get audioLocked(): boolean {\n if (!this.ctx) {\n return true;\n }\n return this.ctx.state !== 'running';\n }\n\n constructor(obj?: SoundSystemParams) {\n super();\n Object.assign(this, obj);\n }\n\n /**\n * Resume playback of all paused audio.\n */\n resumeAll() {\n const handleResume = () => {\n this.pausedComponents.forEach(component => {\n component.play();\n });\n // Clear the previously cached paused list.\n this.pausedComponents = [];\n };\n this.ctx.resume().then(handleResume, handleResume);\n }\n\n /**\n * Pause all currently playing audio.\n */\n pauseAll() {\n this.components.forEach(component => {\n if (component.playing) {\n this.pausedComponents.push(component);\n component.pause();\n }\n });\n this.ctx.suspend().then();\n }\n\n /**\n * Stop all currently playing audio.\n */\n stopAll() {\n this.components.forEach(component => {\n if (component.playing) {\n component.stop();\n }\n });\n // Clear the previously cached paused list.\n this.pausedComponents = [];\n this.ctx.suspend().then();\n }\n\n /**\n * System init: configure params before the game starts.\n */\n init() {\n this.setupAudioContext();\n }\n\n update() {\n const changes = this.componentObserver.clear();\n for (const changed of changes) {\n this.componentChanged(changed);\n }\n }\n\n /**\n * Called when the game starts or resumes playing after a pause.\n */\n onResume() {\n if (!this.autoPauseAndStart) {\n return;\n }\n this.resumeAll();\n }\n\n /**\n * Called when the game is paused.\n */\n onPause() {\n if (!this.autoPauseAndStart) {\n return;\n }\n this.pauseAll();\n }\n\n /**\n * Called when the system is destroyed.\n */\n onDestroy() {\n this.components.forEach(component => {\n component.onDestroy();\n });\n this.components = [];\n if (this.ctx) {\n this.gainNode.disconnect();\n this.gainNode = null;\n this.ctx.close();\n this.ctx = null;\n }\n }\n\n async componentChanged(changed: ComponentChanged) {\n if (changed.componentName !== 'Sound') return;\n\n if (changed.type === OBSERVER_TYPE.ADD) {\n this.add(changed);\n }\n }\n\n private setupAudioContext() {\n try {\n const AudioContext = window.AudioContext || (window as any).webkitAudioContext;\n this.ctx = new AudioContext();\n } catch (error) {\n console.error(error);\n if (this.onError) {\n this.onError(error);\n }\n }\n\n if (!this.ctx) {\n return;\n }\n this.gainNode =\n typeof this.ctx.createGain === 'undefined' ? (this.ctx as any).createGainNode() : this.ctx.createGain();\n this.applyGain();\n this.gainNode.connect(this.ctx.destination);\n this.unlockAudio();\n }\n\n private unlockAudio() {\n if (!this.ctx || !this.audioLocked) {\n return;\n }\n\n const unlock = () => {\n if (this.ctx) {\n const removeListenerFn = () => {\n document.body.removeEventListener('touchstart', unlock);\n document.body.removeEventListener('touchend', unlock);\n document.body.removeEventListener('click', unlock);\n };\n this.ctx.resume().then(removeListenerFn, removeListenerFn);\n }\n };\n document.body.addEventListener('touchstart', unlock);\n document.body.addEventListener('touchend', unlock);\n document.body.addEventListener('click', unlock);\n }\n\n private async add(changed: ComponentChanged) {\n const component = changed.component as SoundComponent;\n this.components.push(component);\n try {\n const { config } = component;\n component.state = 'loading';\n\n const audio = await resource.getResource(config.resource);\n if (!this.audioBufferCache[audio.name] && audio?.data?.audio) {\n this.audioBufferCache[audio.name] = await this.decodeAudioData(audio.data.audio, audio.name);\n }\n if (this.audioBufferCache[audio.name]) {\n component.systemContext = this.ctx;\n component.systemDestination = this.gainNode;\n component.onload(this.audioBufferCache[audio.name]);\n }\n } catch (error) {\n if (this.onError) {\n this.onError(error);\n }\n }\n }\n\n private decodeAudioData(arraybuffer: ArrayBuffer, name: string) {\n if (this.decodeAudioPromiseMap[name]) {\n return this.decodeAudioPromiseMap[name];\n }\n\n const promise = new Promise<AudioBuffer>((resolve, reject) => {\n if (!this.ctx) {\n reject(new Error('No audio support'));\n }\n\n const success = (decodedData: AudioBuffer) => {\n if (this.decodeAudioPromiseMap[name]) {\n delete this.decodeAudioPromiseMap[name];\n }\n if (decodedData) {\n resolve(decodedData);\n } else {\n reject(new Error(`Error decoding audio ${name}`));\n }\n };\n\n const error = (err: DOMException) => {\n if (this.decodeAudioPromiseMap[name]) {\n delete this.decodeAudioPromiseMap[name];\n }\n reject(new Error(`${err}. arrayBuffer byteLength: ${arraybuffer ? arraybuffer.byteLength : 0}`));\n };\n\n const promise = this.ctx.decodeAudioData(arraybuffer, success, error)\n if (promise instanceof Promise) {\n promise.catch((err) => {\n reject(new Error(`catch ${err}, arrayBuffer byteLength: ${arraybuffer ? arraybuffer.byteLength : 0}`));\n });\n }\n });\n\n this.decodeAudioPromiseMap[name] = promise;\n return promise;\n }\n}\n\nexport default SoundSystem;\n","/** Auto-generated by scripts/build-package.mjs — do not edit. */\n\nimport SoundSystem from './SoundSystem';\n\nObject.assign(SoundSystem, {\n packageName: \"@combos-fun/plugin-sound\",\n packageVersion: \"0.0.46\",\n});\n","import { Component } from '@combos-fun/engine';\nimport { Field } from '@combos-fun/inspector-decorator';\n\nexport interface SoundParams {\n resource: string;\n autoplay?: boolean;\n muted?: boolean;\n volume?: number;\n loop?: boolean;\n seek?: number;\n duration?: number;\n onEnd?: () => void;\n}\n\nclass Sound extends Component<SoundParams> {\n static componentName = 'Sound';\n\n systemContext: AudioContext;\n\n systemDestination: GainNode;\n\n playing: boolean;\n\n state: 'unloaded' | 'loading' | 'loaded' = 'unloaded';\n\n config: SoundParams = {\n resource: '',\n autoplay: false,\n muted: false,\n volume: 1,\n loop: false,\n seek: 0,\n };\n\n private buffer: AudioBuffer;\n\n private sourceNode: AudioBufferSourceNode;\n\n private gainNode: GainNode;\n\n private paused: boolean;\n\n private playTime: number = 0;\n\n private startTime: number = 0;\n\n private duration: number = 0;\n\n private actionQueue: (() => void)[] = [];\n\n private endedListener: () => void;\n\n @Field({\n type: 'boolean',\n group: 'Sound',\n label: 'Muted',\n description: 'Silence this sound without changing its volume setting.',\n editor: 'toggle',\n })\n get muted(): boolean {\n return this.config.muted ?? false;\n }\n\n set muted(v: boolean) {\n this.config.muted = v;\n this.applyGain();\n }\n\n @Field({\n type: 'number',\n min: 0,\n max: 1,\n step: 0.01,\n group: 'Sound',\n label: 'Volume',\n description: 'Loudness of this sound from 0 (silent) to 1 (full).',\n editor: 'volume-slider',\n })\n get volume(): number {\n return this.config.volume ?? 1;\n }\n\n set volume(v: number) {\n if (typeof v !== 'number' || v < 0 || v > 1) {\n return;\n }\n this.config.volume = v;\n this.applyGain();\n }\n\n @Field({\n type: 'boolean',\n group: 'Sound',\n label: 'Loop',\n description: 'Replay the sound continuously when it reaches the end.',\n editor: 'toggle',\n })\n get loop(): boolean {\n return this.config.loop ?? false;\n }\n\n set loop(v: boolean) {\n this.config.loop = v;\n if (this.sourceNode) {\n this.sourceNode.loop = v;\n }\n }\n\n @Field({\n type: 'boolean',\n group: 'Sound',\n label: 'Autoplay',\n description: 'Start playing automatically once the audio has loaded.',\n editor: 'toggle',\n })\n get autoplay(): boolean {\n return this.config.autoplay ?? false;\n }\n\n set autoplay(v: boolean) {\n this.config.autoplay = v;\n }\n\n @Field({\n type: 'string',\n group: 'Sound',\n label: 'Resource',\n description: 'Audio resource id used by the sound system.',\n editor: 'text',\n })\n get resource(): string {\n return this.config.resource ?? '';\n }\n\n set resource(v: string) {\n this.config.resource = v;\n }\n\n /**\n * Apply the effective gain (`muted ? 0 : volume`) to the gain node.\n *\n * `config` is the source of truth and the gain is assigned via `gain.value`\n * (updates the AudioParam intrinsic value synchronously) so the `muted` /\n * `volume` getters — and anything reading them back, e.g. the scene-edit\n * volume slider — reflect the change immediately. `setValueAtTime` only\n * schedules on the automation timeline and leaves `.value` stale.\n */\n private applyGain() {\n if (!this.gainNode) {\n return;\n }\n this.gainNode.gain.value = this.config.muted ? 0 : (this.config.volume ?? 1);\n }\n\n init(obj?: SoundParams) {\n if (!obj) {\n return;\n }\n\n Object.assign(this.config, obj);\n if (this.config.autoplay) {\n this.actionQueue.push(this.play.bind(this));\n }\n }\n\n play() {\n if (this.state !== 'loaded') {\n this.actionQueue.push(this.play.bind(this));\n }\n this.destroySource();\n this.createSource();\n\n if (!this.sourceNode) {\n return;\n }\n const when = this.systemContext.currentTime;\n const offset = this.config.seek;\n const duration = this.config.duration;\n\n this.sourceNode.start(0, offset, duration);\n\n this.startTime = when;\n this.playTime = when - offset;\n this.paused = false;\n this.playing = true;\n this.resetConfig();\n this.endedListener = () => {\n if (!this.sourceNode) {\n return;\n }\n if (this.config.onEnd) {\n this.config.onEnd();\n }\n // Release resources once non-interactive playback finishes.\n if (this.playing) {\n this.destroySource();\n }\n };\n this.sourceNode.addEventListener('ended', this.endedListener);\n }\n\n pause() {\n if (this.state !== 'loaded') {\n this.actionQueue.push(this.pause.bind(this));\n }\n if (this.paused || !this.playing) {\n return;\n }\n this.paused = true;\n this.playing = false;\n this.config.seek = this.getCurrentTime();\n this.destroySource();\n }\n\n stop() {\n if (this.state !== 'loaded') {\n this.actionQueue.push(this.stop.bind(this));\n }\n if (!this.paused && !this.playing) {\n return;\n }\n this.playing = false;\n this.paused = false;\n this.destroySource();\n this.resetConfig();\n }\n\n onload(buffer: AudioBuffer) {\n this.state = 'loaded';\n this.buffer = buffer;\n this.duration = this.buffer.duration;\n this.actionQueue.forEach(action => action());\n this.actionQueue.length = 0;\n }\n\n onDestroy() {\n this.actionQueue.length = 0;\n this.destroySource();\n }\n\n private resetConfig() {\n this.config.seek = 0;\n }\n\n private getCurrentTime() {\n if (this.config.loop && this.duration > 0) {\n return (this.systemContext.currentTime - this.playTime) % this.duration;\n }\n\n return this.systemContext.currentTime - this.playTime;\n }\n\n private createSource() {\n if (!this.systemContext || this.state !== 'loaded') {\n return;\n }\n this.sourceNode = this.systemContext.createBufferSource();\n this.sourceNode.buffer = this.buffer;\n this.sourceNode.loop = this.config.loop;\n\n if (!this.gainNode) {\n this.gainNode = this.systemContext.createGain();\n this.gainNode.connect(this.systemDestination);\n Object.assign(this, this.config);\n }\n this.sourceNode.connect(this.gainNode);\n }\n\n private destroySource() {\n if (!this.sourceNode) return;\n this.sourceNode.removeEventListener('ended', this.endedListener);\n this.sourceNode.stop();\n this.sourceNode.disconnect();\n this.sourceNode = null;\n\n this.startTime = 0;\n this.playTime = 0;\n this.playing = false;\n }\n}\n\nexport default Sound;\n"],"names":["SoundSystem"],"mappings":";;;;AAWA,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,MAAM,CAAA;aACvB,IAAA,CAAA,UAAU,GAAG,aAAH,CAAiB;AAwBlC,IAAA,IAAI,KAAK,GAAA;QACP,OAAO,IAAI,CAAC,MAAM;IACpB;IAEA,IAAI,KAAK,CAAC,CAAU,EAAA;AAClB,QAAA,IAAI,CAAC,MAAM,GAAG,CAAC;QACf,IAAI,CAAC,SAAS,EAAE;IAClB;AAEA,IAAA,IAAI,MAAM,GAAA;QACR,OAAO,IAAI,CAAC,OAAO;IACrB;IAEA,IAAI,MAAM,CAAC,CAAS,EAAA;AAClB,QAAA,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;YAC3C;QACF;AACA,QAAA,IAAI,CAAC,OAAO,GAAG,CAAC;QAChB,IAAI,CAAC,SAAS,EAAE;IAClB;AAEA;;;;;;;;AAQG;IACK,SAAS,GAAA;AACf,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;YAClB;QACF;QACA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO;IAC3D;AAEA,IAAA,IAAI,WAAW,GAAA;AACb,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;AACb,YAAA,OAAO,IAAI;QACb;AACA,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS;IACrC;AAEA,IAAA,WAAA,CAAY,GAAuB,EAAA;AACjC,QAAA,KAAK,EAAE;;QA9DD,IAAA,CAAA,iBAAiB,GAAG,IAAI;QAIxB,IAAA,CAAA,UAAU,GAAqB,EAAE;QAEjC,IAAA,CAAA,gBAAgB,GAAqB,EAAE;QAEvC,IAAA,CAAA,gBAAgB,GAAG,EAAE;QAErB,IAAA,CAAA,qBAAqB,GAAG,EAAE;;QAG1B,IAAA,CAAA,MAAM,GAAG,KAAK;QAEd,IAAA,CAAA,OAAO,GAAG,CAAC;AAgDjB,QAAA,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC;IAC1B;AAEA;;AAEG;IACH,SAAS,GAAA;QACP,MAAM,YAAY,GAAG,MAAK;AACxB,YAAA,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,SAAS,IAAG;gBACxC,SAAS,CAAC,IAAI,EAAE;AAClB,YAAA,CAAC,CAAC;;AAEF,YAAA,IAAI,CAAC,gBAAgB,GAAG,EAAE;AAC5B,QAAA,CAAC;AACD,QAAA,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC;IACpD;AAEA;;AAEG;IACH,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,IAAG;AAClC,YAAA,IAAI,SAAS,CAAC,OAAO,EAAE;AACrB,gBAAA,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,SAAS,CAAC;gBACrC,SAAS,CAAC,KAAK,EAAE;YACnB;AACF,QAAA,CAAC,CAAC;QACF,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE;IAC3B;AAEA;;AAEG;IACH,OAAO,GAAA;AACL,QAAA,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,IAAG;AAClC,YAAA,IAAI,SAAS,CAAC,OAAO,EAAE;gBACrB,SAAS,CAAC,IAAI,EAAE;YAClB;AACF,QAAA,CAAC,CAAC;;AAEF,QAAA,IAAI,CAAC,gBAAgB,GAAG,EAAE;QAC1B,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE;IAC3B;AAEA;;AAEG;IACH,IAAI,GAAA;QACF,IAAI,CAAC,iBAAiB,EAAE;IAC1B;IAEA,MAAM,GAAA;QACJ,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE;AAC9C,QAAA,KAAK,MAAM,OAAO,IAAI,OAAO,EAAE;AAC7B,YAAA,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC;QAChC;IACF;AAEA;;AAEG;IACH,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE;YAC3B;QACF;QACA,IAAI,CAAC,SAAS,EAAE;IAClB;AAEA;;AAEG;IACH,OAAO,GAAA;AACL,QAAA,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE;YAC3B;QACF;QACA,IAAI,CAAC,QAAQ,EAAE;IACjB;AAEA;;AAEG;IACH,SAAS,GAAA;AACP,QAAA,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,IAAG;YAClC,SAAS,CAAC,SAAS,EAAE;AACvB,QAAA,CAAC,CAAC;AACF,QAAA,IAAI,CAAC,UAAU,GAAG,EAAE;AACpB,QAAA,IAAI,IAAI,CAAC,GAAG,EAAE;AACZ,YAAA,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE;AAC1B,YAAA,IAAI,CAAC,QAAQ,GAAG,IAAI;AACpB,YAAA,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE;AAChB,YAAA,IAAI,CAAC,GAAG,GAAG,IAAI;QACjB;IACF;IAEA,MAAM,gBAAgB,CAAC,OAAyB,EAAA;AAC9C,QAAA,IAAI,OAAO,CAAC,aAAa,KAAK,OAAO;YAAE;QAEvC,IAAI,OAAO,CAAC,IAAI,KAAK,aAAa,CAAC,GAAG,EAAE;AACtC,YAAA,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;QACnB;IACF;IAEQ,iBAAiB,GAAA;AACvB,QAAA,IAAI;YACF,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,IAAK,MAAc,CAAC,kBAAkB;AAC9E,YAAA,IAAI,CAAC,GAAG,GAAG,IAAI,YAAY,EAAE;QAC/B;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;AACpB,YAAA,IAAI,IAAI,CAAC,OAAO,EAAE;AAChB,gBAAA,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;YACrB;QACF;AAEA,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;YACb;QACF;AACA,QAAA,IAAI,CAAC,QAAQ;YACX,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,KAAK,WAAW,GAAI,IAAI,CAAC,GAAW,CAAC,cAAc,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE;QACzG,IAAI,CAAC,SAAS,EAAE;QAChB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC;QAC3C,IAAI,CAAC,WAAW,EAAE;IACpB;IAEQ,WAAW,GAAA;QACjB,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;YAClC;QACF;QAEA,MAAM,MAAM,GAAG,MAAK;AAClB,YAAA,IAAI,IAAI,CAAC,GAAG,EAAE;gBACZ,MAAM,gBAAgB,GAAG,MAAK;oBAC5B,QAAQ,CAAC,IAAI,CAAC,mBAAmB,CAAC,YAAY,EAAE,MAAM,CAAC;oBACvD,QAAQ,CAAC,IAAI,CAAC,mBAAmB,CAAC,UAAU,EAAE,MAAM,CAAC;oBACrD,QAAQ,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC;AACpD,gBAAA,CAAC;AACD,gBAAA,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;YAC5D;AACF,QAAA,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,MAAM,CAAC;QACpD,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,MAAM,CAAC;QAClD,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC;IACjD;IAEQ,MAAM,GAAG,CAAC,OAAyB,EAAA;AACzC,QAAA,MAAM,SAAS,GAAG,OAAO,CAAC,SAA2B;AACrD,QAAA,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC;AAC/B,QAAA,IAAI;AACF,YAAA,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS;AAC5B,YAAA,SAAS,CAAC,KAAK,GAAG,SAAS;YAE3B,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC;AACzD,YAAA,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE;gBAC5D,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC;YAC9F;YACA,IAAI,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;AACrC,gBAAA,SAAS,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG;AAClC,gBAAA,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,QAAQ;AAC3C,gBAAA,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACrD;QACF;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,IAAI,IAAI,CAAC,OAAO,EAAE;AAChB,gBAAA,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;YACrB;QACF;IACF;IAEQ,eAAe,CAAC,WAAwB,EAAE,IAAY,EAAA;AAC5D,QAAA,IAAI,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE;AACpC,YAAA,OAAO,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC;QACzC;QAEA,MAAM,OAAO,GAAG,IAAI,OAAO,CAAc,CAAC,OAAO,EAAE,MAAM,KAAI;AAC3D,YAAA,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;AACb,gBAAA,MAAM,CAAC,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;YACvC;AAEA,YAAA,MAAM,OAAO,GAAG,CAAC,WAAwB,KAAI;AAC3C,gBAAA,IAAI,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE;AACpC,oBAAA,OAAO,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC;gBACzC;gBACA,IAAI,WAAW,EAAE;oBACf,OAAO,CAAC,WAAW,CAAC;gBACtB;qBAAO;oBACL,MAAM,CAAC,IAAI,KAAK,CAAC,wBAAwB,IAAI,CAAA,CAAE,CAAC,CAAC;gBACnD;AACF,YAAA,CAAC;AAED,YAAA,MAAM,KAAK,GAAG,CAAC,GAAiB,KAAI;AAClC,gBAAA,IAAI,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE;AACpC,oBAAA,OAAO,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC;gBACzC;gBACA,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,GAAG,CAAA,0BAAA,EAA6B,WAAW,GAAG,WAAW,CAAC,UAAU,GAAG,CAAC,CAAA,CAAE,CAAC,CAAC;AAClG,YAAA,CAAC;AAED,YAAA,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,WAAW,EAAE,OAAO,EAAE,KAAK,CAAC;AACrE,YAAA,IAAI,OAAO,YAAY,OAAO,EAAE;AAC9B,gBAAA,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,KAAI;oBACpB,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,GAAG,CAAA,0BAAA,EAA6B,WAAW,GAAG,WAAW,CAAC,UAAU,GAAG,CAAC,CAAA,CAAE,CAAC,CAAC;AACxG,gBAAA,CAAC,CAAC;YACJ;AACF,QAAA,CAAC,CAAC;AAEF,QAAA,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,GAAG,OAAO;AAC1C,QAAA,OAAO,OAAO;IAChB;;AAnRI,WAAW,GAAA,UAAA,CAAA;IAHhB,UAAU,CAAC,iBAAiB,CAAC;AAC5B,QAAA,KAAK,EAAE,EAAE;KACV;AACK,CAAA,EAAA,WAAW,CAoRhB;AAED,oBAAe,WAAW;;ACjS1B;AAIA,MAAM,CAAC,MAAM,CAACA,aAAW,EAAE;AACzB,IAAA,WAAW,EAAE,0BAA0B;AACvC,IAAA,cAAc,EAAE,QAAQ;AACzB,CAAA,CAAC;;ACOF,MAAM,KAAM,SAAQ,SAAsB,CAAA;AAA1C,IAAA,WAAA,GAAA;;QASE,IAAA,CAAA,KAAK,GAAsC,UAAU;AAErD,QAAA,IAAA,CAAA,MAAM,GAAgB;AACpB,YAAA,QAAQ,EAAE,EAAE;AACZ,YAAA,QAAQ,EAAE,KAAK;AACf,YAAA,KAAK,EAAE,KAAK;AACZ,YAAA,MAAM,EAAE,CAAC;AACT,YAAA,IAAI,EAAE,KAAK;AACX,YAAA,IAAI,EAAE,CAAC;SACR;QAUO,IAAA,CAAA,QAAQ,GAAW,CAAC;QAEpB,IAAA,CAAA,SAAS,GAAW,CAAC;QAErB,IAAA,CAAA,QAAQ,GAAW,CAAC;QAEpB,IAAA,CAAA,WAAW,GAAmB,EAAE;IAuO1C;aAxQS,IAAA,CAAA,aAAa,GAAG,OAAH,CAAW;AA4C/B,IAAA,IAAI,KAAK,GAAA;AACP,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,KAAK;IACnC;IAEA,IAAI,KAAK,CAAC,CAAU,EAAA;AAClB,QAAA,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC;QACrB,IAAI,CAAC,SAAS,EAAE;IAClB;AAYA,IAAA,IAAI,MAAM,GAAA;AACR,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC;IAChC;IAEA,IAAI,MAAM,CAAC,CAAS,EAAA;AAClB,QAAA,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;YAC3C;QACF;AACA,QAAA,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QACtB,IAAI,CAAC,SAAS,EAAE;IAClB;AASA,IAAA,IAAI,IAAI,GAAA;AACN,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,KAAK;IAClC;IAEA,IAAI,IAAI,CAAC,CAAU,EAAA;AACjB,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC;AACpB,QAAA,IAAI,IAAI,CAAC,UAAU,EAAE;AACnB,YAAA,IAAI,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC;QAC1B;IACF;AASA,IAAA,IAAI,QAAQ,GAAA;AACV,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,KAAK;IACtC;IAEA,IAAI,QAAQ,CAAC,CAAU,EAAA;AACrB,QAAA,IAAI,CAAC,MAAM,CAAC,QAAQ,GAAG,CAAC;IAC1B;AASA,IAAA,IAAI,QAAQ,GAAA;AACV,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE;IACnC;IAEA,IAAI,QAAQ,CAAC,CAAS,EAAA;AACpB,QAAA,IAAI,CAAC,MAAM,CAAC,QAAQ,GAAG,CAAC;IAC1B;AAEA;;;;;;;;AAQG;IACK,SAAS,GAAA;AACf,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;YAClB;QACF;AACA,QAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;IAC9E;AAEA,IAAA,IAAI,CAAC,GAAiB,EAAA;QACpB,IAAI,CAAC,GAAG,EAAE;YACR;QACF;QAEA,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC;AAC/B,QAAA,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;AACxB,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C;IACF;IAEA,IAAI,GAAA;AACF,QAAA,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE;AAC3B,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C;QACA,IAAI,CAAC,aAAa,EAAE;QACpB,IAAI,CAAC,YAAY,EAAE;AAEnB,QAAA,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;YACpB;QACF;AACA,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,WAAW;AAC3C,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI;AAC/B,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ;QAErC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC;AAE1C,QAAA,IAAI,CAAC,SAAS,GAAG,IAAI;AACrB,QAAA,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,MAAM;AAC7B,QAAA,IAAI,CAAC,MAAM,GAAG,KAAK;AACnB,QAAA,IAAI,CAAC,OAAO,GAAG,IAAI;QACnB,IAAI,CAAC,WAAW,EAAE;AAClB,QAAA,IAAI,CAAC,aAAa,GAAG,MAAK;AACxB,YAAA,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;gBACpB;YACF;AACA,YAAA,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;AACrB,gBAAA,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;YACrB;;AAEA,YAAA,IAAI,IAAI,CAAC,OAAO,EAAE;gBAChB,IAAI,CAAC,aAAa,EAAE;YACtB;AACF,QAAA,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC;IAC/D;IAEA,KAAK,GAAA;AACH,QAAA,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE;AAC3B,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C;QACA,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;YAChC;QACF;AACA,QAAA,IAAI,CAAC,MAAM,GAAG,IAAI;AAClB,QAAA,IAAI,CAAC,OAAO,GAAG,KAAK;QACpB,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE;QACxC,IAAI,CAAC,aAAa,EAAE;IACtB;IAEA,IAAI,GAAA;AACF,QAAA,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE;AAC3B,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C;QACA,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;YACjC;QACF;AACA,QAAA,IAAI,CAAC,OAAO,GAAG,KAAK;AACpB,QAAA,IAAI,CAAC,MAAM,GAAG,KAAK;QACnB,IAAI,CAAC,aAAa,EAAE;QACpB,IAAI,CAAC,WAAW,EAAE;IACpB;AAEA,IAAA,MAAM,CAAC,MAAmB,EAAA;AACxB,QAAA,IAAI,CAAC,KAAK,GAAG,QAAQ;AACrB,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM;QACpB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ;AACpC,QAAA,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,IAAI,MAAM,EAAE,CAAC;AAC5C,QAAA,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC;IAC7B;IAEA,SAAS,GAAA;AACP,QAAA,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC;QAC3B,IAAI,CAAC,aAAa,EAAE;IACtB;IAEQ,WAAW,GAAA;AACjB,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC;IACtB;IAEQ,cAAc,GAAA;AACpB,QAAA,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,GAAG,CAAC,EAAE;AACzC,YAAA,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,WAAW,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ;QACzE;QAEA,OAAO,IAAI,CAAC,aAAa,CAAC,WAAW,GAAG,IAAI,CAAC,QAAQ;IACvD;IAEQ,YAAY,GAAA;QAClB,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE;YAClD;QACF;QACA,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,kBAAkB,EAAE;QACzD,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM;QACpC,IAAI,CAAC,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI;AAEvC,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;YAClB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE;YAC/C,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC;YAC7C,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC;QAClC;QACA,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC;IACxC;IAEQ,aAAa,GAAA;QACnB,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE;QACtB,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC;AAChE,QAAA,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE;AACtB,QAAA,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE;AAC5B,QAAA,IAAI,CAAC,UAAU,GAAG,IAAI;AAEtB,QAAA,IAAI,CAAC,SAAS,GAAG,CAAC;AAClB,QAAA,IAAI,CAAC,QAAQ,GAAG,CAAC;AACjB,QAAA,IAAI,CAAC,OAAO,GAAG,KAAK;IACtB;;AA3NA,UAAA,CAAA;AAPC,IAAA,KAAK,CAAC;AACL,QAAA,IAAI,EAAE,SAAS;AACf,QAAA,KAAK,EAAE,OAAO;AACd,QAAA,KAAK,EAAE,OAAO;AACd,QAAA,WAAW,EAAE,yDAAyD;AACtE,QAAA,MAAM,EAAE,QAAQ;KACjB;AAGA,CAAA,EAAA,KAAA,CAAA,SAAA,EAAA,OAAA,EAAA,IAAA,CAAA;AAiBD,UAAA,CAAA;AAVC,IAAA,KAAK,CAAC;AACL,QAAA,IAAI,EAAE,QAAQ;AACd,QAAA,GAAG,EAAE,CAAC;AACN,QAAA,GAAG,EAAE,CAAC;AACN,QAAA,IAAI,EAAE,IAAI;AACV,QAAA,KAAK,EAAE,OAAO;AACd,QAAA,KAAK,EAAE,QAAQ;AACf,QAAA,WAAW,EAAE,qDAAqD;AAClE,QAAA,MAAM,EAAE,eAAe;KACxB;AAGA,CAAA,EAAA,KAAA,CAAA,SAAA,EAAA,QAAA,EAAA,IAAA,CAAA;AAiBD,UAAA,CAAA;AAPC,IAAA,KAAK,CAAC;AACL,QAAA,IAAI,EAAE,SAAS;AACf,QAAA,KAAK,EAAE,OAAO;AACd,QAAA,KAAK,EAAE,MAAM;AACb,QAAA,WAAW,EAAE,wDAAwD;AACrE,QAAA,MAAM,EAAE,QAAQ;KACjB;AAGA,CAAA,EAAA,KAAA,CAAA,SAAA,EAAA,MAAA,EAAA,IAAA,CAAA;AAgBD,UAAA,CAAA;AAPC,IAAA,KAAK,CAAC;AACL,QAAA,IAAI,EAAE,SAAS;AACf,QAAA,KAAK,EAAE,OAAO;AACd,QAAA,KAAK,EAAE,UAAU;AACjB,QAAA,WAAW,EAAE,wDAAwD;AACrE,QAAA,MAAM,EAAE,QAAQ;KACjB;AAGA,CAAA,EAAA,KAAA,CAAA,SAAA,EAAA,UAAA,EAAA,IAAA,CAAA;AAaD,UAAA,CAAA;AAPC,IAAA,KAAK,CAAC;AACL,QAAA,IAAI,EAAE,QAAQ;AACd,QAAA,KAAK,EAAE,OAAO;AACd,QAAA,KAAK,EAAE,UAAU;AACjB,QAAA,WAAW,EAAE,6CAA6C;AAC1D,QAAA,MAAM,EAAE,MAAM;KACf;AAGA,CAAA,EAAA,KAAA,CAAA,SAAA,EAAA,UAAA,EAAA,IAAA,CAAA;;;;"}
1
+ {"version":3,"file":"plugin-sound.esm.js","sources":["../lib/hostMessages.ts","../lib/SoundSystem.ts","../lib/__combosPackageMeta.gen.ts","../lib/Sound.ts"],"sourcesContent":["/** Parent → iframe (also `window` CustomEvent / `game.emit`): mute or unmute. Payload: `{ muted: boolean }`. */\nexport const COMBOS_DEVELOPMENT_TOOL_SET_MUTED =\n 'combos-development-tool:set-muted' as const;\n\n/** iframe → parent (and `game.emit`): current mute snapshot after a successful change. */\nexport const COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED =\n 'combos-development-tool:state-changed' as const;\n\nexport interface CombosSoundSetMutedMessage {\n type: typeof COMBOS_DEVELOPMENT_TOOL_SET_MUTED;\n muted: boolean;\n}\n\nexport interface CombosSoundStateChangedMessage {\n type: typeof COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED;\n muted: boolean;\n}\n\nexport function parseSetMutedMessage(data: unknown): boolean | null {\n if (!data || typeof data !== 'object') return null;\n const d = data as { type?: unknown; muted?: unknown };\n if (d.type !== COMBOS_DEVELOPMENT_TOOL_SET_MUTED) return null;\n if (typeof d.muted !== 'boolean') return null;\n return d.muted;\n}\n\nexport function parseSetMutedCustomEvent(event: Event): boolean | null {\n const d = (event as CustomEvent<{ muted?: unknown }>).detail;\n if (!d || typeof d !== 'object' || typeof d.muted !== 'boolean') return null;\n return d.muted;\n}\n\nfunction postToParent(payload: object, targetOrigin: string): void {\n if (typeof window === 'undefined') return;\n if (!window.parent || window.parent === window) return;\n try {\n window.parent.postMessage(payload, targetOrigin);\n } catch {\n /* ignore cross-origin or detached frame */\n }\n}\n\n/** Notifies the embedding page (and `game.emit`) of the current mute flag. */\nexport function postParentSoundMuted(\n muted: boolean,\n targetOrigin: string,\n emit?: (type: string, payload: { muted: boolean }) => void,\n): void {\n const state = { muted };\n postToParent({ type: COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED, ...state }, targetOrigin);\n emit?.(COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED, state);\n}\n","import {\n System,\n decorators,\n ComponentChanged,\n OBSERVER_TYPE,\n resource,\n isAllowedMessageOrigin,\n mergeAllowedMessageOrigins,\n} from '@combos-fun/engine';\nimport SoundComponent from './Sound';\nimport {\n COMBOS_DEVELOPMENT_TOOL_SET_MUTED,\n parseSetMutedCustomEvent,\n parseSetMutedMessage,\n postParentSoundMuted,\n} from './hostMessages';\n\ninterface SoundSystemParams {\n autoPauseAndStart?: boolean;\n onError?: (error: any) => void;\n /** postMessage `targetOrigin` when notifying parent (default: Game `pluginInitNotifyTargetOrigin` or `'*'`). */\n postMessageOrigin?: string;\n /**\n * Extra inbound `postMessage` origins merged with engine defaults (`knoffice.tech`, `converge.ai`).\n * Each entry is a host suffix (e.g. `localhost`) or a full origin. Pass `['*']` to accept any origin.\n */\n allowedMessageOrigins?: string[];\n}\n\n@decorators.componentObserver({\n Sound: [],\n})\nclass SoundSystem extends System {\n static systemName = 'SoundSystem';\n\n private ctx: AudioContext;\n\n private gainNode: GainNode;\n\n /** Whether to pause/resume in sync with the game. */\n private autoPauseAndStart = true;\n\n private onError: (error: any) => void;\n\n private components: SoundComponent[] = [];\n\n private pausedComponents: SoundComponent[] = [];\n\n private audioBufferCache = {};\n\n private decodeAudioPromiseMap = {};\n\n /** Desired mute/volume are the source of truth; the gain node is derived. */\n private _muted = false;\n\n private _volume = 1;\n\n private postMessageOrigin = '*';\n\n private allowedMessageOrigins = mergeAllowedMessageOrigins();\n\n private hostMuteBound = false;\n\n get muted(): boolean {\n return this._muted;\n }\n\n set muted(v: boolean) {\n this.setMuted(v);\n }\n\n get volume(): number {\n return this._volume;\n }\n\n set volume(v: number) {\n if (typeof v !== 'number' || v < 0 || v > 1) {\n return;\n }\n this._volume = v;\n this.applyGain();\n }\n\n /**\n * Apply the effective gain (`muted ? 0 : volume`) to the gain node.\n *\n * Assigns `gain.value` directly rather than `setValueAtTime`: `.value` updates\n * the AudioParam's intrinsic value synchronously, so the `muted` / `volume`\n * getters reflect the change immediately. `setValueAtTime` only schedules an\n * event on the automation timeline and leaves `.value` stale until the next\n * render quantum, which made `muted` report the pre-change value.\n */\n private applyGain() {\n if (!this.gainNode) {\n return;\n }\n this.gainNode.gain.value = this._muted ? 0 : this._volume;\n }\n\n get audioLocked(): boolean {\n if (!this.ctx) {\n return true;\n }\n return this.ctx.state !== 'running';\n }\n\n constructor(obj?: SoundSystemParams) {\n super();\n if (!obj) return;\n if (typeof obj.autoPauseAndStart === 'boolean') {\n this.autoPauseAndStart = obj.autoPauseAndStart;\n }\n if (obj.onError) {\n this.onError = obj.onError;\n }\n }\n\n /**\n * Mute or unmute the master gain and notify the embedding host.\n * Same effect as `postMessage({ type: 'combos-development-tool:set-muted', muted })`.\n */\n setMuted(muted: boolean) {\n const next = !!muted;\n if (this._muted === next) {\n return;\n }\n this._muted = next;\n this.applyGain();\n this.postMuteStateChanged();\n }\n\n /**\n * Resume playback of all paused audio.\n */\n resumeAll() {\n const handleResume = () => {\n this.pausedComponents.forEach(component => {\n component.play();\n });\n // Clear the previously cached paused list.\n this.pausedComponents = [];\n };\n this.ctx.resume().then(handleResume, handleResume);\n }\n\n /**\n * Pause all currently playing audio.\n */\n pauseAll() {\n this.components.forEach(component => {\n if (component.playing) {\n this.pausedComponents.push(component);\n component.pause();\n }\n });\n this.ctx.suspend().then();\n }\n\n /**\n * Stop all currently playing audio.\n */\n stopAll() {\n this.components.forEach(component => {\n if (component.playing) {\n component.stop();\n }\n });\n // Clear the previously cached paused list.\n this.pausedComponents = [];\n this.ctx.suspend().then();\n }\n\n /**\n * System init: configure params before the game starts.\n */\n init(params?: SoundSystemParams) {\n this.postMessageOrigin =\n params?.postMessageOrigin ?? this.game?.pluginInitNotifyTargetOrigin ?? '*';\n this.allowedMessageOrigins = mergeAllowedMessageOrigins(params?.allowedMessageOrigins);\n this.bindHostMute();\n this.setupAudioContext();\n }\n\n update() {\n const changes = this.componentObserver.clear();\n for (const changed of changes) {\n this.componentChanged(changed);\n }\n }\n\n /**\n * Called when the game starts or resumes playing after a pause.\n */\n onResume() {\n if (!this.autoPauseAndStart) {\n return;\n }\n this.resumeAll();\n }\n\n /**\n * Called when the game is paused.\n */\n onPause() {\n if (!this.autoPauseAndStart) {\n return;\n }\n this.pauseAll();\n }\n\n /**\n * Called when the system is destroyed.\n */\n onDestroy() {\n this.unbindHostMute();\n this.components.forEach(component => {\n component.onDestroy();\n });\n this.components = [];\n if (this.ctx) {\n this.gainNode.disconnect();\n this.gainNode = null;\n this.ctx.close();\n this.ctx = null;\n }\n }\n\n private readonly onWindowSetMuted = (e: Event) => {\n const muted = parseSetMutedCustomEvent(e);\n if (muted === null) return;\n this.setMuted(muted);\n };\n\n private readonly onGameSetMuted = (payload: { muted?: boolean }) => {\n if (payload && typeof payload.muted === 'boolean') {\n this.setMuted(payload.muted);\n }\n };\n\n private readonly onWindowMessage = (e: MessageEvent) => {\n if (!isAllowedMessageOrigin(e.origin, this.allowedMessageOrigins)) {\n return;\n }\n const muted = parseSetMutedMessage(e.data);\n if (muted === null) return;\n this.setMuted(muted);\n };\n\n private bindHostMute() {\n if (this.hostMuteBound) return;\n this.hostMuteBound = true;\n if (typeof window !== 'undefined') {\n window.addEventListener(COMBOS_DEVELOPMENT_TOOL_SET_MUTED, this.onWindowSetMuted);\n window.addEventListener('message', this.onWindowMessage);\n }\n this.game.on(COMBOS_DEVELOPMENT_TOOL_SET_MUTED, this.onGameSetMuted);\n }\n\n private unbindHostMute() {\n if (!this.hostMuteBound) return;\n this.hostMuteBound = false;\n if (typeof window !== 'undefined') {\n window.removeEventListener(COMBOS_DEVELOPMENT_TOOL_SET_MUTED, this.onWindowSetMuted);\n window.removeEventListener('message', this.onWindowMessage);\n }\n this.game?.off(COMBOS_DEVELOPMENT_TOOL_SET_MUTED, this.onGameSetMuted);\n }\n\n private postMuteStateChanged() {\n postParentSoundMuted(this._muted, this.postMessageOrigin, (type, payload) => {\n this.game?.emit(type, payload);\n });\n }\n\n async componentChanged(changed: ComponentChanged) {\n if (changed.componentName !== 'Sound') return;\n\n if (changed.type === OBSERVER_TYPE.ADD) {\n this.add(changed);\n }\n }\n\n private setupAudioContext() {\n try {\n const AudioContext = window.AudioContext || (window as any).webkitAudioContext;\n this.ctx = new AudioContext();\n } catch (error) {\n console.error(error);\n if (this.onError) {\n this.onError(error);\n }\n }\n\n if (!this.ctx) {\n return;\n }\n this.gainNode =\n typeof this.ctx.createGain === 'undefined' ? (this.ctx as any).createGainNode() : this.ctx.createGain();\n this.applyGain();\n this.gainNode.connect(this.ctx.destination);\n this.unlockAudio();\n }\n\n private unlockAudio() {\n if (!this.ctx || !this.audioLocked) {\n return;\n }\n\n const unlock = () => {\n if (this.ctx) {\n const removeListenerFn = () => {\n document.body.removeEventListener('touchstart', unlock);\n document.body.removeEventListener('touchend', unlock);\n document.body.removeEventListener('click', unlock);\n };\n this.ctx.resume().then(removeListenerFn, removeListenerFn);\n }\n };\n document.body.addEventListener('touchstart', unlock);\n document.body.addEventListener('touchend', unlock);\n document.body.addEventListener('click', unlock);\n }\n\n private async add(changed: ComponentChanged) {\n const component = changed.component as SoundComponent;\n this.components.push(component);\n try {\n const { config } = component;\n component.state = 'loading';\n\n const audio = await resource.getResource(config.resource);\n if (!this.audioBufferCache[audio.name] && audio?.data?.audio) {\n this.audioBufferCache[audio.name] = await this.decodeAudioData(audio.data.audio, audio.name);\n }\n if (this.audioBufferCache[audio.name]) {\n component.systemContext = this.ctx;\n component.systemDestination = this.gainNode;\n component.onload(this.audioBufferCache[audio.name]);\n }\n } catch (error) {\n if (this.onError) {\n this.onError(error);\n }\n }\n }\n\n private decodeAudioData(arraybuffer: ArrayBuffer, name: string) {\n if (this.decodeAudioPromiseMap[name]) {\n return this.decodeAudioPromiseMap[name];\n }\n\n const promise = new Promise<AudioBuffer>((resolve, reject) => {\n if (!this.ctx) {\n reject(new Error('No audio support'));\n }\n\n const success = (decodedData: AudioBuffer) => {\n if (this.decodeAudioPromiseMap[name]) {\n delete this.decodeAudioPromiseMap[name];\n }\n if (decodedData) {\n resolve(decodedData);\n } else {\n reject(new Error(`Error decoding audio ${name}`));\n }\n };\n\n const error = (err: DOMException) => {\n if (this.decodeAudioPromiseMap[name]) {\n delete this.decodeAudioPromiseMap[name];\n }\n reject(new Error(`${err}. arrayBuffer byteLength: ${arraybuffer ? arraybuffer.byteLength : 0}`));\n };\n\n const promise = this.ctx.decodeAudioData(arraybuffer, success, error)\n if (promise instanceof Promise) {\n promise.catch((err) => {\n reject(new Error(`catch ${err}, arrayBuffer byteLength: ${arraybuffer ? arraybuffer.byteLength : 0}`));\n });\n }\n });\n\n this.decodeAudioPromiseMap[name] = promise;\n return promise;\n }\n}\n\nexport default SoundSystem;\n","/** Auto-generated by scripts/build-package.mjs — do not edit. */\n\nimport SoundSystem from './SoundSystem';\n\nObject.assign(SoundSystem, {\n packageName: \"@combos-fun/plugin-sound\",\n packageVersion: \"0.0.48\",\n});\n","import { Component } from '@combos-fun/engine';\nimport { Field } from '@combos-fun/inspector-decorator';\n\nexport interface SoundParams {\n resource: string;\n autoplay?: boolean;\n muted?: boolean;\n volume?: number;\n loop?: boolean;\n seek?: number;\n duration?: number;\n onEnd?: () => void;\n}\n\nclass Sound extends Component<SoundParams> {\n static componentName = 'Sound';\n\n systemContext: AudioContext;\n\n systemDestination: GainNode;\n\n playing: boolean;\n\n state: 'unloaded' | 'loading' | 'loaded' = 'unloaded';\n\n config: SoundParams = {\n resource: '',\n autoplay: false,\n muted: false,\n volume: 1,\n loop: false,\n seek: 0,\n };\n\n private buffer: AudioBuffer;\n\n private sourceNode: AudioBufferSourceNode;\n\n private gainNode: GainNode;\n\n private paused: boolean;\n\n private playTime: number = 0;\n\n private startTime: number = 0;\n\n private duration: number = 0;\n\n private actionQueue: (() => void)[] = [];\n\n private endedListener: () => void;\n\n @Field({\n type: 'boolean',\n group: 'Sound',\n label: 'Muted',\n description: 'Silence this sound without changing its volume setting.',\n editor: 'toggle',\n })\n get muted(): boolean {\n return this.config.muted ?? false;\n }\n\n set muted(v: boolean) {\n this.config.muted = v;\n this.applyGain();\n }\n\n @Field({\n type: 'number',\n min: 0,\n max: 1,\n step: 0.01,\n group: 'Sound',\n label: 'Volume',\n description: 'Loudness of this sound from 0 (silent) to 1 (full).',\n editor: 'volume-slider',\n })\n get volume(): number {\n return this.config.volume ?? 1;\n }\n\n set volume(v: number) {\n if (typeof v !== 'number' || v < 0 || v > 1) {\n return;\n }\n this.config.volume = v;\n this.applyGain();\n }\n\n @Field({\n type: 'boolean',\n group: 'Sound',\n label: 'Loop',\n description: 'Replay the sound continuously when it reaches the end.',\n editor: 'toggle',\n })\n get loop(): boolean {\n return this.config.loop ?? false;\n }\n\n set loop(v: boolean) {\n this.config.loop = v;\n if (this.sourceNode) {\n this.sourceNode.loop = v;\n }\n }\n\n @Field({\n type: 'boolean',\n group: 'Sound',\n label: 'Autoplay',\n description: 'Start playing automatically once the audio has loaded.',\n editor: 'toggle',\n })\n get autoplay(): boolean {\n return this.config.autoplay ?? false;\n }\n\n set autoplay(v: boolean) {\n this.config.autoplay = v;\n }\n\n @Field({\n type: 'string',\n group: 'Sound',\n label: 'Resource',\n description: 'Audio resource id used by the sound system.',\n editor: 'text',\n })\n get resource(): string {\n return this.config.resource ?? '';\n }\n\n set resource(v: string) {\n this.config.resource = v;\n }\n\n /**\n * Apply the effective gain (`muted ? 0 : volume`) to the gain node.\n *\n * `config` is the source of truth and the gain is assigned via `gain.value`\n * (updates the AudioParam intrinsic value synchronously) so the `muted` /\n * `volume` getters — and anything reading them back, e.g. the scene-edit\n * volume slider — reflect the change immediately. `setValueAtTime` only\n * schedules on the automation timeline and leaves `.value` stale.\n */\n private applyGain() {\n if (!this.gainNode) {\n return;\n }\n this.gainNode.gain.value = this.config.muted ? 0 : (this.config.volume ?? 1);\n }\n\n init(obj?: SoundParams) {\n if (!obj) {\n return;\n }\n\n Object.assign(this.config, obj);\n if (this.config.autoplay) {\n this.actionQueue.push(this.play.bind(this));\n }\n }\n\n play() {\n if (this.state !== 'loaded') {\n this.actionQueue.push(this.play.bind(this));\n }\n this.destroySource();\n this.createSource();\n\n if (!this.sourceNode) {\n return;\n }\n const when = this.systemContext.currentTime;\n const offset = this.config.seek;\n const duration = this.config.duration;\n\n this.sourceNode.start(0, offset, duration);\n\n this.startTime = when;\n this.playTime = when - offset;\n this.paused = false;\n this.playing = true;\n this.resetConfig();\n this.endedListener = () => {\n if (!this.sourceNode) {\n return;\n }\n if (this.config.onEnd) {\n this.config.onEnd();\n }\n // Release resources once non-interactive playback finishes.\n if (this.playing) {\n this.destroySource();\n }\n };\n this.sourceNode.addEventListener('ended', this.endedListener);\n }\n\n pause() {\n if (this.state !== 'loaded') {\n this.actionQueue.push(this.pause.bind(this));\n }\n if (this.paused || !this.playing) {\n return;\n }\n this.paused = true;\n this.playing = false;\n this.config.seek = this.getCurrentTime();\n this.destroySource();\n }\n\n stop() {\n if (this.state !== 'loaded') {\n this.actionQueue.push(this.stop.bind(this));\n }\n if (!this.paused && !this.playing) {\n return;\n }\n this.playing = false;\n this.paused = false;\n this.destroySource();\n this.resetConfig();\n }\n\n onload(buffer: AudioBuffer) {\n this.state = 'loaded';\n this.buffer = buffer;\n this.duration = this.buffer.duration;\n this.actionQueue.forEach(action => action());\n this.actionQueue.length = 0;\n }\n\n onDestroy() {\n this.actionQueue.length = 0;\n this.destroySource();\n }\n\n private resetConfig() {\n this.config.seek = 0;\n }\n\n private getCurrentTime() {\n if (this.config.loop && this.duration > 0) {\n return (this.systemContext.currentTime - this.playTime) % this.duration;\n }\n\n return this.systemContext.currentTime - this.playTime;\n }\n\n private createSource() {\n if (!this.systemContext || this.state !== 'loaded') {\n return;\n }\n this.sourceNode = this.systemContext.createBufferSource();\n this.sourceNode.buffer = this.buffer;\n this.sourceNode.loop = this.config.loop;\n\n if (!this.gainNode) {\n this.gainNode = this.systemContext.createGain();\n this.gainNode.connect(this.systemDestination);\n Object.assign(this, this.config);\n }\n this.sourceNode.connect(this.gainNode);\n }\n\n private destroySource() {\n if (!this.sourceNode) return;\n this.sourceNode.removeEventListener('ended', this.endedListener);\n this.sourceNode.stop();\n this.sourceNode.disconnect();\n this.sourceNode = null;\n\n this.startTime = 0;\n this.playTime = 0;\n this.playing = false;\n }\n}\n\nexport default Sound;\n"],"names":["SoundSystem"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@combos-fun/plugin-sound",
3
- "version": "0.0.46",
3
+ "version": "0.0.48",
4
4
  "description": "Audio playback",
5
5
  "main": "index.js",
6
6
  "module": "dist/plugin-sound.esm.js",
@@ -38,10 +38,14 @@
38
38
  "author": "sun668 <q947692259@gmail.com>",
39
39
  "dependencies": {
40
40
  "eventemitter3": "^5.0.4",
41
- "@combos-fun/inspector-decorator": "0.0.46",
42
- "@combos-fun/engine": "0.0.46"
41
+ "@combos-fun/inspector-decorator": "0.0.48",
42
+ "@combos-fun/engine": "0.0.48"
43
+ },
44
+ "devDependencies": {
45
+ "tsx": "^4.20.3"
43
46
  },
44
47
  "scripts": {
45
- "build": "node ../../scripts/build-package.mjs"
48
+ "build": "node ../../scripts/build-package.mjs",
49
+ "test": "node --import tsx --test test/hostMessages.test.ts"
46
50
  }
47
51
  }