8.5 KiB
Editor Lifecycle Bootstrap - Implementation Summary
Date: November 5, 2025
Feature: Editor-Only Quality of Life Improvement
Status: ✅ Complete & Ready to Use
Quick Start
No setup required! Simply press Play in any scene and the lifecycle will work correctly.
What This Fixes
Before this feature:
Press Play in "AppleHillsOverworld" scene
↓
✅ OnManagedAwake() called
❌ OnSceneReady() NEVER called
After this feature:
Press Play in "AppleHillsOverworld" scene
↓
✅ OnManagedAwake() called
✅ OnSceneReady() called ← NOW WORKS!
Files Added
1. EditorLifecycleBootstrap.cs
Location: Assets/Editor/Lifecycle/EditorLifecycleBootstrap.cs
Purpose: Automatically triggers OnSceneReady when playing directly from editor
Type: Editor-only (zero runtime overhead)
Key Features:
- Automatic detection of play mode entry
- Waits for CustomBoot to complete
- Broadcasts OnSceneReady to all components in active scene
- Skips infrastructure scenes (Bootstrap/BootstrapScene)
- Safety timeout (5 seconds)
- Error handling and comprehensive logging
2. Documentation
Location: docs/editor_lifecycle_bootstrap.md
Content: Complete technical documentation and design rationale
How It Works
Sequence of Events
- Developer presses Play in Unity Editor (in any scene)
- PlayModeStateChange.EnteredPlayMode event fires
- EditorLifecycleBootstrap starts polling
- Wait for CustomBoot.Initialised to become true
- Get active scene from Unity SceneManager
- Call LifecycleManager.BroadcastSceneReady(sceneName)
- All components receive OnSceneReady() callback
Code Architecture
[InitializeOnLoad] // Runs in editor
public static class EditorLifecycleBootstrap
{
static EditorLifecycleBootstrap()
{
// Hook into Unity editor play mode events
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
}
private static void WaitForBootAndTriggerSceneReady()
{
// Poll until boot completes
if (!Bootstrap.CustomBoot.Initialised)
return;
// Get active scene
Scene activeScene = SceneManager.GetActiveScene();
// Trigger lifecycle
LifecycleManager.Instance.BroadcastSceneReady(activeScene.name);
}
}
Benefits
For Development
- ✅ Test any scene directly - no need to always start from Bootstrap
- ✅ Consistent behavior - same lifecycle whether starting from Bootstrap or scene
- ✅ Zero configuration - works automatically
- ✅ Better debugging - components initialize properly in editor
For Components
Components can now reliably use OnSceneReady for initialization:
public class FollowerController : ManagedBehaviour
{
protected override void OnSceneReady()
{
// This now works when playing directly from editor!
FindPlayerReference();
}
}
For Builds
- ✅ No runtime impact - editor-only code
- ✅ No performance cost - completely stripped from builds
- ✅ No behavior change - production flow unchanged
Expected Console Output
When pressing Play in "AppleHillsOverworld":
[CustomBoot] Boot initialized
[LifecycleManager] Instance created
[LifecycleManager] Registered PlayerController (Scene: AppleHillsOverworld)
[LifecycleManager] Registered FollowerController (Scene: AppleHillsOverworld)
[LifecycleManager] === Boot Completion Triggered ===
[LifecycleManager] Broadcasting ManagedAwake to 15 components
[EditorLifecycleBootstrap] Triggering OnSceneReady for initial scene: AppleHillsOverworld
[LifecycleManager] Broadcasting SceneReady for scene: AppleHillsOverworld
[FollowerController] Finding player reference (OnSceneReady)
The cyan-colored log clearly indicates when the editor bootstrap triggers.
Testing Checklist
✅ Test Case 1: Direct Play from Gameplay Scene
- Open any gameplay scene (e.g., AppleHillsOverworld)
- Press Play
- Check console for EditorLifecycleBootstrap log
- Verify components receive both OnManagedAwake and OnSceneReady
✅ Test Case 2: Play from Bootstrap Scene
- Open BootstrapScene
- Press Play
- Verify bootstrap log says "Skipping OnSceneReady for infrastructure scene"
- Verify normal scene transition flow works
✅ Test Case 3: Scene Transitions During Play
- Play from any scene
- Use LevelSwitch to change scenes
- Verify SceneManagerService handles transitions normally
- Verify EditorLifecycleBootstrap only triggers once at startup
✅ Test Case 4: Build Verification
- Make a build
- Verify EditorLifecycleBootstrap is NOT included
- Verify production bootstrap flow works normally
Compatibility
✅ Compatible With
- Existing lifecycle system
- SceneManagerService scene transitions
- DontDestroyOnLoad objects
- Multi-scene editing (processes active scene)
- All existing ManagedBehaviour components
❌ Not Needed For
- Production builds (editor-only)
- Bootstrap scene (infrastructure only)
- Scenes loaded via SceneManagerService (already handled)
Safety Features
Timeout Protection
- Maximum wait time: 5 seconds (300 frames at 60fps)
- Prevents infinite loops if boot fails
- Logs error message with diagnostic info
Error Handling
- Try-catch around BroadcastSceneReady
- Null checks for LifecycleManager
- Scene validation before broadcasting
Smart Scene Detection
- Skips infrastructure scenes (Bootstrap, BootstrapScene)
- Only processes gameplay scenes
- Validates scene is loaded before broadcasting
Performance
Editor Impact
- Minimal - Only runs during play mode entry
- Short-lived - Unsubscribes after first trigger
- Efficient - Simple polling mechanism
Runtime Impact
- Zero - Code is editor-only
- Not included in builds - Completely stripped
- No overhead - Production flow unchanged
Troubleshooting
Problem: OnSceneReady still not called
Check:
- Is LifecycleManager being created? (Check console for "[LifecycleManager] Instance created")
- Is CustomBoot completing? (Check for "Boot Completion Triggered")
- Is the scene name correct? (Not a bootstrap scene)
- Does the component inherit from ManagedBehaviour?
Solution: Enable LifecycleManager debug logging to see detailed lifecycle events.
Problem: EditorLifecycleBootstrap not running
Check:
- Is the file in Assets/Editor folder? (Editor-only location)
- Is the AppleHillsEditor assembly definition including AppleHillsScripts?
- Are there any compilation errors?
Solution: Check Unity console for errors. Verify assembly definition references.
Problem: Timeout error after 300 frames
Diagnostic: CustomBoot is failing to initialize properly.
Solution:
- Check CustomBoot logs for errors
- Verify CustomBootSettings are loaded
- Check Addressables are properly configured
Integration with Existing Systems
CustomBoot
- ✅ Waits for CustomBoot.Initialised flag
- ✅ Respects boot completion timing
- ✅ No modifications to CustomBoot required
LifecycleManager
- ✅ Uses existing BroadcastSceneReady method
- ✅ No modifications to LifecycleManager required
- ✅ Follows same pattern as SceneManagerService
SceneManagerService
- ✅ Doesn't interfere with scene transitions
- ✅ Only triggers for initial scene on editor play
- ✅ Production scene flow unchanged
Future Considerations
Potential Enhancements
- Developer Settings Integration - Toggle in settings menu
- Multi-Scene Support - Handle multiple loaded scenes
- Custom Delay - Option to delay trigger by frames
- Editor Window - Visual lifecycle state inspector
Known Limitations
- Only processes single active scene (not multi-scene setups)
- Assumes Bootstrap scene naming convention
- No support for domain reload disabled mode (edge case)
Summary
The EditorLifecycleBootstrap provides a seamless, zero-configuration quality of life improvement for developers. It ensures that playing scenes directly from the Unity Editor provides the same consistent lifecycle orchestration as the production scene flow.
Bottom Line: Press Play anywhere, lifecycle just works. ✅
Related Documentation
docs/editor_lifecycle_bootstrap.md- Full technical documentationdocs/lifecycle_technical_review.md- Lifecycle system overviewdocs/lifecycle_implementation_roadmap.md- Implementation detailsdocs/levelswitch_onsceneready_fix.md- Related timing issue fix