using System; using System.IO; using UnityEngine; namespace ProjectM.Simulation { /// /// Host-local persistence for the game save slice () — single slot, versioned JSON at /// Application.persistentDataPath/save_0.json, atomic writes (temp + File.Replace). Read by the /// menu (to offer "Continue" + stage a ) and the server SaveWriteSystem (autosave). /// JsonUtility keeps it dependency-free. Returns null on a missing / corrupt / version-mismatched file — /// never throws to callers (a bad save degrades to "New Game", it never crashes boot). /// public static class SaveService { static string FilePath => Path.Combine(Application.persistentDataPath, "save_0.json"); public static bool HasSave() => File.Exists(FilePath); public static SaveData Load() { try { if (!File.Exists(FilePath)) return null; var data = JsonUtility.FromJson(File.ReadAllText(FilePath)); // EB-1: additive floor [MinLoadableVersion, CurrentVersion] so OLD v2 saves still load (a missing HP // field 0-defaults and the restore guard maps 0 -> baked Max); v0/v1 garbage is still rejected. if (data == null || data.Version < SaveData.MinLoadableVersion || data.Version > SaveData.CurrentVersion) return null; data.Ledger ??= Array.Empty(); return data; } catch (Exception e) { Debug.LogWarning($"[SaveService] Load failed ({e.Message}); treating as no save."); return null; } } public static void Save(SaveData data) { if (data == null) return; data.Version = SaveData.CurrentVersion; try { var json = JsonUtility.ToJson(data, true); var tmp = FilePath + ".tmp"; File.WriteAllText(tmp, json); if (File.Exists(FilePath)) File.Replace(tmp, FilePath, null); else File.Move(tmp, FilePath); } catch (Exception e) { Debug.LogWarning($"[SaveService] Save failed: {e.Message}"); } } public static void Delete() { try { if (File.Exists(FilePath)) File.Delete(FilePath); } catch (Exception e) { Debug.LogWarning($"[SaveService] Delete failed: {e.Message}"); } } } }