feat: redesign match play and add broadcast tooling

This commit is contained in:
2026-09-29 02:52:56 +00:00
parent f417a831f7
commit 9b9aafefc1
348 changed files with 31588 additions and 11094 deletions

67
streamer/tosu.ts Normal file
View File

@@ -0,0 +1,67 @@
/**
* tosu (https://github.com/tosuapp/tosu) reads the osu! tourney client's
* memory and serves it over a websocket. We need each spectated player's
* live score, and how far through the map they are.
*/
export interface TosuClientScore {
osuId: number;
name: string;
score: number;
/** Percent. */
accuracy: number;
combo: number;
failed: boolean;
}
export interface TosuFrame {
/** 1 idle, 2 waiting for clients, 3 playing, 4 results (tosu's ipcState). */
ipcState: number | null;
beatmapId: number | null;
/** 0–1 through the map. */
progress: number | null;
clients: TosuClientScore[];
}
/** Picks what Vash needs out of one tosu v2 message. Returns null outside tourney mode. */
export function parseTosu(message: unknown): TosuFrame | null {
const root = message as {
tourney?: {
ipcState?: number;
clients?: {
user?: { id?: number; name?: string };
play?: {
score?: number;
accuracy?: number;
failed?: boolean;
combo?: { current?: number };
};
}[];
};
beatmap?: { id?: number; time?: { live?: number; firstObject?: number; lastObject?: number } };
};
if (!root?.tourney || !Array.isArray(root.tourney.clients)) return null;
const time = root.beatmap?.time;
const span =
time && time.lastObject != null && time.firstObject != null
? time.lastObject - time.firstObject
: 0;
return {
ipcState: root.tourney.ipcState ?? null,
beatmapId: root.beatmap?.id ?? null,
progress:
span > 0 && time?.live != null
? Math.max(0, Math.min(1, (time.live - time.firstObject!) / span))
: null,
clients: root.tourney.clients
.filter((client) => (client.user?.id ?? 0) > 0)
.map((client) => ({
osuId: client.user!.id!,
name: client.user?.name ?? '',
score: client.play?.score ?? 0,
accuracy: client.play?.accuracy ?? 0,
combo: client.play?.combo?.current ?? 0,
failed: client.play?.failed ?? false
}))
};
}