You've already forked Nitro_Render_V3
mirror of
https://github.com/duckietm/Nitro_Render_V3.git
synced 2026-06-19 15:06:20 +00:00
feat(sound): snapshot getter + volume-update event on SoundManager
Extends the snapshot pattern to the three audio volume levels (system /
furni / trax) so volume-slider widgets on the React client can subscribe
to a single source of truth via useSyncExternalStore.
API additions on ISoundManager:
- systemVolume / furniVolume getters (parity with the existing
traxVolume getter)
- getVolumesSnapshot(): Readonly<ISoundVolumesSnapshot> with the same
lazy-frozen + invalidation-on-change semantics as the user/session
snapshots
- new ISoundVolumesSnapshot { system, furni, trax } interface
New event: NitroEventType.SOUND_VOLUMES_UPDATED. Dispatched only when
the incoming NitroSettingsEvent.SETTINGS_UPDATED actually changes one
of the three volumes (a no-op refresh stays quiet).
While in there, fixed a real bug: the previous implementation cached
`volumeFurniUpdated` / `volumeTraxUpdated` BEFORE writing the new
values, but read `castedEvent.volumeFurni` / `castedEvent.volumeTrax`
in their pre-division form — comparing percent (e.g. 75) against the
already-divided stored value (e.g. 0.75) — so the change check almost
always reported "updated" for a real settings push and never reported
"updated" if the percent matched the stored fraction by coincidence
(only 0/100 are stable). Updated check is now consistent (compare
fraction vs fraction) and also tracks systemVolume changes for the
new snapshot invalidation.
This commit is contained in:
@@ -1,8 +1,22 @@
|
|||||||
import { IMusicController } from './IMusicController';
|
import { IMusicController } from './IMusicController';
|
||||||
|
import { ISoundVolumesSnapshot } from './ISoundVolumesSnapshot';
|
||||||
|
|
||||||
export interface ISoundManager
|
export interface ISoundManager
|
||||||
{
|
{
|
||||||
init(): Promise<void>;
|
init(): Promise<void>;
|
||||||
musicController: IMusicController;
|
musicController: IMusicController;
|
||||||
traxVolume: number;
|
traxVolume: number;
|
||||||
|
systemVolume: number;
|
||||||
|
furniVolume: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a referentially-stable snapshot of the three volume
|
||||||
|
* levels (system / furni / trax). The same reference is returned
|
||||||
|
* across reads until a volume changes; mutations dispatch
|
||||||
|
* `NitroEventType.SOUND_VOLUMES_UPDATED` to signal invalidation.
|
||||||
|
*
|
||||||
|
* Pairs with `useSyncExternalStore` on the React client for
|
||||||
|
* volume-slider widgets.
|
||||||
|
*/
|
||||||
|
getVolumesSnapshot(): Readonly<ISoundVolumesSnapshot>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export interface ISoundVolumesSnapshot
|
||||||
|
{
|
||||||
|
system: number;
|
||||||
|
furni: number;
|
||||||
|
trax: number;
|
||||||
|
}
|
||||||
@@ -2,3 +2,4 @@ export * from './IMusicController';
|
|||||||
export * from './IPlaylistController';
|
export * from './IPlaylistController';
|
||||||
export * from './ISongInfo';
|
export * from './ISongInfo';
|
||||||
export * from './ISoundManager';
|
export * from './ISoundManager';
|
||||||
|
export * from './ISoundVolumesSnapshot';
|
||||||
|
|||||||
@@ -22,4 +22,5 @@ export class NitroEventType
|
|||||||
public static readonly IGNORED_USERS_UPDATED = 'IGNORED_USERS_UPDATED';
|
public static readonly IGNORED_USERS_UPDATED = 'IGNORED_USERS_UPDATED';
|
||||||
public static readonly GROUP_BADGES_UPDATED = 'GROUP_BADGES_UPDATED';
|
public static readonly GROUP_BADGES_UPDATED = 'GROUP_BADGES_UPDATED';
|
||||||
public static readonly ROOM_USER_LIST_UPDATED = 'ROOM_USER_LIST_UPDATED';
|
public static readonly ROOM_USER_LIST_UPDATED = 'ROOM_USER_LIST_UPDATED';
|
||||||
|
public static readonly SOUND_VOLUMES_UPDATED = 'SOUND_VOLUMES_UPDATED';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { IAdvancedMap, IMusicController, INitroEvent, ISoundManager } from '@nitrots/api';
|
import { IAdvancedMap, IMusicController, INitroEvent, ISoundManager, ISoundVolumesSnapshot } from '@nitrots/api';
|
||||||
import { GetConfiguration } from '@nitrots/configuration';
|
import { GetConfiguration } from '@nitrots/configuration';
|
||||||
import { GetEventDispatcher, NitroSettingsEvent, NitroSoundEvent, RoomEngineEvent, RoomEngineObjectEvent, RoomEngineSamplePlaybackEvent } from '@nitrots/events';
|
import { GetEventDispatcher, NitroEvent, NitroEventType, NitroSettingsEvent, NitroSoundEvent, RoomEngineEvent, RoomEngineObjectEvent, RoomEngineSamplePlaybackEvent } from '@nitrots/events';
|
||||||
import { AdvancedMap, NitroLogger } from '@nitrots/utils';
|
import { AdvancedMap, NitroLogger } from '@nitrots/utils';
|
||||||
import { MusicController } from './music/MusicController';
|
import { MusicController } from './music/MusicController';
|
||||||
|
|
||||||
@@ -9,6 +9,7 @@ export class SoundManager implements ISoundManager
|
|||||||
private _volumeSystem: number = 0.5;
|
private _volumeSystem: number = 0.5;
|
||||||
private _volumeFurni: number = 0.5;
|
private _volumeFurni: number = 0.5;
|
||||||
private _volumeTrax: number = 0.5;
|
private _volumeTrax: number = 0.5;
|
||||||
|
private _volumesSnapshot: Readonly<ISoundVolumesSnapshot> | null = null;
|
||||||
|
|
||||||
private _internalSamples: IAdvancedMap<string, HTMLAudioElement> = new AdvancedMap();
|
private _internalSamples: IAdvancedMap<string, HTMLAudioElement> = new AdvancedMap();
|
||||||
private _furniSamples: IAdvancedMap<number, HTMLAudioElement> = new AdvancedMap();
|
private _furniSamples: IAdvancedMap<number, HTMLAudioElement> = new AdvancedMap();
|
||||||
@@ -81,17 +82,24 @@ export class SoundManager implements ISoundManager
|
|||||||
case NitroSettingsEvent.SETTINGS_UPDATED: {
|
case NitroSettingsEvent.SETTINGS_UPDATED: {
|
||||||
const castedEvent = (event as NitroSettingsEvent);
|
const castedEvent = (event as NitroSettingsEvent);
|
||||||
|
|
||||||
const volumeFurniUpdated = castedEvent.volumeFurni !== this._volumeFurni;
|
const nextSystem = (castedEvent.volumeSystem / 100);
|
||||||
const volumeTraxUpdated = castedEvent.volumeTrax !== this._volumeTrax;
|
const nextFurni = (castedEvent.volumeFurni / 100);
|
||||||
|
const nextTrax = (castedEvent.volumeTrax / 100);
|
||||||
|
|
||||||
this._volumeSystem = (castedEvent.volumeSystem / 100);
|
const volumeSystemUpdated = nextSystem !== this._volumeSystem;
|
||||||
this._volumeFurni = (castedEvent.volumeFurni / 100);
|
const volumeFurniUpdated = nextFurni !== this._volumeFurni;
|
||||||
this._volumeTrax = (castedEvent.volumeTrax / 100);
|
const volumeTraxUpdated = nextTrax !== this._volumeTrax;
|
||||||
|
|
||||||
|
this._volumeSystem = nextSystem;
|
||||||
|
this._volumeFurni = nextFurni;
|
||||||
|
this._volumeTrax = nextTrax;
|
||||||
|
|
||||||
if(volumeFurniUpdated) this.updateFurniSamplesVolume(this._volumeFurni);
|
if(volumeFurniUpdated) this.updateFurniSamplesVolume(this._volumeFurni);
|
||||||
|
|
||||||
if(volumeTraxUpdated) this._musicController?.updateVolume(this._volumeTrax);
|
if(volumeTraxUpdated) this._musicController?.updateVolume(this._volumeTrax);
|
||||||
|
|
||||||
|
if(volumeSystemUpdated || volumeFurniUpdated || volumeTraxUpdated) this.invalidateVolumesSnapshot();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case NitroSoundEvent.PLAY_SOUND: {
|
case NitroSoundEvent.PLAY_SOUND: {
|
||||||
@@ -215,8 +223,38 @@ export class SoundManager implements ISoundManager
|
|||||||
return this._volumeTrax;
|
return this._volumeTrax;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get systemVolume(): number
|
||||||
|
{
|
||||||
|
return this._volumeSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get furniVolume(): number
|
||||||
|
{
|
||||||
|
return this._volumeFurni;
|
||||||
|
}
|
||||||
|
|
||||||
public get musicController(): IMusicController
|
public get musicController(): IMusicController
|
||||||
{
|
{
|
||||||
return this._musicController;
|
return this._musicController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private invalidateVolumesSnapshot(): void
|
||||||
|
{
|
||||||
|
this._volumesSnapshot = null;
|
||||||
|
|
||||||
|
GetEventDispatcher().dispatchEvent(new NitroEvent(NitroEventType.SOUND_VOLUMES_UPDATED));
|
||||||
|
}
|
||||||
|
|
||||||
|
public getVolumesSnapshot(): Readonly<ISoundVolumesSnapshot>
|
||||||
|
{
|
||||||
|
if(this._volumesSnapshot) return this._volumesSnapshot;
|
||||||
|
|
||||||
|
this._volumesSnapshot = Object.freeze<ISoundVolumesSnapshot>({
|
||||||
|
system: this._volumeSystem,
|
||||||
|
furni: this._volumeFurni,
|
||||||
|
trax: this._volumeTrax
|
||||||
|
});
|
||||||
|
|
||||||
|
return this._volumesSnapshot;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user