Apply clock announcement spatial range from server

This commit is contained in:
Jage9
2026-02-27 01:12:24 -05:00
parent 47a7aa0a83
commit 3b414b1f89
7 changed files with 12 additions and 8 deletions

View File

@@ -1,5 +1,5 @@
// Maintainer-controlled web client version. // Maintainer-controlled web client version.
// Format: YYYY.MM.DD Rn (example: 2026.02.20 R2) // Format: YYYY.MM.DD Rn (example: 2026.02.20 R2)
window.CHGRID_WEB_VERSION = "2026.02.25 R270"; window.CHGRID_WEB_VERSION = "2026.02.25 R271";
// Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid. // Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid.
window.CHGRID_TIME_ZONE = "America/Detroit"; window.CHGRID_TIME_ZONE = "America/Detroit";

View File

@@ -13,14 +13,14 @@ export class ClockAnnouncer {
private readonly getListenerPosition: ListenerPositionGetter, private readonly getListenerPosition: ListenerPositionGetter,
) {} ) {}
async playSequence(sounds: string[], sourceX: number, sourceY: number): Promise<void> { async playSequence(sounds: string[], sourceX: number, sourceY: number, range?: number): Promise<void> {
if (sounds.length === 0) return; if (sounds.length === 0) return;
const token = ++this.playToken; const token = ++this.playToken;
const effectiveRange = Number.isFinite(range) && (range as number) > 0 ? (range as number) : undefined;
for (const sound of sounds) { for (const sound of sounds) {
if (token !== this.playToken) return; if (token !== this.playToken) return;
const listener = this.getListenerPosition(); const listener = this.getListenerPosition();
await this.audio.playSpatialSampleAndWait(sound, { x: sourceX, y: sourceY }, listener, 1); await this.audio.playSpatialSampleAndWait(sound, { x: sourceX, y: sourceY }, listener, 1, effectiveRange);
} }
} }
} }

View File

@@ -1660,8 +1660,8 @@ const onAppMessage = createOnMessageHandler({
playIncomingItemUseSound: (url, x, y, range) => { playIncomingItemUseSound: (url, x, y, range) => {
void audio.playSpatialSample(url, { x, y }, { x: state.player.x, y: state.player.y }, 1, range ?? HEARING_RADIUS); void audio.playSpatialSample(url, { x, y }, { x: state.player.x, y: state.player.y }, 1, range ?? HEARING_RADIUS);
}, },
playClockAnnouncement: (sounds, x, y) => { playClockAnnouncement: (sounds, x, y, range) => {
void clockAnnouncer.playSequence(sounds.map(resolveIncomingSoundUrl), x, y); void clockAnnouncer.playSequence(sounds.map(resolveIncomingSoundUrl), x, y, range);
}, },
handleAuthRequired, handleAuthRequired,
handleAuthResult, handleAuthResult,

View File

@@ -69,7 +69,7 @@ type MessageHandlerDeps = {
playLocateToneAt: (x: number, y: number) => void; playLocateToneAt: (x: number, y: number) => void;
resolveIncomingSoundUrl: (url: string) => string; resolveIncomingSoundUrl: (url: string) => string;
playIncomingItemUseSound: (url: string, x: number, y: number, range?: number) => void; playIncomingItemUseSound: (url: string, x: number, y: number, range?: number) => void;
playClockAnnouncement: (sounds: string[], x: number, y: number) => void; playClockAnnouncement: (sounds: string[], x: number, y: number, range?: number) => void;
handleAuthRequired: (message: Extract<IncomingMessage, { type: 'auth_required' }>) => void; handleAuthRequired: (message: Extract<IncomingMessage, { type: 'auth_required' }>) => void;
handleAuthResult: (message: Extract<IncomingMessage, { type: 'auth_result' }>) => Promise<void>; handleAuthResult: (message: Extract<IncomingMessage, { type: 'auth_result' }>) => Promise<void>;
isPeerNegotiationReady: () => boolean; isPeerNegotiationReady: () => boolean;
@@ -310,7 +310,7 @@ export function createOnMessageHandler(deps: MessageHandlerDeps): (message: Inco
case 'item_clock_announce': { case 'item_clock_announce': {
if (!deps.getAudioLayers().world) break; if (!deps.getAudioLayers().world) break;
deps.playClockAnnouncement(message.sounds, message.x, message.y); deps.playClockAnnouncement(message.sounds, message.x, message.y, message.range);
break; break;
} }

View File

@@ -222,6 +222,7 @@ export const itemClockAnnounceSchema = z.object({
sounds: z.array(z.string()), sounds: z.array(z.string()),
x: z.number().int(), x: z.number().int(),
y: z.number().int(), y: z.number().int(),
range: z.number().int().positive().optional(),
}); });
export const itemPianoNoteSchema = z.object({ export const itemPianoNoteSchema = z.object({

View File

@@ -301,6 +301,7 @@ class ItemClockAnnouncePacket(BasePacket):
sounds: list[str] sounds: list[str]
x: int x: int
y: int y: int
range: int | None = None
class ItemPianoNoteBroadcastPacket(BasePacket): class ItemPianoNoteBroadcastPacket(BasePacket):

View File

@@ -495,6 +495,7 @@ class SignalingServer:
"""Broadcast one server-authoritative clock speech sequence from item position.""" """Broadcast one server-authoritative clock speech sequence from item position."""
sound_x, sound_y = self._get_item_sound_source_position(item) sound_x, sound_y = self._get_item_sound_source_position(item)
sound_range = self._get_item_emit_range(item)
sounds = self._build_clock_announcement_sounds(item.params, top_of_hour=top_of_hour) sounds = self._build_clock_announcement_sounds(item.params, top_of_hour=top_of_hour)
if not sounds: if not sounds:
return return
@@ -505,6 +506,7 @@ class SignalingServer:
sounds=sounds, sounds=sounds,
x=sound_x, x=sound_x,
y=sound_y, y=sound_y,
range=sound_range,
) )
) )