const ID = window.crypto.randomUUID(); // Timeout to consider a player disconnected const TIMEOUT = 30_000; let players = {}; document.addEventListener("DOMContentLoaded", () => { let socket = io(); socket.on("connect", () => { console.log("Connected!"); socket.emit("message", { type: "ANNOUNCE", author: ID, name: "" }); players[ID] = { name: "", timeout: null }; }); socket.on("message", (data) => { // Ignore any messages that originate from us. if (data.author !== ID) { switch (data.type) { case "ANNOUNCE": playerConnected(socket, data); break; case "KEEPALIVE": keepAlive(data); break; } } }); // Emit keepalive messages to inform other players we are still here window.setInterval(() => { socket.emit("message", { type: "KEEPALIVE", author: ID }); }, TIMEOUT / 5); }); function playerConnected(socket, data) { // When a new player is seen, all announce to ensure they know all players. if (players[data.author] === undefined) { players[data.author] = { name: data.name, timeout: window.setTimeout(() => { delete players[data.author]; updatePlayerDom(); }, TIMEOUT) }; socket.emit("message", { type: "ANNOUNCE", author: ID, name: "" }); } else { } updatePlayerDom(); } function keepAlive(data) { window.clearTimeout(players[data.author].timeout); players[data.author].timeout = window.setTimeout(() => { delete players[data.author]; updatePlayerDom(); }, TIMEOUT); } function updatePlayerDom() { let list = document.querySelector('#playerList'); list.replaceChildren(); for (let playerId of Object.keys(players)) { let newDom = document.createElement('li'); newDom.textContent = playerId; list.appendChild(newDom); } }