quit the game cleanly on stop, so best times survive
Where they live: `HKCU\Software\Brightsoft\Minesweeper X` in the prefix's `user.reg`. `Time1/2/3` are beginner, intermediate and expert; `Name1/2/3` are the names, which is why the name you type sticks as the default. Nothing is stored beside the executable except the recordings. Why they were always empty: the game holds that whole key in memory and commits it ONLY on a clean exit. `stop()` sent SIGTERM. So every restart of this sidecar threw away every record set since the last one — six wins in one evening left a Best Times table reading 9999.99, which is what started this. `stop()` now drives Game > Exit and waits for the process to go before reaping. It runs FIRST, ahead of even reaping x11vnc, because it needs the display alive and it is racing PM2's clock. ── how it was pinned down ── Not by reading. `user.reg` grew by 848 bytes at the exact moment the game exited, which named the file. Writing `Time1="12.34"` / `Name1="Pastilhas"` into it by hand and restarting made the game display them, which proved the key and the load path. Then switching difficulty and stopping cleanly wrote Width/Height/Mines through from 30/16/99 to 8/8/10, which proved the write path carries in-memory state — beginner is 8x8 here, not the 9x9 I had assumed. ── the part this does NOT fix ── `pm2 restart` will usually still cut it short: PM2 SIGKILLs 1600ms after SIGTERM by default and a full stop takes about 5.6 seconds. That is not new — this sidecar's teardown has always exceeded that budget — but it does mean the fix only reliably applies to an explicit POST /stop. Raising it needs a `kill_timeout` on `Pm2App` in the platform's plugins/ecosystem.ts, which has no such field. Left alone rather than decided quietly; it is in the README. Also reverted: the 12.34 "Pastilhas" beginner record was my probe, not a game. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Officer-Session: de3ed4e6-f88a-429c-94e6-a760336ba83b
This commit is contained in:
@@ -428,6 +428,25 @@ export async function stop(): Promise<SessionStatus> {
|
||||
centring = null;
|
||||
}
|
||||
|
||||
// FIRST, before anything else is torn down. A clean exit is the only time the game writes its settings
|
||||
// key — best times included — so `stop()` used to discard every record set since the last start. Six
|
||||
// wins in one evening left a Best Times table reading 9999.99.
|
||||
//
|
||||
// First for two reasons. It needs the display and the game both alive, and it is racing a clock: PM2
|
||||
// sends SIGTERM and SIGKILLs 1600ms later by default, while a full stop here takes about 5.6 seconds.
|
||||
// Spending any of that budget on reaping x11vnc first is spending it on the part that does not matter.
|
||||
//
|
||||
// Even so, `pm2 restart` will usually cut this short — see the README. An explicit POST /stop always
|
||||
// completes, and that is the path the platform uses when a panel asks.
|
||||
//
|
||||
// Imported dynamically on purpose: `menu.ts` imports from this file, and a static import would close the
|
||||
// cycle. The dynamic form keeps the dependency one-way at module load, where it matters.
|
||||
if (display && alive(game)) {
|
||||
const { quitGame } = await import('./menu');
|
||||
const quit = await quitGame(display, () => alive(game));
|
||||
if (!quit) console.log('[minesweeper] the game did not quit cleanly; settings since the last start are lost');
|
||||
}
|
||||
|
||||
await reap(vnc, 'x11vnc');
|
||||
vnc = null;
|
||||
rmSync(VNC_SOCKET, { force: true });
|
||||
|
||||
Reference in New Issue
Block a user