Riskless/static/js/index.js

156 lines
3.6 KiB
JavaScript

const ID = window.crypto.randomUUID();
// Timeout to consider a player disconnected
const TIMEOUT = 30_000;
let players = {};
const WAITING = 0;
const PRE_GAME = 1;
const PLAYING = 2;
const POST_GAME = 3;
let game_state = WAITING;
let socket;
let random;
// Not totally reliable but better than nothing.
window.addEventListener("beforeunload", () => {
socket.emit("message", {
type: "DISCONNECT",
id: window.crypto.randomUUID(),
author: ID,
name: "",
});
});
document.addEventListener("DOMContentLoaded", () => {
socket = io();
random = new Random();
socket.on("connect", () => {
console.log("Connected!");
socket.emit("message", {
type: "ANNOUNCE",
id: window.crypto.randomUUID(),
author: ID,
name: "",
});
// Create self
players[ID] = new Player(ID, name);
});
socket.on("message", async (data) => {
// Ignore any messages that originate from us.
if (data.author === ID) {
return;
}
switch (data.type) {
case "ANNOUNCE":
playerConnected(data);
break;
case "DISCONNECT":
playerDisconnected(data);
break;
case "KEEPALIVE":
keepAlive(data);
break;
case "SYNC":
await sync(data);
break;
case "RANDOM":
random.processCooperativeRandom(data);
break;
}
});
// Emit keepalive messages to inform other players we are still here
window.setInterval(() => {
socket.emit("message", {
type: "KEEPALIVE",
id: window.crypto.randomUUID(),
author: ID,
});
}, TIMEOUT / 5);
});
/**
* Process player connect packets: these inform that a new player has joined.
*
* @param data Packet received
*/
function playerConnected(data) {
// Block players from joining mid-game
if (game_state !== WAITING) {
return;
}
// When a new player is seen, all announce to ensure they know all players.
if (players[data.author] === undefined) {
players[data.author] = new Player(data.author, data.name);
socket.emit("message", {
type: "ANNOUNCE",
id: window.crypto.randomUUID(),
author: ID,
name: "",
});
players[data.author].resetTimeout();
} else {
}
updatePlayerDom();
}
function playerDisconnected(data) {
console.log("deleting player");
delete players[data.author];
updatePlayerDom();
}
/**
* Process keep-alive packets: these are packets that check players are still online.
*
* @param data Packet received
*/
function keepAlive(data) {
players[data.author].resetTimeout();
}
/**
* Process sync packets: update player details like status and name.
*
* @param data Packet received
*/
async function sync(data) {
players[data.author].name = data.name;
players[data.author].ready = data.ready;
if (allPlayersReady()) {
game_state = PRE_GAME;
// Decide turn order. "Master" begins a cooperative rng process.
if (ID === Array.min(...Object.keys(players))) {
random.coopRandom(Object.keys(players).length, "first-player");
}
// Wait for value to populate
let player1 = await random.get("first-player");
console.log(player1);
}
}
function allPlayersReady() {
for (let player of Object.values(players)) {
if (!player.ready) {
return false;
}
}
return true;
}