import http from "node:http"; import fs from "node:fs"; import path from "node:path"; import { WebSocketServer } from "ws"; const PORT = 8787; const ROOT = path.resolve(process.cwd()); const server = http.createServer((req, res) => { const url = req.url === "/" ? "/index.html" : req.url; const filePath = path.join(ROOT, url); fs.readFile(filePath, (err, data) => { if (err) { res.writeHead(404, { "Content-Type": "text/plain" }); res.end("Not found"); return; } const ext = path.extname(filePath); const typeMap = { ".html": "text/html", ".css": "text/css", ".js": "text/javascript" }; res.writeHead(200, { "Content-Type": typeMap[ext] ?? "text/plain" }); res.end(data); }); }); const wss = new WebSocketServer({ server }); const palette = ["#4ed1ff", "#ffb347", "#7cff6b", "#ff6be5", "#9f8bff", "#ffd86b"]; let paletteIndex = 0; const players = new Map(); const broadcast = (payload) => { const message = JSON.stringify(payload); for (const client of wss.clients) { if (client.readyState === 1) { client.send(message); } } }; wss.on("connection", (socket) => { let playerId = null; socket.on("message", (data) => { let message; try { message = JSON.parse(data.toString()); } catch { return; } if (message.type === "join") { playerId = `p_${Math.random().toString(36).slice(2, 9)}`; const color = palette[paletteIndex % palette.length]; paletteIndex += 1; const name = String(message.name || "Pilot").slice(0, 14); players.set(playerId, { id: playerId, name, color, x: 0, y: 0, score: 0, shield: 100, wave: 1, lastSeen: Date.now() }); socket.send(JSON.stringify({ type: "welcome", id: playerId, color })); return; } if (message.type === "state" && playerId && players.has(playerId)) { const player = players.get(playerId); player.x = message.x; player.y = message.y; player.score = message.score; player.shield = message.shield; player.wave = message.wave; player.lastSeen = Date.now(); } }); socket.on("close", () => { if (playerId) { players.delete(playerId); } }); }); setInterval(() => { const now = Date.now(); for (const [id, player] of players.entries()) { if (now - player.lastSeen > 8000) { players.delete(id); } } broadcast({ type: "roster", players: Array.from(players.values()) }); }, 120); server.listen(PORT, () => { console.log(`Star Courier running on http://localhost:${PORT}`); });