Files
AppleHillsProduction/docs/editor_lifecycle_complete_flow.md
2025-11-05 20:37:17 +01:00

7.6 KiB

Editor Lifecycle Bootstrap - Complete Flow Report

Date: November 5, 2025
Status: Fully Implemented and Save/Load Compliant


Complete Lifecycle Flow When Playing Directly From Editor

Production Flow (SceneManagerService.SwitchSceneAsync)

PHASE 1-7: Scene unloading and preparation
PHASE 8: BeginSceneLoad(sceneName)
PHASE 9: LoadSceneAsync(sceneName)
    └─> Unity loads scene
    └─> Components Awake() → Register with LifecycleManager
PHASE 10: BroadcastSceneReady(sceneName)
    └─> All components receive OnSceneReady()
PHASE 11: SaveLoadManager.RestoreSceneData()
    └─> BroadcastSceneRestoreRequested()
    └─> Components receive OnSceneRestoreRequested()
PHASE 12: Hide loading screen

Editor Flow (EditorLifecycleBootstrap) - NOW MATCHES PRODUCTION

1. User Presses Play in Scene "AppleHillsOverworld"
    ↓
2. PlayModeStateChange.EnteredPlayMode
    ↓
3. Unity: Scene already loaded, all Awake() calls
    └─> ManagedBehaviour.Awake()
    └─> LifecycleManager.Register()
    ↓
4. CustomBoot.Initialise() [RuntimeInitializeOnLoadMethod]
    └─> Creates LifecycleManager
    └─> Loads CustomBootSettings
    └─> Calls OnBootCompletionTriggered()
    ↓
5. LifecycleManager.OnBootCompletionTriggered()
    └─> BroadcastManagedAwake() ✅
    └─> All components receive OnManagedAwake() (priority ordered)
    └─> Sets isBootComplete = true
    └─> Sets Initialised = true
    ↓
6. EditorLifecycleBootstrap: Detects CustomBoot.Initialised == true
    ↓
7. EditorLifecycleBootstrap: Mimics SceneManagerService Phase 10
    └─> LifecycleManager.BroadcastSceneReady("AppleHillsOverworld") ✅
    └─> All components receive OnSceneReady() (priority ordered)
    ↓
8. EditorLifecycleBootstrap: Mimics SceneManagerService Phase 11
    └─> SaveLoadManager.RestoreSceneData() ✅
    └─> LifecycleManager.BroadcastSceneRestoreRequested()
    └─> Components receive OnSceneRestoreRequested() (if save system enabled)

Guaranteed Execution Order

All Lifecycle Hooks Called in Correct Order

  1. OnManagedAwake() - Priority ordered (0 → 1000)

    • Called once on boot completion
    • Components initialize core references
  2. OnSceneReady() - Priority ordered (0 → 1000)

    • Called after scene is fully loaded
    • Components find scene-specific references
  3. OnSceneRestoreRequested(data) - Priority ordered (0 → 1000)

    • Called after OnSceneReady
    • Components restore their saved state

Save/Load Lifecycle Compliance

Global Save/Load (Boot Time):

Boot → Load Save File → BroadcastGlobalRestoreRequested() → OnGlobalRestoreRequested()
  • Works in editor (happens during CustomBoot before EditorLifecycleBootstrap runs)

Scene Save/Load (Scene Transitions):

Scene Load → OnSceneReady() → RestoreSceneData() → BroadcastSceneRestoreRequested() → OnSceneRestoreRequested()
  • Works in production (SceneManagerService orchestrates)
  • NOW works in editor (EditorLifecycleBootstrap orchestrates)

Scene Save (Before Unload):

Scene Unload → SaveSceneData() → BroadcastSceneSaveRequested() → OnSceneSaveRequested()
  • Works in production (SceneManagerService orchestrates)
  • Works in editor for subsequent scene changes (SceneManagerService still handles transitions)

What Was Fixed

Before (Missing Scene Restore)

Editor Play → OnManagedAwake() ✅ → OnSceneReady() ✅ → ❌ NO RESTORE

Problem: Components would initialize but never restore their saved state.

After (Complete Lifecycle)

Editor Play → OnManagedAwake() ✅ → OnSceneReady() ✅ → OnSceneRestoreRequested() ✅

Solution: EditorLifecycleBootstrap now calls SaveLoadManager.RestoreSceneData() after BroadcastSceneReady().


Example Component Flow

SaveableInteractable in "AppleHillsOverworld"

public class SaveableInteractable : ManagedBehaviour
{
    public override bool AutoRegisterForSave => true;
    
    protected override void OnManagedAwake()
    {
        // Initialize core systems
        Debug.Log("SaveableInteractable: OnManagedAwake");
    }
    
    protected override void OnSceneReady()
    {
        // Find scene references
        Debug.Log("SaveableInteractable: OnSceneReady");
    }
    
    protected override void OnSceneRestoreRequested(string data)
    {
        // Restore saved state (e.g., collected status)
        Debug.Log($"SaveableInteractable: Restoring state: {data}");
        var state = JsonUtility.FromJson<InteractableState>(data);
        if (state.collected)
        {
            gameObject.SetActive(false);
        }
    }
}

When Playing Directly from Editor

Console Output:

[LifecycleManager] Broadcasting ManagedAwake to 15 components
SaveableInteractable: OnManagedAwake
[EditorLifecycleBootstrap] Triggering lifecycle for initial scene: AppleHillsOverworld
[LifecycleManager] Broadcasting SceneReady for scene: AppleHillsOverworld
SaveableInteractable: OnSceneReady
[EditorLifecycleBootstrap] Restoring scene data for: AppleHillsOverworld
[SaveLoadManager] Restoring scene-specific data...
[LifecycleManager] Restored scene data to 8 components
SaveableInteractable: Restoring state: {"collected":true,"position":{"x":10,"y":5}}

Result: Item correctly hidden because it was collected in save file


Files Modified

EditorLifecycleBootstrap.cs

Added:

  • using Core.SaveLoad;
  • using AppleHills.Core.Settings;
  • using Bootstrap;
  • SaveLoadManager.RestoreSceneData() call after BroadcastSceneReady()

Complete Flow:

  1. Wait for CustomBoot.Initialised
  2. Get active scene
  3. Call LifecycleManager.BroadcastSceneReady() ← Phase 10
  4. Call SaveLoadManager.RestoreSceneData() ← Phase 11 (NEW!)

Testing Verification

Test 1: Scene with Saved Data

  1. Play game normally (from Bootstrap)
  2. Collect an item
  3. Quit (auto-save triggers)
  4. Open scene directly in editor
  5. Press Play
  6. Expected: Item is hidden (restored from save)
  7. Result: Works correctly

Test 2: Fresh Scene (No Save Data)

  1. Delete save file
  2. Open scene in editor
  3. Press Play
  4. Expected: No errors, all items visible
  5. Result: Works correctly

Test 3: Save System Disabled

  1. Set DebugSettings.useSaveLoadSystem = false
  2. Open scene in editor
  3. Press Play
  4. Expected: No restore calls, but OnSceneReady still works
  5. Result: Works correctly

Complete Guarantees

Execution Order

  1. OnManagedAwake() before OnSceneReady()
  2. OnSceneReady() before OnSceneRestoreRequested()
  3. All hooks are priority-ordered

Save/Load Compliance

  1. Global restore happens on boot
  2. Scene restore happens after OnSceneReady
  3. Save system respects DebugSettings.useSaveLoadSystem

Production Parity

  1. Editor flow matches SceneManagerService flow
  2. Same phase ordering (Phase 10 → Phase 11)
  3. Same conditions and error handling

Safety

  1. Null checks for SaveLoadManager
  2. Exception handling for all broadcasts
  3. Timeout protection (5 seconds max wait)
  4. Bootstrap scene skip logic

Summary

The EditorLifecycleBootstrap now provides complete lifecycle orchestration when playing directly from the Unity Editor, including:

  • OnManagedAwake (boot initialization)
  • OnSceneReady (scene initialization)
  • OnSceneRestoreRequested (save/load restoration)

This matches the production flow from SceneManagerService exactly, ensuring consistent behavior whether you start from the Bootstrap scene or play directly from any gameplay scene.

The save/load lifecycle is now fully compliant in editor mode.