Room codes also dodge orphaned files on disk

makeRoomCode checked only the in-memory map, which covers every live
and restored room — but a file that failed to restore stays on disk
with no map entry, and a new room taking its code would append a
second game into the orphaned file, corrupting both. The generator
now rerolls on disk presence too.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-16 14:02:04 -04:00
co-authored by Claude Fable 5
parent bed29c4992
commit 28bc91c3ac
7 changed files with 117 additions and 134 deletions
@@ -1 +1,108 @@
[ 152609ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 257646ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/treasure-4.png:0
[ 258772ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 260278ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 261785ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 263294ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 264799ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 265121ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/wraith.png:0
[ 266304ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 267808ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 269317ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 270822ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 272327ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 272620ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/skeleton.png:0
[ 273838ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 275344ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 276855ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 277125ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/treasure-3.png:0
[ 278368ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 279883ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 281397ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 282923ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 283123ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/wraith.png:0
[ 284461ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 284627ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/wraith.png:0
[ 286048ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 286122ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/wraith.png:0
[ 287581ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 289243ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 290813ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 292595ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 294390ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 296415ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 298083ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 300593ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 302383ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 305833ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 309405ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 312716ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 313128ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/treasure-4.png:0
[ 315372ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 319132ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/wraith.png:0
[ 320626ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/wraith.png:0
[ 321235ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 325129ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/wraith.png:0
[ 325237ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 331677ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 332629ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/skeleton.png:0
[ 335630ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/wraith.png:0
[ 336248ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 337130ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/wraith.png:0
[ 340522ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 346285ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 349124ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/skeleton.png:0
[ 350627ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/skeleton.png:0
[ 351422ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 352127ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/skeleton.png:0
[ 355407ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 361038ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 364125ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/skeleton.png:0
[ 365624ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/skeleton.png:0
[ 366381ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 367125ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/skeleton.png:0
[ 372878ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 374624ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/thorn-bush.png:0
[ 376712ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 381718ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 386406ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 388135ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/tokens/treasure-4.png:0
[ 389196ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 392191ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 396170ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 397675ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 399182ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 400688ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 402195ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 403703ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 405207ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 406723ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 408239ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 409766ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 411321ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 412956ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 414636ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 416487ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 419087ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 422410ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 428868ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 433168ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 438630ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 444730ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 450587ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 456456ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 460605ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 463161ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 469664ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 473816ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 478354ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 481420ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 486756ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 492582ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 497201ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 503098ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 509043ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 514068ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 518839ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 522451ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
[ 527128ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-CAp618mF.js:1
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

-131
View File
@@ -1,131 +0,0 @@
// Script a complete 2p game on the local server: walk together, punch to the death.
import { WebSocket } from "ws";
import { stepTarget, cellKey } from "./packages/engine/src/board.ts";
const url = "ws://localhost:8899/";
function client() {
const ws = new WebSocket(url);
const queue = [];
const waiters = [];
ws.on("message", (d) => {
const m = JSON.parse(d.toString());
if (waiters.length) waiters.shift()(m);
else queue.push(m);
});
const next = () => new Promise((res) => (queue.length ? res(queue.shift()) : waiters.push(res)));
const send = (m) => ws.send(JSON.stringify(m));
return { ws, next, send, queue };
}
const until = async (c, pred) => {
for (;;) {
const m = await c.next();
if (pred(m)) return m;
}
};
const a = client();
await until(a, (m) => m.type === "welcome");
a.send({ type: "create", name: "alice" });
const seatA = await until(a, (m) => m.type === "seat");
const room = await until(a, (m) => m.type === "room");
const code = room.roomId;
const b = client();
await until(b, (m) => m.type === "welcome");
b.send({ type: "join", roomId: code, name: "bob" });
await until(b, (m) => m.type === "seat");
a.send({ type: "start", expansion: false });
let viewA = (await until(a, (m) => m.type === "state")).view;
let viewB;
const me = (v, who) => v.players.find((p) => p.id === who);
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const settle = async () => {
await sleep(120);
let err = null;
for (const c of [a, b]) {
while (c.queue.length) {
const m = c.queue.shift();
if (m.type === "state" && c === a) viewA = m.view;
if (m.type === "error") err = m.message;
}
}
return err;
};
const cmd = async (c, command) => {
await settle();
c.send({ type: "command", command });
const err = await settle();
return err ? { error: err } : { view: viewA };
};
const step = async (c, dir) => cmd(c, { type: "move", direction: dir });
let safety = 600;
for (;;) {
if (--safety <= 0) throw new Error("script ran away");
await settle();
const who = viewA.activePlayerId;
const active = who === "alice" ? a : b;
const other = who === "alice" ? b : a;
const av = viewA;
if (av.phase === "finished") break;
const meP = me(av, who);
const foe = av.players.find((p) => p.id !== who);
const sameCell = meP.position.x === foe.position.x && meP.position.y === foe.position.y;
let acted = false;
if (sameCell && av.turn.round > 1 && !av.turn.attackUsed) {
const r = await cmd(active, { type: "punch", targetId: foe.id });
if (!r.error) {
await cmd(other, { type: "pass" });
acted = true;
}
}
if (!acted && who === "alice" && av.turn.movementAllowance > av.turn.movementUsed) {
// BFS the maze toward bob; take the first step of the shortest path.
const board = av.board;
const start = meP.position, goal = foe.position;
const prev = new Map([[cellKey(start), null]]);
let frontier = [start];
let found = null;
while (frontier.length && !found) {
const nf = [];
for (const c of frontier) {
for (const d of ["N", "S", "E", "W"]) {
const t = stepTarget(board, c, d);
if (t.kind === "blocked") continue;
const k = cellKey(t.to);
if (prev.has(k)) continue;
prev.set(k, { from: c, dir: d });
if (k === cellKey(goal)) { found = t.to; break; }
nf.push(t.to);
}
if (found) break;
}
frontier = nf;
}
if (found) {
let node = cellKey(found), hop = prev.get(node);
while (hop && cellKey(hop.from) !== cellKey(start)) { node = cellKey(hop.from); hop = prev.get(node); }
if (hop) {
const r = await step(active, hop.dir);
if (!r.error) continue;
}
}
}
const r = await cmd(active, { type: "endTurn", draw: 0 });
if (r.error && /game is over/.test(r.error)) break;
if (r.error) throw new Error("endTurn failed: " + r.error);
}
console.log("FINISHED. winner:", viewA.winner, "room:", code);
// Full replay request.
a.send({ type: "catchUp", sinceSeq: 0, full: true });
const cu = await until(a, (m) => m.type === "catchUp" || m.type === "error");
if (cu.type === "error") { console.log("replay error:", cu.message); process.exit(1); }
console.log("steps:", cu.steps.length);
const s0 = cu.steps[0];
console.log("step0 keys:", Object.keys(s0).join(","));
console.log("step0.view.board present:", !!s0.view?.board, "cells:", s0.view ? Object.keys(s0.view.board.cells).length : 0);
console.log("SEAT for browser:", JSON.stringify([{ roomId: code, name: "alice", token: seatA.token }]));
process.exit(0);
Binary file not shown.

Before

Width:  |  Height:  |  Size: 286 KiB

+4 -2
View File
@@ -15,7 +15,7 @@ import {
type GameView,
type PlayerId,
} from "@wizwar/engine";
import { appendLine, ensureDataDir, readAllRooms, type RoomLine } from "./store";
import { appendLine, ensureDataDir, readAllRooms, roomFileExists, type RoomLine } from "./store";
import { recordRoom } from "./stats";
export interface LoggedCommand {
@@ -72,7 +72,9 @@ function makeRoomCode(): string {
for (let i = 0; i < 4; i++) {
code += ROOM_CODE_ALPHABET[randomInt(ROOM_CODE_ALPHABET.length)];
}
return rooms.has(code) ? makeRoomCode() : code;
// The disk check covers rooms that exist on file but failed to restore —
// reusing such a code would append a new game into the orphaned file.
return rooms.has(code) || roomFileExists(code) ? makeRoomCode() : code;
}
export function roomCount(): number {
+6 -1
View File
@@ -3,7 +3,7 @@
// command. Because the engine is deterministic, replaying a file rebuilds
// the exact game state — server restarts lose nothing.
import { appendFileSync, mkdirSync, readdirSync, readFileSync } from "node:fs";
import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync } from "node:fs";
import { join } from "node:path";
export interface RoomMetaLine {
@@ -60,6 +60,11 @@ export function ensureDataDir(): void {
mkdirSync(DATA_DIR, { recursive: true });
}
/** A room file may exist even when the room failed to restore into memory. */
export function roomFileExists(roomId: string): boolean {
return existsSync(fileFor(roomId));
}
export function appendLine(roomId: string, line: RoomLine): void {
appendFileSync(fileFor(roomId), JSON.stringify(line) + "\n", "utf8");
}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB