#!/usr/bin/env node const http = require("http"); const express = require("express"); const socketio = require("socket.io") const PORT = 8080; const app = express(); const server = http.Server(app); const io = socketio(server); // gameid -> {pl: [socket], started: Bool} const games = new Map(); function genId() { for (let i = 0; i < 10; i++) { // 2176782336 == 36^6 const id = ("000000" + (2176782336 * Math.random() | 0).toString(36)).slice(-6); if (!games.has(id)) return id; } return ""; } function validId(id) { return /^[0-9a-z]{6}$/.test(id); } app.get("/", (req, res) => { const gameid = genId(); if (gameid == "") { res.sendStatus(500); return; } res.redirect("/game/" + gameid); }); app.param("gameid", (req, res, next, gameid) => { if (!validId(gameid)) { res.sendStatus(404); } else { next(); } }); app.get("/game/:gameid", (req, res) => { res.sendFile(__dirname + "/game.html"); }); app.get("/game.css", (req, res) => res.sendFile(__dirname + "/game.css")); app.get("/game.js", (req, res) => res.sendFile(__dirname + "/game.js")); io.on("connection", (conn) => { let gameid, gameobj; conn.on("open", (id) => { console.log("open " + id); if (!validId(id)) { console.log(" invalid"); conn.emit("redirect", "/"); conn.disconnect(true); return; } gameobj = games.get(id); if (gameobj != undefined) { if (gameobj.pl.length == 1 && !gameobj.started) { console.log(" serve"); gameid = id; gameobj.pl.push(conn); gameobj.pl[0].emit("status", "Get ready..."); gameobj.pl[1].emit("status", "Get ready..."); gameobj.pl[0].emit("serve", "left", 0.5, 0.5); gameobj.pl[1].emit("serve", "right", 0.5, 0.5); gameobj.started = true; setTimeout(() => { if (!gameobj || gameobj.pl.length != 2) return; gameobj.pl[0].emit("status", ""); gameobj.pl[1].emit("status", ""); gameobj.pl[0].emit("startBall"); gameobj.pl[1].emit("start"); }, 2000); } else { console.log(" full"); gameobj = undefined; conn.emit("status", "Game full! Opening new game..."); setTimeout(() => { conn.emit("redirect", "/"); conn.disconnect(true); }, 2000); } } else { console.log(" new"); gameid = id; gameobj = {pl: [conn], started: false}; games.set(gameid, gameobj); conn.emit("status", "Waiting for other player..."); } }); conn.on("disconnect", () => { if (gameobj == undefined) return; console.log("stop " + gameid); const newpl = []; for (const p of gameobj.pl) { if (p != conn) { p.emit("stop"); p.emit("status", "Other player left."); setTimeout(() => { p.emit("redirect", "/"); p.disconnect(true); }, 2000); newpl.push(p); } } if (newpl.length == 0) { console.log(" delete"); games.delete(gameid); } else { gameobj.pl = newpl; } }); conn.on("padvec", (pos, vel) => { if (!gameobj) return; for (const p of gameobj.pl) { if (p != conn) { p.emit("padvec", pos, vel); } } }); }); server.listen(PORT, () => console.log("Listening on port " + PORT));