From 4a75370de5f3de8097736c36c5c07cbfe18eee62 Mon Sep 17 00:00:00 2001 From: Eric Wagoner Date: Mon, 17 Aug 2026 18:07:33 -0400 Subject: [PATCH] Restored rooms wake their automatons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bot pump only ran when a command or join arrived, so a server restart landing mid-bot-turn left the restored room waiting forever for a human to poke it — room 928D sat exactly there, its automaton holding a perfectly answerable stack. Boot now kicks the pump for every restored still-running room, two seconds after restore. Co-Authored-By: Claude Fable 5 --- packages/server/src/index.ts | 6 ++++++ packages/server/src/rooms.ts | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index dcdc17c..79adef4 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -35,6 +35,7 @@ import { getRoom, joinRoom, loadPersistedRooms, + runningRooms, addAutomaton, addChat, driveOneAutomaton, @@ -70,6 +71,11 @@ const port = Number(process.env.PORT ?? 8787); // is not reachable from the internet. Dev default stays LAN-friendly. const host = process.env.HOST ?? "0.0.0.0"; loadPersistedRooms(); +// A restart can land mid-bot-turn: without a kick, a restored room whose +// current actor is an automaton waits forever for a human to poke it. +setTimeout(() => { + for (const room of runningRooms()) runBots(room); +}, 2000); // One process serves both the built client and the websocket, so production // needs only a TLS proxy in front (or nothing, on a LAN). diff --git a/packages/server/src/rooms.ts b/packages/server/src/rooms.ts index 5b56c1e..1f88fdb 100644 --- a/packages/server/src/rooms.ts +++ b/packages/server/src/rooms.ts @@ -91,6 +91,11 @@ export function roomCount(): number { return rooms.size; } +/** Every restored, still-running room — so boot can wake their bot pumps. */ +export function runningRooms(): Room[] { + return [...rooms.values()].filter((r) => r.state && r.state.phase === "playing"); +} + export function createRoom(hostId: PlayerId): { room: Room; token: string } { const token = randomBytes(16).toString("hex"); const room: Room = {