version 2

This commit is contained in:
KeshavAnandCode
2026-03-20 18:14:27 -05:00
parent 14dd3fcb75
commit 1075b59d2d
5 changed files with 2334 additions and 1227 deletions

View File

@@ -1,28 +1,25 @@
import type { ServerWebSocket } from "bun";
export interface RoomSettings {
teamMode: boolean;
mode: "individual" | "teams";
numTeams: number;
teamNames: string[];
allowRebuzz: boolean;
buzzerLockout: boolean;
showOrder: boolean;
pointsCorrect: number;
pointsIncorrect: number;
pointsNeg: boolean;
playerPickTeam: boolean; // players can self-assign teams
showBuzzOrder: boolean; // show full order vs first only
buzzerLockout: boolean; // lock after first buzz
timerSeconds: number; // 0 = no timer
}
export interface Player {
id: string;
name: string;
teamIndex: number | null;
score: number;
ws: ServerWebSocket<unknown> | null;
isConnected: boolean;
joinedAt: number;
}
export interface BuzzerState {
roundOpen: boolean;
active: boolean;
buzzOrder: string[];
buzzTimes: Map<string, number>;
}
@@ -34,85 +31,55 @@ export interface Room {
settings: RoomSettings;
players: Map<string, Player>;
buzzerState: BuzzerState;
locked: boolean;
createdAt: number;
locked: boolean; // room locked to new joins
teamLocked: boolean; // team selection locked
}
import type { ServerWebSocket } from "bun";
export const rooms = new Map<string, Room>();
export const rooms = new Map<string, Room>();
export const wsToPlayer = new Map<ServerWebSocket<unknown>, { roomId: string; playerId: string }>();
export function generateId(len = 8): string {
const chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
let out = "";
for (let i = 0; i < len; i++) out += chars[Math.floor(Math.random() * chars.length)];
return out;
export function genId(len = 8): string {
const c = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
let s = "";
for (let i = 0; i < len; i++) s += c[Math.floor(Math.random() * c.length)];
return s;
}
export function defaultSettings(): RoomSettings {
export function sanitize(v: unknown, max = 32): string {
return String(v ?? "").trim().replace(/[<>"'`]/g, "").slice(0, max);
}
export function freshBuzzer(): BuzzerState {
return { roundOpen: false, buzzOrder: [], buzzTimes: new Map() };
}
export function publicRoom(room: Room) {
return {
teamMode: false,
numTeams: 2,
teamNames: ["ALPHA", "BETA", "GAMMA", "DELTA", "EPSILON", "ZETA", "ETA", "THETA"],
allowRebuzz: false,
buzzerLockout: true,
showOrder: true,
pointsCorrect: 100,
pointsIncorrect: 0,
pointsNeg: false,
};
}
export function freshBuzzerState(): BuzzerState {
return { roundOpen: false, active: false, buzzOrder: [], buzzTimes: new Map() };
}
export function sanitize(str: unknown, maxLen = 32): string {
return String(str ?? "")
.trim()
.replace(/[<>"'`]/g, "")
.slice(0, maxLen);
}
export function getPublicRoom(room: Room) {
return {
id: room.id,
settings: room.settings,
locked: room.locked,
modOnline: room.modWs !== null,
id: room.id,
settings: room.settings,
locked: room.locked,
teamLocked: room.teamLocked,
modOnline: room.modWs !== null,
buzzerState: {
roundOpen: room.buzzerState.roundOpen,
active: room.buzzerState.active,
buzzOrder: room.buzzerState.buzzOrder,
},
players: Array.from(room.players.values()).map((p) => ({
id: p.id,
name: p.name,
teamIndex: p.teamIndex,
score: p.score,
players: Array.from(room.players.values()).map(p => ({
id: p.id,
name: p.name,
teamIndex: p.teamIndex,
isConnected: p.isConnected,
})),
};
}
export function broadcastToRoom(
room: Room,
msg: object,
exclude?: ServerWebSocket<unknown>
) {
const data = JSON.stringify(msg);
for (const p of room.players.values()) {
if (p.ws && p.isConnected && p.ws !== exclude) {
try { p.ws.send(data); } catch {}
}
}
if (room.modWs && room.modWs !== exclude) {
try { room.modWs.send(data); } catch {}
}
export function broadcast(room: Room, msg: object, exclude?: ServerWebSocket<unknown>) {
const d = JSON.stringify(msg);
for (const p of room.players.values())
if (p.ws && p.isConnected && p.ws !== exclude) try { p.ws.send(d); } catch {}
if (room.modWs && room.modWs !== exclude) try { room.modWs.send(d); } catch {}
}
export function sendToMod(room: Room, msg: object) {
if (!room.modWs) return;
try { room.modWs.send(JSON.stringify(msg)); } catch {}
}
export function toMod(room: Room, msg: object) {
if (room.modWs) try { room.modWs.send(JSON.stringify(msg)); } catch {}
}