From e59b444dd3e9c5b8dc55d507181ac156118a9aa9 Mon Sep 17 00:00:00 2001 From: KeshavAnandCode Date: Fri, 20 Mar 2026 17:55:48 -0500 Subject: [PATCH] rooms --- src/rooms.ts | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/src/rooms.ts b/src/rooms.ts index e69de29..a648464 100644 --- a/src/rooms.ts +++ b/src/rooms.ts @@ -0,0 +1,118 @@ +export interface RoomSettings { + teamMode: boolean; + numTeams: number; + teamNames: string[]; + allowRebuzz: boolean; + buzzerLockout: boolean; + showOrder: boolean; + pointsCorrect: number; + pointsIncorrect: number; + pointsNeg: boolean; +} + +export interface Player { + id: string; + name: string; + teamIndex: number | null; + score: number; + ws: ServerWebSocket | null; + isConnected: boolean; + joinedAt: number; +} + +export interface BuzzerState { + roundOpen: boolean; + active: boolean; + buzzOrder: string[]; + buzzTimes: Map; +} + +export interface Room { + id: string; + moderatorSecret: string; + modWs: ServerWebSocket | null; + settings: RoomSettings; + players: Map; + buzzerState: BuzzerState; + locked: boolean; + createdAt: number; +} + +import type { ServerWebSocket } from "bun"; + +export const rooms = new Map(); +export const wsToPlayer = new Map, { 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 defaultSettings(): RoomSettings { + 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, + 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, + isConnected: p.isConnected, + })), + }; +} + +export function broadcastToRoom( + room: Room, + msg: object, + exclude?: ServerWebSocket +) { + 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 sendToMod(room: Room, msg: object) { + if (!room.modWs) return; + try { room.modWs.send(JSON.stringify(msg)); } catch {} +}