Add barrier type. Transition into playing phase properly.
This commit is contained in:
30
static/js/barrier.js
Normal file
30
static/js/barrier.js
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Typical barrier type.
|
||||
*
|
||||
* Block all clients until everyone has hit the barrier.
|
||||
*/
|
||||
class Barrier {
|
||||
constructor() {
|
||||
let resolver;
|
||||
this.promise = new Promise((resolve) => {
|
||||
resolver = resolve;
|
||||
});
|
||||
this.resolver = resolver;
|
||||
this.hits = new Set();
|
||||
}
|
||||
|
||||
wait() {
|
||||
socket.emit("message", Packet.createBarrierSignal());
|
||||
|
||||
return this.promise;
|
||||
}
|
||||
|
||||
resolve(data) {
|
||||
this.hits.add(data.author);
|
||||
|
||||
if (this.hits.size === Object.keys(players).length - 1) {
|
||||
this.hits = new Set();
|
||||
this.resolver();
|
||||
}
|
||||
}
|
||||
}
|
@ -2,17 +2,36 @@ function updatePlayerDom() {
|
||||
let list = document.querySelector("#playerList");
|
||||
list.replaceChildren();
|
||||
|
||||
let newDom = document.createElement("li");
|
||||
newDom.textContent = ID + " (you)";
|
||||
newDom.style.color = "grey";
|
||||
list.appendChild(newDom);
|
||||
for (let playerId of Object.keys(players).sort()) {
|
||||
let player = players[playerId];
|
||||
|
||||
for (let playerId of Object.keys(players)) {
|
||||
if (playerId !== ID) {
|
||||
let newDom = document.createElement("li");
|
||||
newDom.textContent = playerId;
|
||||
list.appendChild(newDom);
|
||||
let statusSpan = document.createElement("div");
|
||||
statusSpan.classList.add("status-span");
|
||||
if (game_state === WAITING) {
|
||||
if (player.ready) {
|
||||
statusSpan.textContent = "R";
|
||||
statusSpan.classList.add("ready");
|
||||
} else {
|
||||
statusSpan.textContent = "N";
|
||||
statusSpan.classList.add("not-ready");
|
||||
}
|
||||
} else {
|
||||
if (player.isPlaying) {
|
||||
statusSpan.textContent = "P";
|
||||
}
|
||||
}
|
||||
|
||||
let idSpan = document.createElement("span");
|
||||
if (playerId === ID) {
|
||||
idSpan.textContent = `${playerId} (you)`;
|
||||
} else {
|
||||
idSpan.textContent = playerId;
|
||||
}
|
||||
|
||||
let newDom = document.createElement("li");
|
||||
newDom.appendChild(statusSpan);
|
||||
newDom.appendChild(idSpan);
|
||||
list.appendChild(newDom);
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,12 +43,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
ev.target.classList.toggle("active");
|
||||
ev.target.textContent = nowReady ? "Ready" : "Not ready";
|
||||
|
||||
socket.emit("message", {
|
||||
type: "SYNC",
|
||||
author: ID,
|
||||
ready: nowReady,
|
||||
name: "",
|
||||
});
|
||||
socket.emit("message", Packet.createSetReady(nowReady));
|
||||
|
||||
updatePlayerDom();
|
||||
|
||||
if (allPlayersReady()) {
|
||||
await startPregame();
|
||||
|
@ -14,29 +14,21 @@ let game_state = WAITING;
|
||||
|
||||
let socket;
|
||||
let random;
|
||||
let barrier;
|
||||
|
||||
// Not totally reliable but better than nothing.
|
||||
window.addEventListener("beforeunload", () => {
|
||||
socket.emit("message", {
|
||||
type: "DISCONNECT",
|
||||
id: window.crypto.randomUUID(),
|
||||
author: ID,
|
||||
name: "",
|
||||
});
|
||||
socket.emit("message", Packet.createDisconnect());
|
||||
});
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
socket = io();
|
||||
random = new Random();
|
||||
barrier = new Barrier();
|
||||
|
||||
socket.on("connect", () => {
|
||||
console.log("Connected!");
|
||||
socket.emit("message", {
|
||||
type: "ANNOUNCE",
|
||||
id: window.crypto.randomUUID(),
|
||||
author: ID,
|
||||
name: "",
|
||||
});
|
||||
socket.emit("message", Packet.createAnnounce());
|
||||
// Create self
|
||||
players[ID] = new Player(ID, name);
|
||||
us = players[ID];
|
||||
@ -61,23 +53,23 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
keepAlive(data);
|
||||
break;
|
||||
|
||||
case "SYNC":
|
||||
await sync(data);
|
||||
case "READY":
|
||||
await setReady(data);
|
||||
break;
|
||||
|
||||
case "RANDOM":
|
||||
await random.processCooperativeRandom(data);
|
||||
break;
|
||||
|
||||
case "BARRIER":
|
||||
barrier.resolve(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,
|
||||
});
|
||||
socket.emit("message", Packet.createKeepAlive());
|
||||
}, TIMEOUT / 5);
|
||||
});
|
||||
|
||||
@ -95,12 +87,7 @@ function playerConnected(data) {
|
||||
// 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: "",
|
||||
});
|
||||
socket.emit("message", Packet.createAnnounce());
|
||||
players[data.author].resetTimeout();
|
||||
} else {
|
||||
}
|
||||
@ -128,10 +115,12 @@ function keepAlive(data) {
|
||||
*
|
||||
* @param data Packet received
|
||||
*/
|
||||
async function sync(data) {
|
||||
async function setReady(data) {
|
||||
players[data.author].name = data.name;
|
||||
players[data.author].ready = data.ready;
|
||||
|
||||
updatePlayerDom();
|
||||
|
||||
if (allPlayersReady()) {
|
||||
await startPregame();
|
||||
}
|
||||
@ -148,11 +137,20 @@ function allPlayersReady() {
|
||||
}
|
||||
|
||||
async function startPregame() {
|
||||
console.log("All players ready.");
|
||||
console.log("all players ready.");
|
||||
|
||||
game_state = PRE_GAME;
|
||||
|
||||
let player1 = await random.get(Object.keys(players).length, "first-player");
|
||||
let firstPlayerIndex = await random.get(Object.keys(players).length, "first-player");
|
||||
|
||||
console.log(player1);
|
||||
let firstPlayer = Object.values(players).sort((a, b) => (a.id < b.id ? -1 : 1))[
|
||||
firstPlayerIndex
|
||||
];
|
||||
|
||||
firstPlayer.isPlaying = true;
|
||||
game_state = PLAYING;
|
||||
|
||||
await barrier.wait();
|
||||
|
||||
updatePlayerDom();
|
||||
}
|
||||
|
35
static/js/packet.js
Normal file
35
static/js/packet.js
Normal file
@ -0,0 +1,35 @@
|
||||
class Packet {
|
||||
static _createBase(name) {
|
||||
return {
|
||||
type: name,
|
||||
id: window.crypto.randomUUID(),
|
||||
author: ID,
|
||||
};
|
||||
}
|
||||
|
||||
static createAnnounce() {
|
||||
return {
|
||||
...this._createBase("ANNOUNCE"),
|
||||
name: "",
|
||||
};
|
||||
}
|
||||
|
||||
static createDisconnect() {
|
||||
return this._createBase("DISCONNECT");
|
||||
}
|
||||
|
||||
static createKeepAlive() {
|
||||
return this._createBase("KEEPALIVE");
|
||||
}
|
||||
|
||||
static createSetReady(nowReady) {
|
||||
return {
|
||||
...this._createBase("READY"),
|
||||
ready: nowReady,
|
||||
};
|
||||
}
|
||||
|
||||
static createBarrierSignal() {
|
||||
return this._createBase("BARRIER");
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ class Player {
|
||||
this.timeout = null;
|
||||
this.id = id;
|
||||
this.ready = false;
|
||||
this.isPlaying = false;
|
||||
}
|
||||
|
||||
resetTimeout() {
|
||||
|
@ -27,7 +27,6 @@ class Random {
|
||||
|
||||
let promise;
|
||||
await navigator.locks.request(`random-${sessionId}`, () => {
|
||||
console.log("in lock now");
|
||||
if (this.sessions[sessionId].finalValue === null) {
|
||||
let session = this.sessions[sessionId];
|
||||
let resolver;
|
||||
|
Reference in New Issue
Block a user