feat: redesign match play and add broadcast tooling
This commit is contained in:
67
streamer/tosu.ts
Normal file
67
streamer/tosu.ts
Normal 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
|
||||
}))
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user