Heartbeat server

This commit is contained in:
2026-02-09 23:06:15 +01:00
parent dec8fa1710
commit bd9db87ccb
2 changed files with 107 additions and 78 deletions

View File

@@ -17,29 +17,36 @@ const rooms = {};
function broadcast(roomId) {
const room = rooms[roomId];
if (!room) return;
room.players.forEach(p => {
if (p.ws && p.ws.readyState === WebSocket.OPEN) {
p.ws.send(JSON.stringify({
type: "state",
game: room.game,
yourRole: p.role
}));
p.ws.send(JSON.stringify({ type: "state", game: room.game, yourRole: p.role }));
}
});
}
// Heartbeat: Check if clients are still alive every 30s
const interval = setInterval(() => {
wss.clients.forEach(ws => {
if (ws.isAlive === false) return ws.terminate();
ws.isAlive = false;
ws.ping();
});
}, 30000);
wss.on("connection", (ws, req) => {
const urlParams = new URLSearchParams(req.url.split('?')[1]);
let roomId = urlParams.get("room");
let sessionId = urlParams.get("sessionId");
ws.isAlive = true;
ws.on('pong', () => ws.isAlive = true);
if (!roomId || !rooms[roomId]) {
if (!roomId) roomId = randomBytes(3).toString("hex");
if (!roomId || roomId === "null") roomId = randomBytes(3).toString("hex");
rooms[roomId] = {
game: { wolf: 5, sheep: [0, 1, 3], turn: "sheep", moveCount: 0, winner: null },
players: [],
nextFirstRole: "sheep" // Tracks who should be sheep next game
nextFirstRole: "sheep"
};
}
@@ -55,7 +62,6 @@ wss.on("connection", (ws, req) => {
if (player) {
player.ws = ws;
} else {
// Assign role based on who is already there
const role = room.players.length === 0 ? room.nextFirstRole : (room.nextFirstRole === "sheep" ? "wolf" : "sheep");
player = { ws, role, sessionId };
room.players.push(player);
@@ -66,31 +72,23 @@ wss.on("connection", (ws, req) => {
ws.on("message", msg => {
let data = JSON.parse(msg);
if (data.type === "restart") {
// Swap roles for the next round
room.players.forEach(p => p.role = (p.role === "wolf" ? "sheep" : "wolf"));
room.nextFirstRole = room.nextFirstRole === "sheep" ? "wolf" : "sheep";
room.game = { wolf: 5, sheep: [0, 1, 3], turn: "sheep", moveCount: 0, winner: null };
broadcast(roomId);
} else if (data.type === "leave") {
room.players = room.players.filter(p => p.sessionId !== sessionId);
if (room.players.length === 0) delete rooms[roomId];
} else {
} else if (data.from !== undefined && data.to !== undefined) {
handleMove(roomId, player.role, data);
}
});
});
// Reuse the handleMove and checkWinConditions from previous scripts...
function checkWinConditions(game) {
if (game.wolf === 0) return "wolf";
if (game.moveCount >= 40) return "wolf";
const canWolfMove = board_wolf[game.wolf].some(to => !game.sheep.includes(to));
const canSheepMove = game.sheep.some(from => board_sheep[from].some(to => to !== game.wolf && !game.sheep.includes(to)));
if (!canWolfMove) return "sheep";
if (!canSheepMove && game.turn === "sheep") return "wolf";
return null;
}
ws.on("close", () => {
// We keep the player in the room for a while to allow reconnects
});
});
function handleMove(roomId, role, { from, to }) {
const room = rooms[roomId];
@@ -107,4 +105,14 @@ function handleMove(roomId, role, { from, to }) {
broadcast(roomId);
}
server.listen(3030);
function checkWinConditions(game) {
if (game.wolf === 0) return "wolf";
if (game.moveCount >= 40) return "wolf";
const canWolfMove = board_wolf[game.wolf].some(to => !game.sheep.includes(to));
const canSheepMove = game.sheep.some(from => board_sheep[from].some(to => to !== game.wolf && !game.sheep.includes(to)));
if (!canWolfMove) return "sheep";
if (!canSheepMove && game.turn === "sheep") return "wolf";
return null;
}
server.listen(3030, () => console.log("Server running on port 3030"));