# Save System Architecture **Project:** AppleHills **Date:** November 3, 2025 --- ## Critical Decision: All Save Data is Level-Specific **IMPORTANT:** In AppleHills, **ALL save data is level-specific**. There is no global persistent save data that carries across all levels. ### What This Means - ❌ **DO NOT use ISaveParticipant pattern** for new components - ✅ **DO use OnSaveRequested() / OnRestoreRequested() lifecycle hooks** instead - ✅ All save/load operations are tied to the current level/scene ### Migration Impact For existing components that implement ISaveParticipant: - **Remove ISaveParticipant interface** implementation - **Remove SaveLoadManager.RegisterParticipant()** calls - **Add OnSaveRequested()** override to save level-specific state - **Add OnRestoreRequested()** override to restore level-specific state - **Use SaveLoadManager's existing save/load system** within these hooks ### Examples #### ❌ OLD Pattern (Don't use) ```csharp public class PuzzleManager : MonoBehaviour, ISaveParticipant { void Awake() { BootCompletionService.RegisterInitAction(() => { SaveLoadManager.Instance.RegisterParticipant(this); }); } public string GetSaveId() => "PuzzleManager"; public string Save() { return JsonUtility.ToJson(puzzleState); } public void Restore(string data) { puzzleState = JsonUtility.FromJson(data); } } ``` #### ✅ NEW Pattern (Use this) ```csharp public class PuzzleManager : ManagedBehaviour { protected override int ManagedAwakePriority => 120; protected override void OnSaveRequested() { // Save level-specific puzzle state string saveData = JsonUtility.ToJson(puzzleState); SaveLoadManager.Instance.SaveLevelData("PuzzleManager", saveData); } protected override void OnRestoreRequested() { // Restore level-specific puzzle state string saveData = SaveLoadManager.Instance.LoadLevelData("PuzzleManager"); if (!string.IsNullOrEmpty(saveData)) { puzzleState = JsonUtility.FromJson(saveData); } } } ``` ### Components Affected by This Decision All components that currently use ISaveParticipant: 1. PuzzleManager - puzzle state per level 2. PlayerTouchController - player position/state per level 3. FollowerController - follower state per level 4. CardSystemManager - card collection per level 5. SaveableInteractable - interactable state per level 6. AppleMachine - apple machine state per level **All of these will be migrated to use OnSaveRequested/OnRestoreRequested instead of ISaveParticipant.** --- ## SaveLoadManager Integration The SaveLoadManager will continue to work as before, but components will interact with it through lifecycle hooks: ### Lifecycle Flow 1. **Before scene unloads:** `LifecycleManager.BroadcastSaveRequested(sceneName)` - All ManagedBehaviours in that scene get `OnSaveRequested()` called - Each component saves its level-specific data via SaveLoadManager 2. **SaveLoadManager.Save()** called to persist all level data 3. **Scene unloads** 4. **New scene loads** 5. **After scene loads:** `LifecycleManager.BroadcastRestoreRequested(sceneName)` - All ManagedBehaviours in that scene get `OnRestoreRequested()` called - Each component restores its level-specific data from SaveLoadManager --- **End of Document**