Add configurable manifest-driven race audio system
This commit is contained in:
@@ -251,7 +251,7 @@ export function processDecoderMessageHelper(msg, deps, decoderRole = "main") {
|
||||
state, t, getActiveSession, ensureSessionResult, normalizeStartMode, getSessionLapWindow,
|
||||
findEventTeamForPassing, persistPassingToBackend, pushOverlayEvent, buildLeaderboard,
|
||||
formatLap, announcePassing, saveState, lastOverlayLeaderKeyBySession,
|
||||
lastOverlayTop3BySession, lastOverlayBestLapByKey,
|
||||
lastOverlayTop3BySession, lastOverlayBestLapByKey, triggerRaceAudio = () => {}, getTrackRecordMs = () => null,
|
||||
} = deps;
|
||||
|
||||
if (!msg || typeof msg !== "object") {
|
||||
@@ -277,6 +277,7 @@ export function processDecoderMessageHelper(msg, deps, decoderRole = "main") {
|
||||
const result = ensureSessionResult(session.id);
|
||||
const competitor = resolveCompetitor(session, transponder, { state, t, findEventTeamForPassing });
|
||||
if (competitor.ignore) {
|
||||
triggerRaceAudio("unknown_transponder", { variables: { transponder }, scope: transponder, logData: { raceId: session.eventId, sessionId: session.id } });
|
||||
return;
|
||||
}
|
||||
const key = competitor.key;
|
||||
@@ -327,6 +328,7 @@ export function processDecoderMessageHelper(msg, deps, decoderRole = "main") {
|
||||
if (!Array.isArray(result.pitEvents)) result.pitEvents = [];
|
||||
result.pitEvents.push({ timestamp, type: "entry", transponder, competitorKey: key, driverId: entry.driverId, carId: entry.carId });
|
||||
pushOverlayEvent("pit", `${entry.displayName || entry.driverName} • PIT IN`);
|
||||
triggerRaceAudio("entering_pits", { variant: entry.carId || entry.driverId || transponder, driverId: entry.driverId, logData: { raceId: session.eventId, driverId: entry.driverId } });
|
||||
saveState();
|
||||
return;
|
||||
}
|
||||
@@ -356,6 +358,7 @@ export function processDecoderMessageHelper(msg, deps, decoderRole = "main") {
|
||||
entry.pitEntryCarName = "";
|
||||
entry.pitEntryTransponder = "";
|
||||
pushOverlayEvent("pit", `${entry.displayName || entry.driverName} • PIT ${formatLap(pitStopMs)}`);
|
||||
triggerRaceAudio("leaving_pits", { variant: entry.carId || entry.driverId || transponder, driverId: entry.driverId, logData: { raceId: session.eventId, driverId: entry.driverId } });
|
||||
saveState();
|
||||
return;
|
||||
}
|
||||
@@ -448,6 +451,13 @@ export function processDecoderMessageHelper(msg, deps, decoderRole = "main") {
|
||||
return;
|
||||
}
|
||||
|
||||
const previousPersonalBest = Number(entry.bestLapMs || 0) || null;
|
||||
const leaderboardBefore = buildLeaderboard(session);
|
||||
const previousPosition = leaderboardBefore.findIndex((row) => row.key === key);
|
||||
const previousLeaderKey = leaderboardBefore[0]?.key || null;
|
||||
const previousSessionFastest = leaderboardBefore.map((row) => Number(row.bestLapMs || 0)).filter((value) => value > 500).sort((a, b) => a - b)[0] || null;
|
||||
const previousTrackRecord = Number(getTrackRecordMs(session) || 0) || null;
|
||||
|
||||
entry.laps += 1;
|
||||
entry.lastLapMs = lapMs;
|
||||
entry.lastTimestamp = timestamp;
|
||||
@@ -460,10 +470,18 @@ export function processDecoderMessageHelper(msg, deps, decoderRole = "main") {
|
||||
persistPassingToBackend(session.id, passing);
|
||||
pushOverlayEvent("passing", `${entry.displayName || entry.driverName} • ${formatLap(entry.lastLapMs)}`);
|
||||
const leaderboard = buildLeaderboard(session);
|
||||
const currentPosition = leaderboard.findIndex((row) => row.key === key);
|
||||
const audioVariables = { driverName: entry.speechName || entry.displayName || entry.driverName, lapTime: formatLap(lapMs) };
|
||||
if (previousPersonalBest && lapMs < previousPersonalBest) triggerRaceAudio("personal_best", { variables: audioVariables, driverId: entry.driverId, competitorKey: key, logData: { raceId: session.eventId, driverId: entry.driverId, lapNumber: entry.laps, lapTime: lapMs } });
|
||||
if (previousSessionFastest && lapMs < previousSessionFastest) triggerRaceAudio("fastest_lap", { variables: audioVariables, driverId: entry.driverId, competitorKey: key, logData: { raceId: session.eventId, driverId: entry.driverId, lapNumber: entry.laps, lapTime: lapMs } });
|
||||
if (previousTrackRecord && lapMs < previousTrackRecord) triggerRaceAudio("track_record", { variables: audioVariables, driverId: entry.driverId, competitorKey: key, logData: { raceId: session.eventId, driverId: entry.driverId, lapNumber: entry.laps, lapTime: lapMs } });
|
||||
if (previousPosition >= 0 && currentPosition >= 0 && currentPosition < previousPosition) triggerRaceAudio("position_gain", { driverId: entry.driverId, competitorKey: key });
|
||||
if (previousPosition >= 0 && currentPosition > previousPosition) triggerRaceAudio("position_loss", { driverId: entry.driverId, competitorKey: key });
|
||||
const leader = leaderboard[0];
|
||||
if (leader?.key && lastOverlayLeaderKeyBySession[session.id] !== leader.key) {
|
||||
lastOverlayLeaderKeyBySession[session.id] = leader.key;
|
||||
pushOverlayEvent("leader", `${leader.displayName || leader.driverName} • P1`);
|
||||
if (previousLeaderKey && previousLeaderKey !== leader.key) triggerRaceAudio("new_leader", { variables: { driverName: leader.displayName || leader.driverName }, driverId: leader.driverId, competitorKey: leader.key, logData: { raceId: session.eventId, driverId: leader.driverId } });
|
||||
}
|
||||
if (entry.bestLapMs && Number.isFinite(entry.bestLapMs)) {
|
||||
const bestKey = `${session.id}:${entry.key}`;
|
||||
|
||||
Reference in New Issue
Block a user