Save/Load System
Persistence layer for game progress, profiles, and settings.
Key Classes
SaveLoadManager
Location: Assets/_Game/Scripts/Managers/SaveLoadManager.cs
Service: [Service(LoadScene = "BootstrapScene")] - Persistent across scenes
Core operations:
| Method | Purpose |
|---|---|
SaveGame() | Persist current state to disk |
HasSaveData() | Check if save exists |
GetSaveData() | Retrieve current save data |
DeleteSaveData() | Clear save data |
ProfileManager
Location: Assets/_Game/Scripts/Managers/ProfileManager.cs
Service: [Service(LoadScene = "BootstrapScene")] - Persistent
Multi-profile system:
public class ProfileManager : MonoBehaviour{ public int CurrentActiveProfileIndex; public RunDifficulty GameDifficulty;
public void CreateProfile(string name, RunDifficulty difficulty); public void SelectProfile(int index); public void DeleteProfile(int index);}GameSaveData
Location: Assets/_Game/Scripts/Data/GameSaveData.cs
Master save container:
[Serializable]public class GameSaveData{ // Progress public WorkDayProgress workDayProgress; public GameRunState currentGameState; public ShopPrepareSubstate currentSubstate;
// Player data public CharacterCustomizationData characterCustomization; public List<string> helperCatIds; public GamePlaythroughData playthroughData;
// Session data public GameSessionMetadata lastSessionMetadata; public GameLevelProgression levelProgression;
// Upgrades and shop public List<CakeUpgradeSaveEntry> cakeUpgrades; public List<string> offeredHelperCatIds; public List<string> offeredCakeUpgradeIds;
// Flags and history public PlayerGameFlags playerGameFlags; public List<StarCompletionRecord> starCompletionHistory;
// Meta public float totalPlaytimeSeconds; public string saveVersion;}GameProfileData
Profile with auto-backup saves:
[Serializable]public class GameProfileData{ public string profileName; public GameSaveData currentSave; public List<GameSaveData> autoBackups; public DateTime lastPlayedTime;}Save Triggers
Saves happen automatically at:
| Trigger | Location |
|---|---|
| Entering OverworldScene | OverworldSceneInitializer |
| Entering Shop state | GameRunOrchestrator |
| After level completion | GameRunManager |
| Application pause/quit | OverworldSceneInitializer / GameRunSceneInitializer |
Never during active gameplay - prevents save scumming.
Serialization
Uses Unity’s JsonUtility:
string json = JsonUtility.ToJson(saveData, prettyPrint: true);File.WriteAllText(savePath, json);Save location: Application.persistentDataPath
Restoration Flow
Mid-Run Save (shop/gameplay/lost)
1. ProfileManager loads save, determines currentGameState2. Creates GameRunStartConfig (mode=RestoreSave, saveData=...)3. SceneTransitionCoordinator.TransitionToGameRun(config)4. GameRunSceneInitializer.RestoreSave(): - Restore helper cats (via PersistentHelperCatManager) - Restore star completion history - Restore deck configuration - Restore game flags5. GameRunOrchestrator.RestoreSavedRunAfterSceneLoad()6. Transition to saved stateOverworld Save
1. ProfileManager loads save2. SceneTransitionCoordinator.TransitionToOverworld()3. OverworldSceneInitializer.RestorePersistentData(): - Restore helper cats - Restore star completion history - Restore game flags4. InitializeOverworld() activates hub worldValidation
private bool ValidateSaveData(GameSaveData saveData){ if (saveData == null) return false; if (saveData.workDayProgress == null) return false;
// Check restaurant still exists var restaurant = ProgressionDataManager.Instance .GetRestaurant(saveData.workDayProgress.CurrentRestaurantId);
return restaurant != null;}Playtime Tracking
Both GameRunSceneInitializer and OverworldSceneInitializer track session duration:
public void UpdatePlaytime(){ float sessionDuration = Time.time - sessionStartTime; saveData.totalPlaytimeSeconds += sessionDuration;}Called on:
- Application pause
- Application quit
- Before saves
Error Handling
- Invalid saves log warnings but don’t crash
- Missing data uses defaults
- Corrupted saves can be deleted via profile manager