156 lines
3.6 KiB
JavaScript
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;
|
|
}
|