Resume: exiting a match keeps it alive instead of destroying it
Leaving the table (back button, browser/hardware back) no longer resets the game — it minimizes it and stays resumable: - game-store: add `paused` + minimize()/resume(). Single-player (AI) matches pause their local timers so nothing happens while away; live (server-run) matches keep streaming via the still-active subscription (the .NET GameRoom already runs the match to completion and re-broadcasts state on reconnect). - GameScreen: an unmount effect minimizes any in-progress match no matter how you leave; only a finished match (reward dismissed) tears down. - ResumeGameBar: floating "return to game" pill shown from any screen while a match is alive, or while a finished match still has an unseen reward. - page.tsx: after a full reload, re-enter live mode (minimized) when the server re-broadcasts state, and notify when a match you left finishes while away. Verified: tsc + next build clean; web image rebuilt and serving on :1500. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -25,11 +25,29 @@ export function GameScreen() {
|
||||
const [reward, setReward] = useState<RewardResult | null>(null);
|
||||
const submitted = useRef(false);
|
||||
|
||||
// Leaving the table (back button, browser/hardware back) keeps the match alive
|
||||
// & resumable — pause is handled by the unmount effect below. A finished match
|
||||
// is torn down instead.
|
||||
const exit = () => {
|
||||
if (useGameStore.getState().game.phase === "match-over") reset();
|
||||
go(returnTo);
|
||||
};
|
||||
|
||||
// Match truly finished (reward dismissed): tear the match down.
|
||||
const finish = () => {
|
||||
reset();
|
||||
go(returnTo);
|
||||
};
|
||||
|
||||
// Any way the table unmounts (exit button, hardware/browser back), keep an
|
||||
// in-progress match alive and resumable instead of letting it run unattended.
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
const gs = useGameStore.getState();
|
||||
if (gs.started && gs.game.phase !== "match-over") gs.minimize();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const notifyAchievements = (r: RewardResult) => {
|
||||
for (const a of r.newAchievements)
|
||||
pushNotification({
|
||||
@@ -85,7 +103,7 @@ export function GameScreen() {
|
||||
won={game.matchWinner === 0}
|
||||
onClose={() => {
|
||||
setReward(null);
|
||||
exit();
|
||||
finish();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user