import type { Inventory, LogDrop, TreeState, Vec2 } from './types'; import type { UpgradeId } from './upgrades'; const STORAGE_KEY = 'forest-save-v1'; export interface SaveData { version: 1; inventory: Inventory; upgradeLevels: Record; /** World state (character/trees/logs) is optional so older saves without it still load fine — * progress is restored either way, just with a freshly spawned world. */ character?: Vec2; trees?: TreeState[]; logDrops?: LogDrop[]; } function isValidSave(value: unknown): value is SaveData { if (!value || typeof value !== 'object') return false; const data = value as Partial; return ( data.version === 1 && typeof data.inventory === 'object' && data.inventory !== null && typeof data.inventory.logs === 'number' && typeof data.inventory.coins === 'number' && typeof data.upgradeLevels === 'object' && data.upgradeLevels !== null ); } /** Reads the saved game from localStorage, or null if there's none / it's corrupted. */ export function loadSave(): SaveData | null { try { const raw = localStorage.getItem(STORAGE_KEY); if (!raw) return null; const parsed: unknown = JSON.parse(raw); return isValidSave(parsed) ? parsed : null; } catch { // localStorage unavailable (private mode, disabled) or corrupted JSON — treat as no save. return null; } } /** Writes the save to localStorage. Best-effort: silently no-ops if storage is unavailable/full. */ export function writeSave(data: SaveData): void { try { localStorage.setItem(STORAGE_KEY, JSON.stringify(data)); } catch { // Ignore — e.g. private browsing mode or quota exceeded. } }