3.4 KiB
3.4 KiB
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)
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<PuzzleState>(data);
}
}
✅ NEW Pattern (Use this)
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<PuzzleState>(saveData);
}
}
}
Components Affected by This Decision
All components that currently use ISaveParticipant:
- PuzzleManager - puzzle state per level
- PlayerTouchController - player position/state per level
- FollowerController - follower state per level
- CardSystemManager - card collection per level
- SaveableInteractable - interactable state per level
- 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
- Before scene unloads:
LifecycleManager.BroadcastSaveRequested(sceneName)- All ManagedBehaviours in that scene get
OnSaveRequested()called - Each component saves its level-specific data via SaveLoadManager
- All ManagedBehaviours in that scene get
- SaveLoadManager.Save() called to persist all level data
- Scene unloads
- New scene loads
- After scene loads:
LifecycleManager.BroadcastRestoreRequested(sceneName)- All ManagedBehaviours in that scene get
OnRestoreRequested()called - Each component restores its level-specific data from SaveLoadManager
- All ManagedBehaviours in that scene get
End of Document