feat: server-authoritative save — wait for server before game starts
Some checks failed
CI/CD — Build & Deploy / Build & Deploy (push) Failing after 18s

- Store starts in ready:false — no game actions until authority loaded
- useSaveSync signals serverLoaded (success, empty, or unreachable)
- GameSync orchestrates: logged in → wait server, guest → localStorage
- Home shows loading screen until ready
- localStorage = cache only, server = authority for logged-in users
This commit is contained in:
2026-03-24 14:30:53 +01:00
parent 3fc5e98069
commit 8ce54bfb03
4 changed files with 94 additions and 21 deletions

View File

@@ -1,7 +1,7 @@
// useSaveSync.ts — Auto-save game state to backend every 30s
// Cookie-based auth — credentials sent automatically
// Serveur = autorité. Cookie-based auth — credentials sent automatically.
import { useEffect, useRef, useCallback } from "react";
import { useEffect, useRef, useCallback, useState } from "react";
import { useAuth } from "../context/AuthContext";
import type { GameState } from "../core/economy";
@@ -37,18 +37,29 @@ export function useSaveSync({ getGameState, onLoad, playTimeSeconds }: SaveSyncO
const { user } = useAuth();
const lastSaveRef = useRef<string | null>(null);
const loadedRef = useRef(false);
const [serverLoaded, setServerLoaded] = useState(false);
// Load save on mount (once)
// Load save from server on mount (once, only if logged in)
useEffect(() => {
if (loadedRef.current || !user) return;
if (loadedRef.current || !user) {
// Not logged in → signal immediately
if (!user) setServerLoaded(true);
return;
}
loadedRef.current = true;
apiRequest("/save").then((data) => {
if (data?.gameState) {
onLoad(data.gameState);
lastSaveRef.current = data.lastSave;
console.info("[SaveSync] Loaded save from server");
console.info("[SaveSync] Loaded save from server — server is authority");
} else {
console.info("[SaveSync] No server save found — starting fresh");
}
setServerLoaded(true);
}).catch(() => {
console.warn("[SaveSync] Server unreachable — falling back to local");
setServerLoaded(true);
});
}, [onLoad, user]);
@@ -99,5 +110,5 @@ export function useSaveSync({ getGameState, onLoad, playTimeSeconds }: SaveSyncO
return () => window.removeEventListener("beforeunload", handleUnload);
}, [getGameState, playTimeSeconds, user]);
return { saveToServer, lastSave: lastSaveRef.current };
return { saveToServer, lastSave: lastSaveRef.current, serverLoaded };
}