Files
esports/streamer/tosu.ts

68 lines
1.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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
}))
};
}