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

1437 lines
51 KiB
Markdown

# ManagedBehaviour Lifecycle System - Implementation Guide
## Overview
This document provides a step-by-step implementation plan for creating a custom lifecycle management system that extends MonoBehaviour with deterministic, ordered lifecycle hooks. The system integrates with existing bootstrap, scene management, save/load, and game state management infrastructure.
---
## Current System Analysis
### Existing Lifecycle Flow
1. **Unity Bootstrap Phase**
- `RuntimeInitializeOnLoadMethod(BeforeSplashScreen)``CustomBoot.Initialise()`
- Loads CustomBootSettings via Addressables
- BootstrapScene loads with initial GameObjects
2. **Unity Standard Lifecycle**
- `Awake()` - All MonoBehaviours (unordered within frame)
- `OnEnable()` - After Awake phase
- `Start()` - After OnEnable phase
- Game loop: `Update()`, `FixedUpdate()`, `LateUpdate()`
3. **Custom Bootstrap Integration**
- Components register with `BootCompletionService.RegisterInitAction()` in `Awake()`
- `CustomBoot` completes → triggers `BootCompletionService.HandleBootCompleted()`
- `BootCompletionService` executes registered actions (priority-sorted, 0-1000+)
- Components implement `InitializePostBoot()` methods
4. **Scene Lifecycle Integration**
- `SceneManagerService` manages additive scene loading/unloading
- Components subscribe to `SceneLoadCompleted` and `SceneUnloadStarted` events
- `SceneManagerService.SwitchSceneAsync()` handles scene transitions
5. **Save/Load System**
- `SaveLoadManager` maintains registry of `ISaveParticipant` components
- Components call `RegisterParticipant()` in post-boot initialization
- Components call `UnregisterParticipant()` in `OnDestroy()`
- State restoration happens after load or when new participants register
6. **Game State Management (GameManager)**
- Pause/Resume system with counter-based requests
- `IPausable` component registration (manual Subscribe/Unsubscribe)
- Settings initialization (ServiceLocator pattern)
- Developer settings integration
### Existing Patterns
- **Singleton Pattern**: All managers use `_instance` field with `Instance` property
- **Two-Phase Init**: `Awake()` + `InitializePostBoot()`
- **Priority-Based Boot**: Components specify boot priority (10-100+, lower = earlier)
- **Manual Event Management**: Subscribe in OnEnable/Start, unsubscribe in OnDestroy
- **Inheritance Example**: `InteractionActionBase` provides `protected virtual` lifecycle hooks
---
## Architecture Design
### Core Components
#### 1. LifecycleManager (Singleton)
Central orchestrator that:
- Maintains registries of all ManagedBehaviours (separate lists per lifecycle phase)
- Broadcasts lifecycle events in priority-sorted order
- Integrates with BootCompletionService, SceneManagerService, SaveLoadManager, GameManager
- Handles late registration and edge cases
- Provides optional debug/profiling tools
#### 2. ManagedBehaviour (Base Class)
Enhanced MonoBehaviour providing:
- Virtual lifecycle hooks (opt-in via override)
- Automatic registration/unregistration with LifecycleManager
- Priority/ordering support via properties
- Built-in managed event subscription system (auto-cleanup)
- Optional auto-integration with SaveLoadManager and GameManager
#### 3. ManagedEvent System
Helper system for automatic event subscription cleanup:
- Stores event subscriptions internally
- Auto-unsubscribes all events on destruction
- Prevents memory leaks and manual cleanup
---
## Lifecycle Phases
### Complete Lifecycle Flow
```
┌─────────────────────────────────────────────────────────────┐
│ PHASE 1: UNITY ENGINE BOOTSTRAP │
│ - RuntimeInitializeOnLoadMethod (CustomBoot.Initialise) │
│ - BootstrapScene loads │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ PHASE 2: UNITY STANDARD LIFECYCLE │
│ - Unity Awake() [all MonoBehaviours] │
│ └→ ManagedBehaviour.Awake() auto-registers with Manager │
│ - Unity OnEnable() │
│ - Unity Start() │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ PHASE 3: MANAGED AWAKE (Deterministic) │
│ - LifecycleManager.BroadcastManagedAwake() │
│ - Calls OnManagedAwake() in priority order (0→1000) │
│ - Singleton initialization, component setup │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ PHASE 4: BOOT COMPLETION │
│ - CustomBoot completes │
│ - BootCompletionService.HandleBootCompleted() │
│ - LifecycleManager.BroadcastBootComplete() │
│ - Calls OnBootComplete() in priority order │
│ - Settings loaded, services initialized │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ PHASE 5: SCENE READY │
│ - SceneManagerService finishes loading │
│ - LifecycleManager.BroadcastSceneReady() │
│ - Calls OnSceneReady() for all active ManagedBehaviours │
│ - Scene-specific initialization │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ PHASE 6: GAME LOOP (Runtime) │
│ - Unity Update/FixedUpdate/LateUpdate │
│ - Optional: OnManagedUpdate() (priority-ordered) │
│ - Optional: OnManagedFixedUpdate() (priority-ordered) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ PHASE 7: PAUSE/RESUME (State Change) │
│ - GameManager.RequestPause() / ReleasePause() │
│ - LifecycleManager.BroadcastPause/Resume() │
│ - Calls OnPaused() / OnResumed() for all active │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ PHASE 8: SCENE UNLOADING (Transition) │
│ - SceneManagerService.SwitchSceneAsync() starts │
│ - LifecycleManager.BroadcastSceneUnloading() │
│ - Calls OnSceneUnloading() for scene-specific components │
│ - Cleanup before scene unload │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ PHASE 9: DESTRUCTION │
│ - Unity OnDisable() │
│ - Unity OnDestroy() │
│ └→ ManagedBehaviour.OnDestroy() auto-unregisters │
│ - LifecycleManager.BroadcastManagedDestroy() │
│ - Calls OnManagedDestroy() in reverse priority order │
│ - Auto-cleanup of managed events │
└─────────────────────────────────────────────────────────────┘
```
### Lifecycle Hook Reference
| Hook Name | Priority Order | When Called | Use Case |
|-----------|----------------|-------------|----------|
| `OnManagedAwake()` | Low→High (0→∞) | After Unity Awake, before Start | Deterministic initialization |
| `OnBootComplete()` | Low→High (0→∞) | After CustomBoot completes | Post-boot initialization (replaces InitializePostBoot) |
| `OnSceneReady()` | Low→High (0→∞) | After scene fully loaded | Scene-specific setup |
| `OnManagedUpdate()` | Low→High (0→∞) | Every frame (optional) | Ordered per-frame logic |
| `OnManagedFixedUpdate()` | Low→High (0→∞) | Every physics frame (optional) | Ordered physics logic |
| `OnPaused()` | Low→High (0→∞) | When game pauses | Pause state handling |
| `OnResumed()` | Low→High (0→∞) | When game resumes | Resume state handling |
| `OnSceneUnloading()` | High→Low (∞→0) | Before scene unloads | Scene cleanup |
| `OnManagedDestroy()` | High→Low (∞→0) | Before Unity OnDestroy | Guaranteed cleanup |
---
## Implementation Steps
### STEP 1: Create Core Enums and Interfaces
**File**: `Assets/Scripts/Core/Lifecycle/LifecycleEnums.cs`
**Actions**:
1. Create namespace `Core.Lifecycle`
2. Define `LifecyclePhase` enum with all phases
3. Define `LifecycleFlags` enum for component opt-in (bitflags)
4. Add XML documentation for each value
**Key Details**:
- LifecyclePhase: ManagedAwake, BootComplete, SceneReady, Update, FixedUpdate, Paused, Resumed, SceneUnloading, ManagedDestroy
- LifecycleFlags: None, ManagedAwake, BootComplete, SceneReady, ManagedUpdate, ManagedFixedUpdate, Pause, SceneUnloading, ManagedDestroy, All (bitwise OR of all)
---
### STEP 2: Create ManagedEvent System
**File**: `Assets/Scripts/Core/Lifecycle/ManagedEventSubscription.cs`
**Actions**:
1. Create internal struct `ManagedEventSubscription` to store event delegate and target
2. Create class `ManagedEventManager` with:
- List of subscriptions per ManagedBehaviour
- `RegisterEvent<T>(target, action)` method
- `UnregisterAllEvents()` method that invokes `-=` on all stored subscriptions
3. Handle both `Action` and generic `Action<T>` delegates
4. Use reflection to dynamically unsubscribe
**Key Details**:
- Store event info as: object target (event owner), Delegate handler, string eventName
- Support common Unity event patterns (Action, Action\<T\>, UnityEvent, etc.)
- Provide safe null checks before unsubscribing
---
### STEP 3: Create ManagedBehaviour Base Class (Structure)
**File**: `Assets/Scripts/Core/Lifecycle/ManagedBehaviour.cs`
**Actions**:
1. Create abstract class `ManagedBehaviour : MonoBehaviour`
2. Add virtual properties for priorities:
- `ManagedAwakePriority` (default 100)
- `BootCompletePriority` (default 100)
- `SceneReadyPriority` (default 100)
- `UpdatePriority` (default 100)
- `DestroyPriority` (default 100)
3. Add property `ActiveLifecyclePhases` (returns LifecycleFlags, default None)
4. Add property `AutoRegisterSaveParticipant` (default false)
5. Add property `AutoRegisterPausable` (default false)
6. Add property `IsPersistent` (default false) - survives scene changes
7. Add private field `ManagedEventManager _eventManager`
8. Add private bool `_isRegistered` to track registration state
**Key Details**:
- All priority properties are virtual so subclasses can override
- ActiveLifecyclePhases determines which hooks are called (opt-in)
- IsPersistent flag controls whether component persists across scenes
---
### STEP 4: Implement ManagedBehaviour Lifecycle Hooks (Virtual Methods)
**File**: `Assets/Scripts/Core/Lifecycle/ManagedBehaviour.cs` (continued)
**Actions**:
1. Add virtual protected methods (empty by default):
- `OnManagedAwake()`
- `OnBootComplete()`
- `OnSceneReady()`
- `OnManagedUpdate()`
- `OnManagedFixedUpdate()`
- `OnPaused()`
- `OnResumed()`
- `OnSceneUnloading()`
- `OnManagedDestroy()`
2. Add XML documentation for each method
3. Add protected helper methods:
- `RegisterManagedEvent<T>(target, action)` - wraps _eventManager
- `IsLifecyclePhaseActive(LifecyclePhase)` - checks flags
**Key Details**:
- All hooks are `protected virtual void` (no return value)
- Empty implementations allow opt-in override pattern
- Use `[Conditional("UNITY_EDITOR")]` attribute for debug-only hooks if needed
---
### STEP 5: Implement ManagedBehaviour Unity Integration
**File**: `Assets/Scripts/Core/Lifecycle/ManagedBehaviour.cs` (continued)
**Actions**:
1. Implement `protected virtual void Awake()`:
- Initialize _eventManager
- Register with LifecycleManager (call `LifecycleManager.Instance.Register(this)`)
- Set _isRegistered = true
2. Implement `protected virtual void OnDestroy()`:
- Unregister from LifecycleManager (call `LifecycleManager.Instance.Unregister(this)`)
- Call _eventManager.UnregisterAllEvents()
- Auto-unregister from SaveLoadManager and GameManager if applicable
- Set _isRegistered = false
3. Make both methods call base implementation warning (for subclasses)
**Key Details**:
- Use null checks for LifecycleManager.Instance (may not exist during shutdown)
- Provide clear error logging if registration fails
- Support scenario where subclass overrides Awake/OnDestroy (must call base)
---
### STEP 6: Create LifecycleManager (Structure)
**File**: `Assets/Scripts/Core/Lifecycle/LifecycleManager.cs`
**Actions**:
1. Create class `LifecycleManager : MonoBehaviour`
2. Implement singleton pattern (private static _instance, public static Instance)
3. Add separate `List<ManagedBehaviour>` for each lifecycle phase:
- `_managedAwakeList`
- `_bootCompleteList`
- `_sceneReadyList`
- `_updateList`
- `_fixedUpdateList`
- `_pauseList`
- `_sceneUnloadingList`
- `_destroyList`
4. Add Dictionary<ManagedBehaviour, int> for tracking which lists each component is in (bitmask)
5. Add bool flags: `_isBootComplete`, `_isSceneReady`, `_isPaused`
6. Add queue for late registrations: `Queue<ManagedBehaviour> _pendingRegistrations`
**Key Details**:
- Each list must be kept sorted by priority
- Use SortedList or List with manual sorting after registration
- Dictionary tracks which phases each component participates in
---
### STEP 7: Implement LifecycleManager Registration System
**File**: `Assets/Scripts/Core/Lifecycle/LifecycleManager.cs` (continued)
**Actions**:
1. Implement `public void Register(ManagedBehaviour component)`:
- Check component.ActiveLifecyclePhases flags
- Add to appropriate lists based on flags
- Insert in priority-sorted position
- Handle auto-registration with SaveLoadManager if component is ISaveParticipant && AutoRegisterSaveParticipant
- Handle auto-registration with GameManager if component is IPausable && AutoRegisterPausable
- If boot already complete and component has BootComplete flag, immediately call OnBootComplete
- If scene already ready and component has SceneReady flag, immediately call OnSceneReady
2. Implement `public void Unregister(ManagedBehaviour component)`:
- Remove from all lists
- Handle auto-unregistration from SaveLoadManager and GameManager
**Key Details**:
- Use binary search for insertion point (lists sorted by priority)
- Handle edge case: registration during broadcast (queue and process later)
- Validate component is not null and has valid priorities
---
### STEP 8: Implement LifecycleManager Broadcast System
**File**: `Assets/Scripts/Core/Lifecycle/LifecycleManager.cs` (continued)
**Actions**:
1. Implement broadcast methods for each phase:
- `BroadcastManagedAwake()`
- `BroadcastBootComplete()`
- `BroadcastSceneReady()`
- `BroadcastPause()`
- `BroadcastResume()`
- `BroadcastSceneUnloading()`
- `BroadcastManagedDestroy()`
2. Each method iterates through corresponding list and calls hook
3. Add try-catch around each call with error logging
4. Process pending registrations after broadcast completes
5. Set state flags (_isBootComplete, _isSceneReady, _isPaused)
**Key Details**:
- Iterate forward for normal phases (low→high priority)
- Iterate backward for cleanup phases (SceneUnloading, ManagedDestroy)
- Use `for` loop with index (not foreach) to handle list modifications
- Log phase start/end with timing info (use Stopwatch)
---
### STEP 9: Implement LifecycleManager Update Handlers
**File**: `Assets/Scripts/Core/Lifecycle/LifecycleManager.cs` (continued)
**Actions**:
1. Implement `void Update()`:
- Check if _updateList is empty (skip if so)
- Iterate _updateList and call OnManagedUpdate() on each
- Add try-catch with error logging
2. Implement `void FixedUpdate()`:
- Check if _fixedUpdateList is empty (skip if so)
- Iterate _fixedUpdateList and call OnManagedFixedUpdate() on each
- Add try-catch with error logging
3. Add optimization: disable Update/FixedUpdate when lists are empty
**Key Details**:
- Use `enabled = false` when no components registered for updates
- Re-enable when first component registers
- Consider pooling/caching for performance
---
### STEP 10: Integrate LifecycleManager with Bootstrap
**File**: `Assets/Scripts/Core/Lifecycle/LifecycleManager.cs` (continued)
**Actions**:
1. In `Awake()`:
- Set singleton instance
- Subscribe to BootCompletionService.OnBootComplete
- Set up initial state
2. Implement handler for `BootCompletionService.OnBootComplete`:
- Set _isBootComplete = true
- Call BroadcastManagedAwake() first (if not already called)
- Then call BroadcastBootComplete()
3. Add `Start()` method:
- Call BroadcastManagedAwake() if boot not complete yet (fallback)
**Key Details**:
- LifecycleManager should exist in BootstrapScene (persistent)
- Must handle both editor and runtime initialization
- Consider RuntimeInitializeOnLoadMethod for creation if needed
---
### STEP 11: Integrate LifecycleManager with SceneManagerService
**File**: `Assets/Scripts/Core/Lifecycle/LifecycleManager.cs` (continued)
**Actions**:
1. In post-boot initialization:
- Subscribe to SceneManagerService.Instance.SceneLoadCompleted
- Subscribe to SceneManagerService.Instance.SceneUnloadStarted
2. Implement handler for `SceneLoadCompleted`:
- Set _isSceneReady = true
- Call BroadcastSceneReady()
- Handle scene-specific vs persistent components (check IsPersistent flag)
3. Implement handler for `SceneUnloadStarted`:
- Set _isSceneReady = false
- Call BroadcastSceneUnloading()
- Only call on scene-specific components (IsPersistent = false)
4. In `OnDestroy()`:
- Unsubscribe from all events
**Key Details**:
- Track which scene each component belongs to (use component.gameObject.scene)
- Only broadcast SceneReady/Unloading to components in affected scene
- Persistent components (BootstrapScene) should not receive scene lifecycle events
---
### STEP 12: Integrate LifecycleManager with GameManager (Pause System)
**File**: `Assets/Scripts/Core/Lifecycle/LifecycleManager.cs` (continued)
**Actions**:
1. In post-boot initialization:
- Subscribe to GameManager.Instance.OnGamePaused
- Subscribe to GameManager.Instance.OnGameResumed
2. Implement handler for `OnGamePaused`:
- Set _isPaused = true
- Call BroadcastPause()
3. Implement handler for `OnGameResumed`:
- Set _isPaused = false
- Call BroadcastResume()
**Key Details**:
- Components can opt-in to pause events via ActiveLifecyclePhases flags
- BroadcastPause/Resume iterates _pauseList only
- Late-registered components get immediate pause state if game is paused
---
### STEP 13: Add Debug and Profiling Tools
**File**: `Assets/Scripts/Core/Lifecycle/LifecycleManager.cs` (continued)
**Actions**:
1. Add `[SerializeField] private bool enableDebugLogging = false`
2. Add `[SerializeField] private bool enableProfilingMarkers = true`
3. Create LogDebugMessage() helper that checks flag
4. Add Unity Profiler markers around each broadcast phase
5. Implement GetRegisteredComponents() method for inspector/debugging
6. Add OnGUI() debug overlay showing:
- Registered component counts per phase
- Current lifecycle state flags
- Last broadcast timings
**Key Details**:
- Use `UnityEngine.Profiling.ProfilerMarker` for zero-cost profiling in builds
- Debug overlay only active in editor or development builds
- Consider creating custom inspector for LifecycleManager
---
### STEP 14: Create LifecycleManager Prefab
**File**: `Assets/Prefabs/Core/LifecycleManager.prefab`
**Actions**:
1. Create empty GameObject named "LifecycleManager"
2. Add LifecycleManager component
3. Configure default settings (debug logging off, profiling on)
4. Save as prefab
5. Add to BootstrapScene if not already present
6. Verify it persists across scenes (should be in BootstrapScene which is additive)
**Key Details**:
- Only one instance should exist (singleton)
- Should be in BootstrapScene, not in gameplay scenes
- Consider adding validation script to prevent duplicates
---
### STEP 15: Update Bootstrap Integration
**File**: `Assets/Scripts/Bootstrap/BootCompletionService.cs`
**Actions**:
1. In `HandleBootCompleted()` method, add:
- Before executing initialization actions, notify LifecycleManager
- Call `LifecycleManager.Instance?.OnBootCompletionStarting()` (new method)
2. After initialization actions complete:
- Call existing `OnBootComplete?.Invoke()`
- LifecycleManager handles this via event subscription
**File**: `Assets/Scripts/Bootstrap/CustomBoot.cs`
**Actions**:
1. Verify LifecycleManager exists before CustomBoot completes
2. Add fallback: if LifecycleManager doesn't exist, log warning
**Key Details**:
- BootCompletionService remains authoritative for boot completion
- LifecycleManager observes and broadcasts to ManagedBehaviours
- Maintain backward compatibility with existing RegisterInitAction pattern
---
### STEP 16: Extend SaveLoadManager Integration
**File**: `Assets/Scripts/Core/SaveLoad/SaveLoadManager.cs`
**Actions**:
1. Add public method `AutoRegisterParticipant(ISaveParticipant participant, ManagedBehaviour owner)`:
- Same as RegisterParticipant but stores reference to owner ManagedBehaviour
- Allows automatic unregistration when owner is destroyed
2. Add public method `AutoUnregisterParticipant(ManagedBehaviour owner)`:
- Looks up participant by owner reference and unregisters
3. Store Dictionary<ManagedBehaviour, string> to track auto-registrations
**File**: `Assets/Scripts/Core/Lifecycle/ManagedBehaviour.cs`
**Actions**:
1. In Awake() registration:
- Check if `this is ISaveParticipant` and `AutoRegisterSaveParticipant == true`
- If yes, call SaveLoadManager.Instance.AutoRegisterParticipant(this as ISaveParticipant, this)
2. In OnDestroy() cleanup:
- Call SaveLoadManager.Instance.AutoUnregisterParticipant(this)
**Key Details**:
- Only auto-register after boot completes (SaveLoadManager must be initialized)
- Handle null checks (SaveLoadManager may not exist in editor)
- Log when auto-registration occurs (debug mode)
---
### STEP 17: Extend GameManager Pausable Integration
**File**: `Assets/Scripts/Core/GameManager.cs`
**Actions**:
1. Add public method `AutoRegisterPausable(IPausable component, ManagedBehaviour owner)`:
- Same as RegisterPausableComponent but stores owner reference
2. Add public method `AutoUnregisterPausable(ManagedBehaviour owner)`:
- Looks up pausable by owner and unregisters
3. Store Dictionary<ManagedBehaviour, IPausable> to track auto-registrations
**File**: `Assets/Scripts/Core/Lifecycle/ManagedBehaviour.cs`
**Actions**:
1. In post-boot registration (called by LifecycleManager):
- Check if `this is IPausable` and `AutoRegisterPausable == true`
- If yes, call GameManager.Instance.AutoRegisterPausable(this as IPausable, this)
2. In OnDestroy() cleanup:
- Call GameManager.Instance.AutoUnregisterPausable(this)
**Key Details**:
- Wait until boot completes before registering with GameManager
- Handle case where component implements both ISaveParticipant and IPausable
- Verify GameManager exists before calling
---
### STEP 18: Create Migration Helper Attribute
**File**: `Assets/Scripts/Core/Lifecycle/RequiresManagedBehaviourAttribute.cs`
**Actions**:
1. Create custom attribute `[RequiresManagedBehaviour]`
2. Can be applied to classes that should be converted to ManagedBehaviour
3. Create custom inspector that shows warning if class derives from MonoBehaviour instead
**File**: `Assets/Editor/ManagedBehaviourValidation.cs`
**Actions**:
1. Create editor script that scans project for components with attribute
2. Shows list of components needing migration
3. Provides "Convert to ManagedBehaviour" button for each
4. Automatic string replacement in source files
**Key Details**:
- Editor-only functionality (Assets/Editor folder)
- Use AssetDatabase to find and modify scripts
- Show before/after preview before conversion
---
### STEP 19: Create Example ManagedBehaviour Implementations
**File**: `Assets/Scripts/Core/Lifecycle/Examples/ExampleManagedSingleton.cs`
**Actions**:
1. Create example showing singleton pattern with ManagedBehaviour
2. Demonstrate priority usage
3. Show lifecycle hook overrides
4. Include code comments explaining each part
**File**: `Assets/Scripts/Core/Lifecycle/Examples/ExampleManagedComponent.cs`
**Actions**:
1. Create example showing scene-specific component
2. Demonstrate managed event subscription
3. Show auto-save participant integration
4. Show auto-pausable integration
**File**: `Assets/Scripts/Core/Lifecycle/Examples/ExampleManagedManager.cs`
**Actions**:
1. Create example showing persistent manager
2. Demonstrate all lifecycle phases
3. Show priority ordering
4. Include performance considerations
**Key Details**:
- Well-commented code for reference
- Cover common use cases (singleton, scene component, manager)
- Include unit tests if applicable
---
### STEP 20: Migrate Core Systems (Phase 1)
**Priority Order**: GameManager → SceneManagerService → SaveLoadManager → InputManager
**File**: `Assets/Scripts/Core/GameManager.cs`
**Actions**:
1. Change class declaration: `public class GameManager : ManagedBehaviour`
2. Override properties:
- `protected override int ManagedAwakePriority => 10;` (very early)
- `protected override int BootCompletePriority => 10;`
3. Remove `BootCompletionService.RegisterInitAction(InitializePostBoot)` from Awake
4. Rename `InitializePostBoot()` to `protected override void OnBootComplete()`
5. Move Awake logic to `protected override void OnManagedAwake()`
6. Add `protected override LifecycleFlags ActiveLifecyclePhases => LifecycleFlags.ManagedAwake | LifecycleFlags.BootComplete;`
7. Keep existing pause/resume system (don't double-integrate)
8. Remove manual singleton setup (handled by base class)
9. Test thoroughly
**Key Details**:
- GameManager initializes early (priority 10)
- Keep existing functionality intact
- Verify settings loading still works
- Ensure pause system integration works
---
### STEP 21: Migrate Core Systems (Phase 2)
**Target**: SceneManagerService, SaveLoadManager, InputManager, ItemManager
**For Each File**:
1. Change base class to ManagedBehaviour
2. Set appropriate priorities (15-30 range)
3. Move InitializePostBoot → OnBootComplete
4. Remove manual BootCompletionService registration
5. Add ActiveLifecyclePhases flags
6. Test scene transitions, save/load, input handling
**Priorities**:
- SceneManagerService: 15 (after GameManager)
- SaveLoadManager: 20 (after SceneManagerService)
- InputManager: 25 (after SaveLoadManager)
- ItemManager: 30 (general manager)
**Key Details**:
- Verify event subscriptions still work
- Check scene loading/unloading
- Validate save/load system
- Test input handling in different modes
---
### STEP 22: Migrate UI Systems
**Target**: UIPageController, LoadingScreenController, PauseMenu, CardSystemUI components
**For Each File**:
1. Change base class to ManagedBehaviour
2. Set priority 50-100 (standard range)
3. Convert InitializePostBoot → OnBootComplete
4. Use RegisterManagedEvent for event subscriptions
5. Add OnSceneReady override if needed for scene-specific UI
6. Test UI navigation, loading screens, pause menu
**Key Details**:
- UI generally has lower priority than managers
- Scene-specific UI should override OnSceneReady
- Use AutoRegisterSaveParticipant for UI with state
---
### STEP 23: Migrate Gameplay Systems
**Target**: PuzzleManager, DivingGameManager, CinematicsManager, CardSystemManager
**For Each File**:
1. Change base class to ManagedBehaviour
2. Set priority 100-200 (gameplay systems)
3. Convert InitializePostBoot → OnBootComplete
4. Use OnSceneReady for scene-specific setup
5. Use OnSceneUnloading for cleanup
6. Consider AutoRegisterSaveParticipant
7. Test gameplay features
**Key Details**:
- Scene-specific managers should handle OnSceneReady/Unloading
- Persistent managers (like CardSystemManager) set IsPersistent = true
- Verify minigame transitions work correctly
---
### STEP 24: Migrate Interaction Systems
**Target**: Interactable, InteractionActionBase, DialogueComponent
**File**: `Assets/Scripts/Interactions/InteractionActionBase.cs`
**Actions**:
1. Change base class from MonoBehaviour to ManagedBehaviour
2. Change `protected virtual void Awake()` to `protected override void OnManagedAwake()`
3. Keep OnEnable/OnDisable as-is (Unity lifecycle needed for enable/disable)
4. Consider using RegisterManagedEvent for parentInteractable events
**Key Details**:
- InteractionActionBase is itself a base class (virtual methods remain)
- Subclasses inherit ManagedBehaviour capabilities
- Test interaction flow thoroughly
---
### STEP 25: Migrate Player and Movement Systems
**Target**: PlayerTouchController, FollowerController
**For Each File**:
1. Change base class to ManagedBehaviour
2. Keep Update() as Unity Update (movement needs every frame)
3. Use OnBootComplete for post-boot initialization
4. Use RegisterManagedEvent for InputManager event subscriptions
5. Test movement, pathfinding, interactions
**Key Details**:
- Performance-critical components should use Unity Update, not OnManagedUpdate
- Only use ManagedBehaviour for initialization/cleanup benefits
- Verify A* pathfinding still works
---
### STEP 26: Update InteractionActionBase Pattern
**File**: `Assets/Scripts/Interactions/InteractionActionBase.cs`
**Actions**:
1. Since this is a base class, ensure subclasses can override lifecycle hooks
2. Add example subclass showing proper override chain
3. Document pattern for action components
**Pattern**:
```csharp
public class MyAction : InteractionActionBase
{
protected override void OnManagedAwake()
{
base.OnManagedAwake(); // Calls parent registration
// Custom initialization
}
}
```
**Key Details**:
- Base.OnManagedAwake() must be called in subclasses
- Provide clear documentation for this pattern
- Consider sealed methods if override not intended
---
### STEP 27: Create Validation and Testing Suite
**File**: `Assets/Editor/Tests/LifecycleSystemTests.cs`
**Actions**:
1. Create Unity Test Runner tests for:
- Registration/unregistration
- Priority ordering
- Lifecycle hook execution order
- Event subscription cleanup
- Save/load integration
- Pause system integration
- Scene transition handling
2. Create test ManagedBehaviour subclasses
3. Mock managers for isolated testing
**File**: `Assets/Scripts/Core/Lifecycle/LifecycleValidator.cs`
**Actions**:
1. Create runtime validator that checks:
- No duplicate registrations
- All ManagedBehaviours properly registered
- Priority conflicts (warnings)
- Missing overrides (if flags set but no override)
2. Add menu item "Tools/Lifecycle/Validate Scene"
**Key Details**:
- Tests should cover all lifecycle phases
- Include edge cases (late registration, scene transitions)
- Performance benchmarks for Update broadcasts
---
### STEP 28: Create Documentation
**File**: `docs/ManagedBehaviour_Usage_Guide.md`
**Content**:
1. Quick start guide
2. Common patterns and examples
3. Lifecycle phase reference
4. Priority guidelines
5. Performance considerations
6. Migration guide from MonoBehaviour
7. Troubleshooting section
**File**: `docs/ManagedBehaviour_API_Reference.md`
**Content**:
1. Complete API documentation
2. All virtual methods with parameters
3. All properties and their defaults
4. Integration points (SaveLoadManager, GameManager)
5. Best practices
**File**: `docs/ManagedBehaviour_Architecture.md`
**Content**:
1. System architecture diagram
2. Component interaction flows
3. Performance characteristics
4. Design decisions and rationale
5. Future extension points
---
### STEP 29: Performance Optimization Pass
**File**: `Assets/Scripts/Core/Lifecycle/LifecycleManager.cs`
**Actions**:
1. Profile Update/FixedUpdate broadcasts
2. Consider using Unity Jobs for parallel execution (if applicable)
3. Add object pooling for event subscriptions
4. Cache frequently accessed lists
5. Add compile-time flags for debug features
6. Optimize sort algorithms for registration
7. Consider lazy initialization for empty lists
**Targets**:
- Registration: < 0.1ms per component
- Update broadcast: < 0.5ms for 100 components
- Memory overhead: < 100 bytes per ManagedBehaviour
**Key Details**:
- Use Unity Profiler to identify bottlenecks
- Compare against baseline (vanilla MonoBehaviour)
- Optimize hot paths (Update broadcasts)
---
### STEP 30: Create Editor Tools
**File**: `Assets/Editor/LifecycleManagerInspector.cs`
**Actions**:
1. Custom inspector for LifecycleManager
2. Show registered components grouped by phase
3. Display component priorities
4. Show current state flags
5. Add "Force Broadcast" buttons for testing
6. Real-time component count display
**File**: `Assets/Editor/ManagedBehaviourInspector.cs`
**Actions**:
1. Custom inspector for ManagedBehaviour
2. Show active lifecycle phases (visual flags)
3. Display current registration status
4. Show priority values
5. List registered managed events
6. Add "Test Lifecycle" button
**File**: `Assets/Editor/LifecycleDebugWindow.cs`
**Actions**:
1. Custom editor window "Window/Lifecycle/Debug"
2. Real-time lifecycle event log
3. Component hierarchy view
4. Priority visualization
5. Performance metrics
6. Event subscription viewer
---
### STEP 31: Final Integration Testing
**Test Scenarios**:
1. **Boot Sequence Test**:
- Start game from BootstrapScene
- Verify all lifecycle phases execute in order
- Check priority ordering is respected
- Validate settings load correctly
2. **Scene Transition Test**:
- Switch between multiple scenes
- Verify OnSceneReady called for new scenes
- Verify OnSceneUnloading called for old scenes
- Check persistent components don't receive scene events
3. **Save/Load Test**:
- Save game state
- Switch scenes
- Load saved state
- Verify all ISaveParticipant components restored
4. **Pause System Test**:
- Pause game (multiple requests)
- Verify all pausable components paused
- Resume game
- Verify all components resumed
5. **Late Registration Test**:
- Instantiate ManagedBehaviour after boot
- Verify it receives appropriate lifecycle calls
- Check it gets current state (paused, scene ready, etc.)
6. **Destruction Test**:
- Destroy ManagedBehaviours during gameplay
- Verify cleanup happens correctly
- Check no memory leaks (event subscriptions cleaned)
7. **Performance Test**:
- Spawn 100+ ManagedBehaviours
- Measure frame time impact
- Profile Update broadcasts
- Check memory usage
---
### STEP 32: Migration Strategy for Remaining Components
**Approach**: Gradual, category-by-category migration
**Phase 1: Critical Path** (Already covered in steps 20-25)
- Core managers
- UI systems
- Gameplay systems
**Phase 2: Scene-Specific Components**
- Level switches
- Minigame components
- Puzzle elements
- Scene triggers
**Phase 3: Utility Components**
- Camera systems
- Audio managers
- Effect spawners
- Pooling systems
**Phase 4: Low-Priority/External**
- Experimental scripts
- Test components
- External plugin wrappers
**For Each Component**:
1. Assess if it benefits from ManagedBehaviour (needs lifecycle control?)
2. If yes: follow migration pattern (change base class, update hooks)
3. If no: leave as MonoBehaviour (simple utility scripts)
4. Test after each file migrated
5. Commit to version control
**Key Details**:
- Not all components need migration (only those needing lifecycle control)
- Prioritize components with InitializePostBoot, scene event subscriptions, or complex initialization
- Simple components (visual effects, UI elements) can stay MonoBehaviour
- Document migration decisions in code comments
---
### STEP 33: Backward Compatibility Layer
**File**: `Assets/Scripts/Core/Lifecycle/LegacyMonoBehaviourAdapter.cs`
**Actions**:
1. Create adapter class for existing MonoBehaviour components
2. Allows non-migrated components to participate in lifecycle
3. Implement manual registration helper:
```csharp
public static class LifecycleHelper
{
public static void RegisterLegacyComponent(MonoBehaviour component, Action onBootComplete)
{
BootCompletionService.RegisterInitAction(onBootComplete);
}
}
```
4. Document when to use adapter vs. migration
**Key Details**:
- Provides bridge during migration period
- Allows incremental adoption
- Eventually can be deprecated once migration complete
---
### STEP 34: Code Cleanup and Refactoring
**Actions**:
1. **Remove Redundant Code**:
- Search for `BootCompletionService.RegisterInitAction` in migrated files (should be removed)
- Search for manual event subscription patterns (Convert to RegisterManagedEvent)
- Remove empty InitializePostBoot methods
2. **Standardize Patterns**:
- Consistent priority values across similar components
- Consistent ActiveLifecyclePhases usage
- Consistent logging patterns
3. **Update Comments**:
- Remove outdated references to old lifecycle
- Add references to ManagedBehaviour lifecycle
- Document priority decisions
4. **Code Review**:
- Review all migrated files
- Check for proper base.OnManagedAwake() calls
- Verify no breaking changes to public APIs
---
### STEP 35: Update Project Documentation
**Files to Update**:
1. `docs/bootstrap_readme.md`:
- Add section on ManagedBehaviour integration
- Update lifecycle flow diagrams
- Reference new lifecycle guide
2. `README.md`:
- Add link to ManagedBehaviour documentation
- Update project structure description
3. Create `docs/ManagedBehaviour_Migration_Log.md`:
- List of migrated components
- Migration dates
- Issues encountered and solutions
- Components intentionally not migrated
4. Update inline documentation:
- Update XML comments in migrated files
- Reference ManagedBehaviour lifecycle in comments
- Add examples where helpful
---
### STEP 36: Performance Profiling and Optimization
**Actions**:
1. **Baseline Measurements**:
- Measure current performance (before optimization)
- Profile Update broadcasts (100+ components)
- Memory allocation tracking
- GC pressure measurement
2. **Optimization Targets**:
- LifecycleManager.Update < 0.5ms (100 components)
- LifecycleManager.FixedUpdate < 0.3ms (100 components)
- Registration < 0.1ms per component
- Zero GC allocations during broadcasts
3. **Implementation**:
- Cache component counts
- Use for loops instead of foreach (no allocator)
- Avoid boxing in generic methods
- Pool event subscription objects
- Use struct enumerators
4. **Validation**:
- Re-profile after optimizations
- Compare against baseline
- Ensure optimizations don't break functionality
---
### STEP 37: Edge Case Handling
**Scenarios to Handle**:
1. **Editor Mode**:
- Handle domain reload
- Handle enter/exit play mode
- Handle script recompilation during play
2. **Build Scenarios**:
- Development builds (debug logging enabled)
- Release builds (debug code stripped)
- Platform-specific behavior
3. **Error Recovery**:
- Handle missing LifecycleManager gracefully
- Handle null component references
- Handle exceptions during lifecycle hooks (isolate failures)
4. **Threading**:
- Ensure thread safety for registration queue
- Handle registration from background threads (queue for main thread)
5. **Scene Edge Cases**:
- Handle multiple scenes loaded additively
- Handle rapid scene switches
- Handle scene unload during lifecycle broadcast
**Implementation**: Add defensive checks, logging, and fallbacks throughout LifecycleManager and ManagedBehaviour.
---
### STEP 38: Create Tutorial Scene
**File**: `Assets/Scenes/ManagedBehaviourTutorial.unity`
**Actions**:
1. Create tutorial scene demonstrating system
2. Include examples of:
- Simple ManagedBehaviour
- Priority ordering demonstration
- Lifecycle phase visualization
- Event subscription examples
- Save/load integration
- Pause system integration
3. Add UI showing lifecycle events in real-time
4. Include interactive elements to trigger phases
**File**: `Assets/Scripts/Tutorial/LifecycleEventLogger.cs`
**Actions**:
1. Create component that logs all lifecycle events to UI
2. Shows order of execution
3. Shows timing information
4. Color-codes by priority
---
### STEP 39: Community Documentation and Examples
**File**: `docs/ManagedBehaviour_FAQ.md`
**Content**:
1. Frequently asked questions
2. Common mistakes and solutions
3. When to use ManagedBehaviour vs MonoBehaviour
4. Performance considerations
5. Debugging tips
**File**: `docs/ManagedBehaviour_Recipes.md`
**Content**:
1. Common patterns and recipes
2. Singleton pattern with ManagedBehaviour
3. Scene-specific manager pattern
4. Persistent service pattern
5. Component with managed events pattern
6. Save/load participant pattern
---
### STEP 40: Final Review and Release Preparation
**Checklist**:
- [ ] All core systems migrated
- [ ] All tests passing
- [ ] Performance targets met
- [ ] Documentation complete
- [ ] Examples created and tested
- [ ] Editor tools working
- [ ] No console errors or warnings
- [ ] Code reviewed
- [ ] Backward compatibility maintained
- [ ] Migration guide complete
**Final Actions**:
1. Create release notes
2. Tag version in git
3. Update project version number
4. Create migration checklist for team
5. Schedule team training/walkthrough
6. Monitor for issues after deployment
---
## Appendix A: Priority Guidelines
### Recommended Priority Ranges
| Component Type | Priority Range | Reasoning |
|----------------|----------------|-----------|
| Core Infrastructure | 0-20 | LifecycleManager, CustomBoot integration |
| Core Managers | 10-30 | GameManager, SceneManager, SaveManager |
| Service Providers | 30-50 | Settings providers, factories |
| Gameplay Managers | 50-100 | PuzzleManager, CardSystem, Minigames |
| UI Controllers | 100-150 | Page controllers, loading screens |
| Scene Components | 150-200 | Level-specific logic |
| Gameplay Objects | 200-500 | Interactables, pickups, NPCs |
| Visual Effects | 500-1000 | Particles, animations, decorative |
### Priority Best Practices
- Use increments of 5 or 10 for easy insertion
- Document priority decisions in code comments
- Avoid priority 0 (reserved for system use)
- Group related components in same priority range
- Consider dependencies when assigning priorities
---
## Appendix B: Common Migration Patterns
### Pattern 1: Basic Singleton Manager
**Before**:
```csharp
public class MyManager : MonoBehaviour
{
private static MyManager _instance;
public static MyManager Instance => _instance;
void Awake()
{
_instance = this;
BootCompletionService.RegisterInitAction(InitializePostBoot);
}
private void InitializePostBoot()
{
// Setup
}
}
```
**After**:
```csharp
public class MyManager : ManagedBehaviour
{
private static MyManager _instance;
public static MyManager Instance => _instance;
protected override int BootCompletePriority => 50;
protected override LifecycleFlags ActiveLifecyclePhases =>
LifecycleFlags.ManagedAwake | LifecycleFlags.BootComplete;
protected override void OnManagedAwake()
{
_instance = this;
}
protected override void OnBootComplete()
{
// Setup
}
}
```
### Pattern 2: Component with Event Subscriptions
**Before**:
```csharp
public class MyComponent : MonoBehaviour
{
void Start()
{
SomeManager.Instance.OnEvent += HandleEvent;
}
void OnDestroy()
{
if (SomeManager.Instance != null)
SomeManager.Instance.OnEvent -= HandleEvent;
}
private void HandleEvent() { }
}
```
**After**:
```csharp
public class MyComponent : ManagedBehaviour
{
protected override LifecycleFlags ActiveLifecyclePhases =>
LifecycleFlags.BootComplete;
protected override void OnBootComplete()
{
RegisterManagedEvent(SomeManager.Instance,
m => m.OnEvent += HandleEvent);
}
private void HandleEvent() { }
// No OnDestroy needed - auto cleanup
}
```
### Pattern 3: Scene-Specific Component
**Before**:
```csharp
public class LevelComponent : MonoBehaviour
{
void Start()
{
SceneManagerService.Instance.SceneLoadCompleted += OnSceneLoaded;
Initialize();
}
void OnDestroy()
{
if (SceneManagerService.Instance != null)
SceneManagerService.Instance.SceneLoadCompleted -= OnSceneLoaded;
}
private void OnSceneLoaded(string sceneName) { }
private void Initialize() { }
}
```
**After**:
```csharp
public class LevelComponent : ManagedBehaviour
{
protected override LifecycleFlags ActiveLifecyclePhases =>
LifecycleFlags.SceneReady | LifecycleFlags.SceneUnloading;
protected override void OnSceneReady()
{
Initialize();
}
protected override void OnSceneUnloading()
{
Cleanup();
}
private void Initialize() { }
private void Cleanup() { }
}
```
---
## Appendix C: Troubleshooting Guide
### Issue: Lifecycle hook not being called
**Symptoms**: OnBootComplete or other hook not executing
**Solutions**:
1. Check ActiveLifecyclePhases includes the appropriate flag
2. Verify LifecycleManager exists in scene
3. Ensure base.OnManagedAwake() called if overriding
4. Check LifecycleManager debug logs
### Issue: Wrong execution order
**Symptoms**: Components initialize in unexpected order
**Solutions**:
1. Verify priority values (lower = earlier)
2. Check for priority conflicts (same priority = undefined order)
3. Add debug logging to verify execution order
4. Use LifecycleDebugWindow to visualize order
### Issue: Events not cleaning up
**Symptoms**: Memory leaks or errors after component destruction
**Solutions**:
1. Use RegisterManagedEvent instead of manual subscription
2. Verify OnDestroy calls base.OnDestroy()
3. Check event target is not null when registering
4. Review LifecycleManager event cleanup logs
### Issue: Performance degradation
**Symptoms**: Frame time increases with many ManagedBehaviours
**Solutions**:
1. Only override lifecycle hooks you need
2. Don't use OnManagedUpdate if Unity Update suffices
3. Profile with Unity Profiler to find bottleneck
4. Check for excessive logging in release builds
5. Optimize ActiveLifecyclePhases (don't include unused phases)
---
## Appendix D: Integration Checklist
Use this checklist when migrating each component:
**Pre-Migration**:
- [ ] Component has InitializePostBoot or complex initialization
- [ ] Component subscribes to manager events
- [ ] Component needs deterministic initialization order
- [ ] Component is ISaveParticipant or IPausable
**Migration**:
- [ ] Changed base class to ManagedBehaviour
- [ ] Set appropriate priority values
- [ ] Added ActiveLifecyclePhases flags
- [ ] Moved Awake logic to OnManagedAwake
- [ ] Moved InitializePostBoot to OnBootComplete
- [ ] Converted event subscriptions to RegisterManagedEvent
- [ ] Removed manual BootCompletionService registration
- [ ] Set AutoRegisterSaveParticipant if ISaveParticipant
- [ ] Set AutoRegisterPausable if IPausable
- [ ] Updated XML documentation
**Post-Migration**:
- [ ] No compiler errors
- [ ] Component still functions correctly
- [ ] Lifecycle hooks called at appropriate times
- [ ] Priority ordering correct relative to dependencies
- [ ] No memory leaks (events cleaned up)
- [ ] Performance acceptable
- [ ] Code reviewed
- [ ] Tests updated/added
---
## Appendix E: Future Enhancements
Potential future additions to the system:
1. **Async Lifecycle Hooks**: Support for async/await in lifecycle methods
2. **Conditional Phases**: Enable/disable phases at runtime
3. **Lifecycle Groups**: Group related components for batch operations
4. **Visual Editor**: Node-based lifecycle flow visualization
5. **Hot Reload Support**: Better handling of domain reload in editor
6. **Multi-threading**: Parallel execution of independent components
7. **Lifecycle Templates**: Pre-configured setups for common patterns
8. **Analytics Integration**: Track lifecycle performance in production
9. **Memory Pooling**: Pool ManagedBehaviour instances for performance
10. **Dependency Injection**: Auto-resolve dependencies in OnManagedAwake
---
## Document Metadata
**Version**: 1.0
**Last Updated**: October 30, 2025
**Author**: AI Assistant
**Status**: Ready for Implementation
**Implementation Estimate**: 40-60 hours across 2-3 weeks
**Risk Level**: Medium (significant refactoring, but incremental approach reduces risk)
**Prerequisites**: Unity 2021.3+, C# 8.0+, existing bootstrap system
**Next Steps**:
1. Review this document thoroughly
2. Get team approval
3. Begin with STEP 1
4. Progress sequentially through steps
5. Test thoroughly at each phase
6. Document any deviations or issues