812 lines
29 KiB
Markdown
812 lines
29 KiB
Markdown
|
|
# Lifecycle Management System - Technical Review & Recommendations
|
||
|
|
|
||
|
|
**Date:** November 3, 2025
|
||
|
|
**Reviewer:** System Architect
|
||
|
|
**Project:** AppleHills (6-month timeline)
|
||
|
|
**Status:** Awaiting Technical Review Approval
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Executive Summary
|
||
|
|
|
||
|
|
This document analyzes the proposed ManagedBehaviour lifecycle management system and provides a pragmatic recommendation for a 6-month project timeline. After analyzing the current codebase (20+ components using InitializePostBoot, 6+ ISaveParticipant implementations, 10+ IPausable implementations), I recommend implementing a **Streamlined ManagedBehaviour** approach that solves 80% of the problems with 20% of the complexity.
|
||
|
|
|
||
|
|
**Key Recommendation:** Implement core lifecycle management without the complex multi-phase system. Focus on boot lifecycle, auto-registration, and event cleanup. Estimated implementation: 2-3 days + 1-2 days migration.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. Current System Analysis
|
||
|
|
|
||
|
|
### 1.1 Existing Lifecycle Patterns
|
||
|
|
|
||
|
|
The codebase currently uses **four different initialization patterns**:
|
||
|
|
|
||
|
|
#### Pattern A: Unity Standard (Awake → Start)
|
||
|
|
```csharp
|
||
|
|
void Awake() { /* Basic setup */ }
|
||
|
|
void Start() { /* Initialization */ }
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Pattern B: Two-Phase Bootstrap (Awake → InitializePostBoot)
|
||
|
|
```csharp
|
||
|
|
void Awake()
|
||
|
|
{
|
||
|
|
_instance = this;
|
||
|
|
BootCompletionService.RegisterInitAction(InitializePostBoot, priority: 100);
|
||
|
|
}
|
||
|
|
|
||
|
|
private void InitializePostBoot()
|
||
|
|
{
|
||
|
|
// Setup after boot completes
|
||
|
|
}
|
||
|
|
```
|
||
|
|
**Usage:** 20+ components across the codebase
|
||
|
|
|
||
|
|
#### Pattern C: Manual Event Subscription
|
||
|
|
```csharp
|
||
|
|
void Awake()
|
||
|
|
{
|
||
|
|
BootCompletionService.RegisterInitAction(InitializePostBoot);
|
||
|
|
}
|
||
|
|
|
||
|
|
private void InitializePostBoot()
|
||
|
|
{
|
||
|
|
SceneManagerService.Instance.SceneLoadCompleted += OnSceneLoaded;
|
||
|
|
GameManager.Instance.OnGamePaused += OnPaused;
|
||
|
|
}
|
||
|
|
|
||
|
|
void OnDestroy()
|
||
|
|
{
|
||
|
|
// MUST remember to unsubscribe - memory leak risk!
|
||
|
|
SceneManagerService.Instance.SceneLoadCompleted -= OnSceneLoaded;
|
||
|
|
GameManager.Instance.OnGamePaused -= OnPaused;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Pattern D: Manual Registration (ISaveParticipant, IPausable)
|
||
|
|
```csharp
|
||
|
|
private void InitializePostBoot()
|
||
|
|
{
|
||
|
|
SaveLoadManager.Instance.RegisterParticipant(this);
|
||
|
|
GameManager.Instance.RegisterPausableComponent(this);
|
||
|
|
}
|
||
|
|
|
||
|
|
void OnDestroy()
|
||
|
|
{
|
||
|
|
SaveLoadManager.Instance.UnregisterParticipant(GetSaveId());
|
||
|
|
GameManager.Instance.UnregisterPausableComponent(this);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
**Usage:** 6+ ISaveParticipant, 10+ IPausable implementations
|
||
|
|
|
||
|
|
### 1.2 Bootstrap Flow
|
||
|
|
|
||
|
|
```
|
||
|
|
CustomBoot.Initialise() [BeforeSplashScreen]
|
||
|
|
↓
|
||
|
|
Load CustomBootSettings (Addressables)
|
||
|
|
↓
|
||
|
|
Unity Awake() [All MonoBehaviours, unordered]
|
||
|
|
↓
|
||
|
|
Unity Start()
|
||
|
|
↓
|
||
|
|
CustomBoot completes
|
||
|
|
↓
|
||
|
|
BootCompletionService.HandleBootCompleted()
|
||
|
|
↓
|
||
|
|
Execute registered init actions (priority sorted: 0→1000)
|
||
|
|
↓
|
||
|
|
OnBootComplete event fires
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. Problem Identification
|
||
|
|
|
||
|
|
### Critical Issues
|
||
|
|
|
||
|
|
#### 🔴 P0: Confusing Two-Phase Lifecycle
|
||
|
|
- Developers must remember to use `Awake()` + `InitializePostBoot()` pattern
|
||
|
|
- Priority is defined at registration site (not in component), making dependencies unclear
|
||
|
|
- Inconsistent naming: `InitializePostBoot()`, `Initialize()`, `Init()`, `PostBootInit()`
|
||
|
|
- No clear guidance on what belongs in which phase
|
||
|
|
|
||
|
|
#### 🔴 P0: Memory Leak Risk
|
||
|
|
- Manual event subscription requires matching unsubscription in OnDestroy()
|
||
|
|
- Easy to forget unsubscribe, especially during rapid development
|
||
|
|
- No automated cleanup mechanism
|
||
|
|
- Found 15+ manual subscription sites
|
||
|
|
|
||
|
|
#### 🟡 P1: Registration Burden
|
||
|
|
- ISaveParticipant components must manually call RegisterParticipant() and UnregisterParticipant()
|
||
|
|
- IPausable components must manually call RegisterPausableComponent() and UnregisterPausableComponent()
|
||
|
|
- Boilerplate code repeated across 16+ components
|
||
|
|
|
||
|
|
#### 🟡 P1: Late Registration Handling
|
||
|
|
- Components instantiated after boot must handle "already booted" case manually
|
||
|
|
- BootCompletionService handles this, but scene-specific services don't
|
||
|
|
- Inconsistent behavior across different managers
|
||
|
|
|
||
|
|
#### 🟢 P2: Priority System Fragmentation
|
||
|
|
- Boot priority defined at call site: `RegisterInitAction(method, priority: 50)`
|
||
|
|
- No centralized view of initialization order
|
||
|
|
- Hard to debug dependency issues
|
||
|
|
|
||
|
|
### Non-Issues (Working Well)
|
||
|
|
|
||
|
|
✅ **Singleton Pattern:** Consistent `_instance` field + `Instance` property
|
||
|
|
✅ **BootCompletionService:** Solid priority-based initialization
|
||
|
|
✅ **Scene Management:** Event-based lifecycle works well
|
||
|
|
✅ **Save/Load System:** ISaveParticipant interface is clean
|
||
|
|
✅ **Pause System:** Counter-based pause with IPausable interface
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. Solution Options
|
||
|
|
|
||
|
|
### Option A: Minimal Enhancement (Conservative)
|
||
|
|
**Description:** Keep MonoBehaviour base, add helper utilities
|
||
|
|
|
||
|
|
**Changes:**
|
||
|
|
- Create `BootHelper` utility class for common patterns
|
||
|
|
- Add `ManagedEventSubscription` wrapper for auto-cleanup
|
||
|
|
- Extension methods for auto-registration
|
||
|
|
|
||
|
|
**Pros:**
|
||
|
|
- Minimal code changes (< 1 day implementation)
|
||
|
|
- Zero breaking changes
|
||
|
|
- Very safe
|
||
|
|
|
||
|
|
**Cons:**
|
||
|
|
- Doesn't solve core lifecycle confusion
|
||
|
|
- Still requires manual patterns
|
||
|
|
- Least impactful solution
|
||
|
|
|
||
|
|
**Effort:** 1 day implementation, 0 days migration
|
||
|
|
**Recommendation:** ❌ Not recommended - doesn't solve main problems
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Option B+: Streamlined ManagedBehaviour with Scene Orchestration (RECOMMENDED)
|
||
|
|
**Description:** Focused base class solving critical pain points + orchestrated scene transitions
|
||
|
|
|
||
|
|
**Core Features:**
|
||
|
|
1. **Deterministic Boot Lifecycle**
|
||
|
|
- `OnManagedAwake()` - Called after Unity Awake, priority-ordered
|
||
|
|
- `OnBootComplete()` - Called after boot completes, priority-ordered
|
||
|
|
- Properties: `ManagedAwakePriority`, `BootCompletePriority`
|
||
|
|
|
||
|
|
2. **Orchestrated Scene Lifecycle**
|
||
|
|
- `OnSceneUnloading()` - Called before scene unloads, reverse priority-ordered
|
||
|
|
- `OnSceneReady()` - Called after scene loads, priority-ordered
|
||
|
|
- Properties: `SceneUnloadingPriority`, `SceneReadyPriority`
|
||
|
|
- SceneManagerService.SwitchSceneAsync() orchestrates full flow
|
||
|
|
|
||
|
|
3. **Auto-Registration**
|
||
|
|
- Auto-register ISaveParticipant (opt-in via `AutoRegisterSaveParticipant` property)
|
||
|
|
- Auto-register IPausable (opt-in via `AutoRegisterPausable` property)
|
||
|
|
- Auto-unregister on destroy
|
||
|
|
|
||
|
|
4. **Managed Event Subscriptions**
|
||
|
|
- `RegisterManagedEvent(target, handler)` - Auto-cleanup on destroy
|
||
|
|
- Prevents memory leaks
|
||
|
|
- Simple, fail-safe pattern
|
||
|
|
|
||
|
|
5. **LifecycleManager**
|
||
|
|
- Central orchestrator (singleton in BootstrapScene)
|
||
|
|
- Maintains priority-sorted lists
|
||
|
|
- Broadcasts lifecycle events
|
||
|
|
- Integrates with BootCompletionService (temporarily)
|
||
|
|
- Tracks which scene each component belongs to
|
||
|
|
|
||
|
|
6. **Enhanced SceneManagerService**
|
||
|
|
- SwitchSceneAsync() includes full orchestration
|
||
|
|
- No separate orchestrator class needed
|
||
|
|
- Integrates with LifecycleManager for scene lifecycle callbacks
|
||
|
|
|
||
|
|
**NOT Included** (keeping it simple):
|
||
|
|
- ❌ OnManagedUpdate / OnManagedFixedUpdate - Performance overhead, rarely needed
|
||
|
|
- ❌ OnPaused / OnResumed - Implement IPausable interface directly instead
|
||
|
|
- ❌ Separate SceneTransitionOrchestrator - Logic integrated into SceneManagerService
|
||
|
|
|
||
|
|
**Example Usage:**
|
||
|
|
```csharp
|
||
|
|
public class GameManager : ManagedBehaviour
|
||
|
|
{
|
||
|
|
protected override int ManagedAwakePriority => 10; // Very early
|
||
|
|
protected override int BootCompletePriority => 10;
|
||
|
|
|
||
|
|
protected override void OnManagedAwake()
|
||
|
|
{
|
||
|
|
// Deterministic initialization, runs at priority 10
|
||
|
|
SetupSingleton();
|
||
|
|
}
|
||
|
|
|
||
|
|
protected override void OnBootComplete()
|
||
|
|
{
|
||
|
|
// Replaces InitializePostBoot()
|
||
|
|
InitializeSettings();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public class PuzzleManager : ManagedBehaviour, ISaveParticipant
|
||
|
|
{
|
||
|
|
protected override bool AutoRegisterSaveParticipant => true; // Auto-registers!
|
||
|
|
protected override int SceneReadyPriority => 100;
|
||
|
|
protected override int SceneUnloadingPriority => 100;
|
||
|
|
|
||
|
|
protected override LifecycleFlags ActiveLifecyclePhases =>
|
||
|
|
LifecycleFlags.BootComplete |
|
||
|
|
LifecycleFlags.SceneReady |
|
||
|
|
LifecycleFlags.SceneUnloading;
|
||
|
|
|
||
|
|
protected override void OnBootComplete()
|
||
|
|
{
|
||
|
|
// SaveLoadManager registration happens automatically
|
||
|
|
}
|
||
|
|
|
||
|
|
protected override void OnSceneReady()
|
||
|
|
{
|
||
|
|
// Scene fully loaded, discover puzzles in scene
|
||
|
|
DiscoverPuzzlesInScene();
|
||
|
|
}
|
||
|
|
|
||
|
|
protected override void OnSceneUnloading()
|
||
|
|
{
|
||
|
|
// Save transient state before scene unloads
|
||
|
|
CleanupPuzzles();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Pros:**
|
||
|
|
- ✅ Solves main pain points (lifecycle confusion, memory leaks, registration burden)
|
||
|
|
- ✅ Orchestrated scene transitions with proper save/cleanup/restore flow
|
||
|
|
- ✅ Clear migration path (change base class, rename methods)
|
||
|
|
- ✅ Minimal performance overhead
|
||
|
|
- ✅ Can be extended incrementally
|
||
|
|
- ✅ Clean, intuitive API
|
||
|
|
- ✅ ~5-7 days total implementation + migration
|
||
|
|
|
||
|
|
**Cons:**
|
||
|
|
- Requires base class change (20+ files)
|
||
|
|
- Scene lifecycle adds some complexity (but solves critical orchestration need)
|
||
|
|
- BootCompletionService remains temporarily (deprecated over time)
|
||
|
|
|
||
|
|
**Effort:** 3-4 days implementation, 2-3 days migration, 1 day BootCompletionService removal
|
||
|
|
**Recommendation:** ✅ **RECOMMENDED** - Best balance for 6-month project with proper scene orchestration
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Option C: Full ManagedBehaviour (As Proposed)
|
||
|
|
**Description:** Complete 9-phase lifecycle system as documented
|
||
|
|
|
||
|
|
**All Features from Option B, PLUS:**
|
||
|
|
- OnSceneReady / OnSceneUnloading with automatic scene tracking
|
||
|
|
- OnManagedUpdate / OnManagedFixedUpdate with priority ordering
|
||
|
|
- OnPaused / OnResumed lifecycle hooks
|
||
|
|
- Per-phase priority properties (9 different priority settings)
|
||
|
|
- LifecycleFlags enum for opt-in per phase
|
||
|
|
- IsPersistent flag for scene persistence tracking
|
||
|
|
- Complex multi-list management in LifecycleManager
|
||
|
|
|
||
|
|
**Pros:**
|
||
|
|
- Most comprehensive solution
|
||
|
|
- Future-proof and extensible
|
||
|
|
- Complete control over execution order
|
||
|
|
|
||
|
|
**Cons:**
|
||
|
|
- ❌ High implementation complexity (5-7 days)
|
||
|
|
- ❌ Significant migration effort (3-5 days for 20+ files)
|
||
|
|
- ❌ Performance overhead (broadcasts every frame for OnManagedUpdate)
|
||
|
|
- ❌ Over-engineered for 6-month timeline
|
||
|
|
- ❌ Higher maintenance burden
|
||
|
|
- ❌ More opportunities for bugs in complex orchestration
|
||
|
|
|
||
|
|
**Effort:** 5-7 days implementation, 3-5 days migration, ongoing maintenance
|
||
|
|
**Recommendation:** ⚠️ Too complex for current project scope
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. Detailed Recommendation: Streamlined ManagedBehaviour with Orchestrated Scene Transitions (Option B+)
|
||
|
|
|
||
|
|
### 4.1 Architecture
|
||
|
|
|
||
|
|
```
|
||
|
|
┌─────────────────────────────────────────────────────────┐
|
||
|
|
│ CustomBoot (Unchanged) │
|
||
|
|
│ - Loads settings via Addressables │
|
||
|
|
│ - Triggers BootCompletionService │
|
||
|
|
└─────────────────────────────────────────────────────────┘
|
||
|
|
↓
|
||
|
|
┌─────────────────────────────────────────────────────────┐
|
||
|
|
│ BootCompletionService (Thin Adapter - TO BE DEPRECATED)│
|
||
|
|
│ - Executes legacy RegisterInitAction callbacks │
|
||
|
|
│ - Fires OnBootComplete event │
|
||
|
|
│ - Triggers LifecycleManager.OnBootCompletionTriggered()│
|
||
|
|
│ - GOAL: Remove once all code migrated │
|
||
|
|
└─────────────────────────────────────────────────────────┘
|
||
|
|
↓
|
||
|
|
┌─────────────────────────────────────────────────────────┐
|
||
|
|
│ LifecycleManager (Core Orchestrator) │
|
||
|
|
│ - Maintains sorted lists for each phase │
|
||
|
|
│ - BroadcastManagedAwake() │
|
||
|
|
│ - BroadcastBootComplete() │
|
||
|
|
│ - BroadcastSceneUnloading(sceneName) │
|
||
|
|
│ - BroadcastSceneReady(sceneName) │
|
||
|
|
│ - Tracks which scene each component belongs to │
|
||
|
|
└─────────────────────────────────────────────────────────┘
|
||
|
|
↓
|
||
|
|
┌─────────────────────────────────────────────────────────┐
|
||
|
|
│ SceneManagerService (Enhanced - Scene Orchestration) │
|
||
|
|
│ - SwitchSceneAsync() orchestrates full transition: │
|
||
|
|
│ 1. Show loading screen │
|
||
|
|
│ 2. LifecycleManager.BroadcastSceneUnloading() │
|
||
|
|
│ 3. SaveLoadManager.Save() │
|
||
|
|
│ 4. UnloadSceneAsync() │
|
||
|
|
│ 5. LoadSceneAsync() │
|
||
|
|
│ 6. LifecycleManager.BroadcastSceneReady() │
|
||
|
|
│ 7. Hide loading screen │
|
||
|
|
└─────────────────────────────────────────────────────────┘
|
||
|
|
↓
|
||
|
|
┌─────────────────────────────────────────────────────────┐
|
||
|
|
│ ManagedBehaviour (Base Class) │
|
||
|
|
│ - Auto-registers with LifecycleManager in Awake() │
|
||
|
|
│ - OnManagedAwake() / OnBootComplete() │
|
||
|
|
│ - OnSceneUnloading() / OnSceneReady() │
|
||
|
|
│ - Priority properties for all lifecycle hooks │
|
||
|
|
│ - Auto-registration for ISaveParticipant/IPausable │
|
||
|
|
│ - Managed event subscriptions with auto-cleanup │
|
||
|
|
└─────────────────────────────────────────────────────────┘
|
||
|
|
↓ uses
|
||
|
|
┌─────────────────────────────────────────────────────────┐
|
||
|
|
│ ManagedEventSubscription (Helper) │
|
||
|
|
│ - Stores event subscriptions │
|
||
|
|
│ - Auto-unsubscribes on destroy │
|
||
|
|
└─────────────────────────────────────────────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4.2 Migration End Goal
|
||
|
|
|
||
|
|
**Target State:** Remove all legacy lifecycle services
|
||
|
|
- ❌ BootCompletionService - Completely removed
|
||
|
|
- ❌ Manual RegisterInitAction calls - Eliminated
|
||
|
|
- ❌ InitializePostBoot methods - Converted to OnBootComplete
|
||
|
|
- ✅ LifecycleManager - Single source of truth for all lifecycle
|
||
|
|
- ✅ ManagedBehaviour - Standard base class for all components
|
||
|
|
- ✅ SceneManagerService - Orchestrates scene transitions with lifecycle integration
|
||
|
|
|
||
|
|
### 4.2 Lifecycle Flow
|
||
|
|
|
||
|
|
```
|
||
|
|
Unity Awake() (All MonoBehaviours)
|
||
|
|
↓
|
||
|
|
ManagedBehaviour.Awake()
|
||
|
|
└→ Registers with LifecycleManager
|
||
|
|
↓
|
||
|
|
Unity Start()
|
||
|
|
↓
|
||
|
|
CustomBoot completes
|
||
|
|
↓
|
||
|
|
BootCompletionService.HandleBootCompleted()
|
||
|
|
↓
|
||
|
|
LifecycleManager.BroadcastManagedAwake()
|
||
|
|
└→ Calls OnManagedAwake() in priority order (0→∞)
|
||
|
|
↓
|
||
|
|
LifecycleManager.BroadcastBootComplete()
|
||
|
|
└→ Calls OnBootComplete() in priority order (0→∞)
|
||
|
|
└→ Auto-registers ISaveParticipant/IPausable if configured
|
||
|
|
↓
|
||
|
|
[Game Loop]
|
||
|
|
↓
|
||
|
|
ManagedBehaviour.OnDestroy()
|
||
|
|
└→ Auto-unregisters from LifecycleManager
|
||
|
|
└→ Auto-unsubscribes all managed events
|
||
|
|
└→ Auto-unregisters from SaveLoadManager/GameManager
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4.3 Implementation Plan
|
||
|
|
|
||
|
|
#### Phase 1: Core Infrastructure (Day 1)
|
||
|
|
1. **Create LifecycleEnums.cs**
|
||
|
|
- `LifecyclePhase` enum (ManagedAwake, BootComplete)
|
||
|
|
|
||
|
|
2. **Create ManagedEventSubscription.cs**
|
||
|
|
- Internal struct to store subscription info
|
||
|
|
- ManagedEventManager for auto-cleanup
|
||
|
|
|
||
|
|
3. **Create ManagedBehaviour.cs**
|
||
|
|
- Base class extending MonoBehaviour
|
||
|
|
- Virtual properties: `ManagedAwakePriority`, `BootCompletePriority`, `AutoRegisterSaveParticipant`, `AutoRegisterPausable`
|
||
|
|
- Virtual methods: `OnManagedAwake()`, `OnBootComplete()`
|
||
|
|
- Auto-registration in Awake()
|
||
|
|
- Auto-cleanup in OnDestroy()
|
||
|
|
- `RegisterManagedEvent()` helper
|
||
|
|
|
||
|
|
4. **Create LifecycleManager.cs**
|
||
|
|
- Singleton in BootstrapScene
|
||
|
|
- Sorted lists for each phase
|
||
|
|
- Register/Unregister methods
|
||
|
|
- BroadcastManagedAwake/BootComplete methods
|
||
|
|
- Integration with BootCompletionService
|
||
|
|
|
||
|
|
#### Phase 2: Integration (Day 2)
|
||
|
|
5. **Modify BootCompletionService.cs**
|
||
|
|
- After existing init actions, call LifecycleManager broadcasts
|
||
|
|
|
||
|
|
6. **Extend SaveLoadManager.cs**
|
||
|
|
- Add `AutoRegisterParticipant(ISaveParticipant, ManagedBehaviour)` method
|
||
|
|
- Add `AutoUnregisterParticipant(ManagedBehaviour)` method
|
||
|
|
- Track auto-registrations
|
||
|
|
|
||
|
|
7. **Extend GameManager.cs**
|
||
|
|
- Add `AutoRegisterPausable(IPausable, ManagedBehaviour)` method
|
||
|
|
- Add `AutoUnregisterPausable(ManagedBehaviour)` method
|
||
|
|
- Track auto-registrations
|
||
|
|
|
||
|
|
#### Phase 3: Testing & Documentation (Day 3)
|
||
|
|
8. **Create Example Implementations**
|
||
|
|
- ExampleManagedSingleton.cs
|
||
|
|
- ExampleManagedComponent.cs
|
||
|
|
- ExampleManagedSaveParticipant.cs
|
||
|
|
|
||
|
|
9. **Write Migration Guide**
|
||
|
|
- Step-by-step conversion process
|
||
|
|
- Common patterns and gotchas
|
||
|
|
|
||
|
|
10. **Create Validation Tools** (Optional)
|
||
|
|
- Editor script to find components needing migration
|
||
|
|
- Automated conversion helper
|
||
|
|
|
||
|
|
#### Phase 4: Migration (Days 4-5)
|
||
|
|
11. **Migrate Core Systems** (Priority Order)
|
||
|
|
- GameManager (priority 10)
|
||
|
|
- SceneManagerService (priority 15)
|
||
|
|
- SaveLoadManager (priority 20)
|
||
|
|
- AudioManager (priority 25)
|
||
|
|
|
||
|
|
12. **Migrate UI Systems** (Priority 50-100)
|
||
|
|
- UIPageController
|
||
|
|
- LoadingScreenController
|
||
|
|
- PauseMenu
|
||
|
|
- CardSystemUI components
|
||
|
|
|
||
|
|
13. **Migrate Gameplay Systems** (Priority 100-200)
|
||
|
|
- PuzzleManager
|
||
|
|
- CardSystemManager
|
||
|
|
- FollowerController
|
||
|
|
- PlayerTouchController
|
||
|
|
- DialogueComponent
|
||
|
|
|
||
|
|
### 4.4 Migration Process (Per Component)
|
||
|
|
|
||
|
|
**Step 1:** Change base class
|
||
|
|
```csharp
|
||
|
|
// Before
|
||
|
|
public class GameManager : MonoBehaviour
|
||
|
|
|
||
|
|
// After
|
||
|
|
public class GameManager : ManagedBehaviour
|
||
|
|
```
|
||
|
|
|
||
|
|
**Step 2:** Set priorities
|
||
|
|
```csharp
|
||
|
|
protected override int ManagedAwakePriority => 10;
|
||
|
|
protected override int BootCompletePriority => 10;
|
||
|
|
```
|
||
|
|
|
||
|
|
**Step 3:** Move initialization
|
||
|
|
```csharp
|
||
|
|
// Before
|
||
|
|
void Awake()
|
||
|
|
{
|
||
|
|
_instance = this;
|
||
|
|
BootCompletionService.RegisterInitAction(InitializePostBoot);
|
||
|
|
}
|
||
|
|
|
||
|
|
private void InitializePostBoot() { /* ... */ }
|
||
|
|
|
||
|
|
// After
|
||
|
|
protected override void OnManagedAwake()
|
||
|
|
{
|
||
|
|
_instance = this;
|
||
|
|
}
|
||
|
|
|
||
|
|
protected override void OnBootComplete()
|
||
|
|
{
|
||
|
|
// Former InitializePostBoot() code
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Step 4:** Enable auto-registration (if applicable)
|
||
|
|
```csharp
|
||
|
|
// For ISaveParticipant
|
||
|
|
protected override bool AutoRegisterSaveParticipant => true;
|
||
|
|
|
||
|
|
// For IPausable
|
||
|
|
protected override bool AutoRegisterPausable => true;
|
||
|
|
|
||
|
|
// Remove manual registration code from InitializePostBoot/OnDestroy
|
||
|
|
```
|
||
|
|
|
||
|
|
**Step 5:** Convert event subscriptions
|
||
|
|
```csharp
|
||
|
|
// Before
|
||
|
|
private void InitializePostBoot()
|
||
|
|
{
|
||
|
|
SceneManagerService.Instance.SceneLoadCompleted += OnSceneLoaded;
|
||
|
|
}
|
||
|
|
|
||
|
|
void OnDestroy()
|
||
|
|
{
|
||
|
|
SceneManagerService.Instance.SceneLoadCompleted -= OnSceneLoaded;
|
||
|
|
}
|
||
|
|
|
||
|
|
// After
|
||
|
|
protected override void OnBootComplete()
|
||
|
|
{
|
||
|
|
RegisterManagedEvent(SceneManagerService.Instance,
|
||
|
|
nameof(SceneManagerService.SceneLoadCompleted), OnSceneLoaded);
|
||
|
|
}
|
||
|
|
// OnDestroy cleanup automatic!
|
||
|
|
```
|
||
|
|
|
||
|
|
**Step 6:** Test thoroughly
|
||
|
|
- Verify initialization order
|
||
|
|
- Check event subscriptions work
|
||
|
|
- Confirm save/load integration
|
||
|
|
- Test pause functionality
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. Risk Assessment
|
||
|
|
|
||
|
|
### Technical Risks
|
||
|
|
|
||
|
|
| Risk | Likelihood | Impact | Mitigation |
|
||
|
|
|------|-----------|--------|------------|
|
||
|
|
| Base class change breaks existing components | Medium | High | Incremental migration, thorough testing |
|
||
|
|
| Performance overhead from lifecycle broadcasts | Low | Medium | Profile in real scenarios, optimize if needed |
|
||
|
|
| Managed event system fails to unsubscribe | Low | High | Extensive unit tests, code review |
|
||
|
|
| LifecycleManager initialization order issues | Medium | High | Careful integration with BootCompletionService |
|
||
|
|
| Developers revert to old patterns | Medium | Low | Clear documentation, code review enforcement |
|
||
|
|
|
||
|
|
### Schedule Risks
|
||
|
|
|
||
|
|
| Risk | Likelihood | Impact | Mitigation |
|
||
|
|
|------|-----------|--------|------------|
|
||
|
|
| Implementation takes longer than estimated | Low | Medium | 3-day buffer built into 6-month timeline |
|
||
|
|
| Migration uncovers edge cases | Medium | Medium | Migrate critical systems first, iterate |
|
||
|
|
| Team resistance to new pattern | Low | Medium | Provide clear examples, migration support |
|
||
|
|
|
||
|
|
### Mitigation Strategy
|
||
|
|
|
||
|
|
1. **Implement core infrastructure first** - Validate approach before migration
|
||
|
|
2. **Migrate critical systems first** - GameManager, SaveLoadManager
|
||
|
|
3. **Incremental rollout** - Don't migrate everything at once
|
||
|
|
4. **Comprehensive testing** - Unit tests + integration tests
|
||
|
|
5. **Documentation-first** - Write migration guide before starting
|
||
|
|
6. **Code reviews** - Ensure proper usage patterns
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 6. Success Criteria
|
||
|
|
|
||
|
|
### Quantitative Metrics
|
||
|
|
- ✅ All 20+ components using InitializePostBoot migrated
|
||
|
|
- ✅ Zero memory leaks from event subscriptions (verified via profiler)
|
||
|
|
- ✅ < 5% performance overhead in worst-case scenarios
|
||
|
|
- ✅ 100% of ISaveParticipant/IPausable use auto-registration
|
||
|
|
|
||
|
|
### Qualitative Goals
|
||
|
|
- ✅ Clear, consistent lifecycle pattern across codebase
|
||
|
|
- ✅ Reduced boilerplate (no manual registration code)
|
||
|
|
- ✅ Easier onboarding for new developers
|
||
|
|
- ✅ Better debuggability (centralized lifecycle view)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 7. Timeline Estimate
|
||
|
|
|
||
|
|
### Option B+: Streamlined ManagedBehaviour with Scene Orchestration (Recommended)
|
||
|
|
- **Phase 1 - Core Infrastructure:** 2 days
|
||
|
|
- Day 1: LifecycleEnums, ManagedEventSubscription, ManagedBehaviour structure
|
||
|
|
- Day 2: LifecycleManager implementation, prefab setup
|
||
|
|
- **Phase 2 - Integration:** 1 day
|
||
|
|
- BootCompletionService integration, SaveLoadManager/GameManager extensions, SceneManagerService prep
|
||
|
|
- **Phase 3 - Scene Orchestration:** 2 days
|
||
|
|
- Day 4: SceneManagerService.SwitchSceneAsync() orchestration, examples
|
||
|
|
- Day 5: Migration guide, testing & validation
|
||
|
|
- **Phase 4 - Migration & Cleanup:** 3 days
|
||
|
|
- Day 6: Core systems migration (GameManager, SceneManagerService, SaveLoadManager)
|
||
|
|
- Day 7: UI & gameplay systems migration (12+ files)
|
||
|
|
- Day 8: Final testing, BootCompletionService removal, documentation
|
||
|
|
- **Total:** 8 days (~1.5 weeks)
|
||
|
|
- **% of 6-month project:** 1.6%
|
||
|
|
|
||
|
|
### Full ManagedBehaviour (Not Recommended)
|
||
|
|
- **Implementation:** 5-7 days
|
||
|
|
- **Migration:** 3-5 days
|
||
|
|
- **Testing & Documentation:** 2 days
|
||
|
|
- **Ongoing Maintenance:** Higher
|
||
|
|
- **Total:** 10-14 days (~2-3 weeks)
|
||
|
|
- **% of 6-month project:** 3.5%
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 8. Alternative Approaches Considered
|
||
|
|
|
||
|
|
### 8.1 Unity ECS/DOTS
|
||
|
|
**Rejected Reason:** Too radical a change, incompatible with existing MonoBehaviour architecture
|
||
|
|
|
||
|
|
### 8.2 Dependency Injection Framework (Zenject/VContainer)
|
||
|
|
**Rejected Reason:** Solves different problems, adds external dependency, steeper learning curve
|
||
|
|
|
||
|
|
### 8.3 Event Bus System
|
||
|
|
**Rejected Reason:** Doesn't address lifecycle ordering, adds complexity without solving core issues
|
||
|
|
|
||
|
|
### 8.4 Unity's Initialization System (InitializeOnLoad)
|
||
|
|
**Rejected Reason:** Editor-only, doesn't solve runtime lifecycle ordering
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 9. Incremental Extension Path
|
||
|
|
|
||
|
|
If future needs arise, the Streamlined ManagedBehaviour can be extended:
|
||
|
|
|
||
|
|
**Phase 2 Additions** (if needed later):
|
||
|
|
- Add `OnSceneReady()` / `OnSceneUnloading()` hooks
|
||
|
|
- Automatic scene tracking based on GameObject.scene
|
||
|
|
- Priority-based scene lifecycle
|
||
|
|
|
||
|
|
**Phase 3 Additions** (if needed later):
|
||
|
|
- Add `OnManagedUpdate()` / `OnManagedFixedUpdate()`
|
||
|
|
- Opt-in via LifecycleFlags
|
||
|
|
- Performance profiling required
|
||
|
|
|
||
|
|
**Phase 4 Additions** (if needed later):
|
||
|
|
- Add `OnPaused()` / `OnResumed()` hooks
|
||
|
|
- Integrate with GameManager pause system
|
||
|
|
- Alternative to IPausable interface
|
||
|
|
|
||
|
|
**Key Principle:** Start simple, extend only when proven necessary
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 10. Recommendation Summary
|
||
|
|
|
||
|
|
### Primary Recommendation: ✅ APPROVE Option B+ (Streamlined ManagedBehaviour with Scene Orchestration)
|
||
|
|
|
||
|
|
**Rationale:**
|
||
|
|
1. **Solves critical problems** - Lifecycle confusion, memory leaks, registration burden, scene orchestration
|
||
|
|
2. **Appropriate scope** - 8 days for complete implementation, migration, and cleanup
|
||
|
|
3. **Low risk** - Incremental migration, clear patterns, well-tested approach
|
||
|
|
4. **Extensible** - Can add features later if needed
|
||
|
|
5. **Team-friendly** - Clear API, good examples, comprehensive migration guide
|
||
|
|
6. **End Goal Achievable** - Complete removal of BootCompletionService and legacy patterns
|
||
|
|
|
||
|
|
**Deliverables:**
|
||
|
|
- LifecycleManager (singleton in BootstrapScene)
|
||
|
|
- ManagedBehaviour base class with 4 lifecycle hooks
|
||
|
|
- ManagedEventSubscription system for auto-cleanup
|
||
|
|
- Enhanced SceneManagerService with orchestrated transitions
|
||
|
|
- Extended SaveLoadManager/GameManager with auto-registration
|
||
|
|
- Migration guide and examples
|
||
|
|
- 20+ components migrated
|
||
|
|
- BootCompletionService completely removed
|
||
|
|
|
||
|
|
**Deprecation Strategy:**
|
||
|
|
1. **Phase 1-2:** BootCompletionService triggers LifecycleManager (adapter pattern)
|
||
|
|
2. **Phase 3:** Scene orchestration integrated into SceneManagerService
|
||
|
|
3. **Phase 4:** All components migrated, BootCompletionService removed
|
||
|
|
4. **End State:** LifecycleManager as single source of truth
|
||
|
|
|
||
|
|
**Next Steps if Approved:**
|
||
|
|
1. Create feature branch `feature/managed-behaviour`
|
||
|
|
2. Implement core infrastructure (Days 1-2)
|
||
|
|
3. Integration with existing systems (Day 3)
|
||
|
|
4. Scene orchestration (Days 4-5)
|
||
|
|
5. Migration (Days 6-7)
|
||
|
|
6. Cleanup and BootCompletionService removal (Day 8)
|
||
|
|
7. Code review and testing
|
||
|
|
8. Merge to main
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 11. Questions for Technical Review
|
||
|
|
|
||
|
|
1. **Do you agree with the recommended scope?** (Streamlined vs Full)
|
||
|
|
2. **Should we migrate all 20+ components immediately or incrementally?**
|
||
|
|
3. **Any specific components that should NOT be migrated?**
|
||
|
|
4. **Should we create automated migration tools or manual migration?**
|
||
|
|
5. **Any additional lifecycle hooks needed for specific game systems?**
|
||
|
|
6. **Performance profiling required before or after implementation?**
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 12. References
|
||
|
|
|
||
|
|
- Original Proposal: `managed_bejavior.md`
|
||
|
|
- Bootstrap Documentation: `bootstrap_readme.md`
|
||
|
|
- Current BootCompletionService: `Assets/Scripts/Bootstrap/BootCompletionService.cs`
|
||
|
|
- Current GameManager: `Assets/Scripts/Core/GameManager.cs`
|
||
|
|
- Current SaveLoadManager: `Assets/Scripts/Core/SaveLoad/SaveLoadManager.cs`
|
||
|
|
- Current SceneManagerService: `Assets/Scripts/Core/SceneManagerService.cs`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Appendix A: Code Impact Analysis
|
||
|
|
|
||
|
|
### Files Using InitializePostBoot Pattern (20 files)
|
||
|
|
```
|
||
|
|
UI/Core/UIPageController.cs
|
||
|
|
UI/LoadingScreenController.cs
|
||
|
|
UI/CardSystem/CardAlbumUI.cs
|
||
|
|
UI/CardSystem/CardSystemSceneVisibility.cs
|
||
|
|
UI/PauseMenu.cs
|
||
|
|
Dialogue/DialogueComponent.cs
|
||
|
|
Sound/AudioManager.cs
|
||
|
|
Movement/FollowerController.cs
|
||
|
|
PuzzleS/PuzzleManager.cs
|
||
|
|
Levels/MinigameSwitch.cs
|
||
|
|
Core/GameManager.cs
|
||
|
|
Core/SceneManagerService.cs
|
||
|
|
Core/SaveLoad/SaveLoadManager.cs
|
||
|
|
+ others
|
||
|
|
```
|
||
|
|
|
||
|
|
### Files Implementing ISaveParticipant (6 files)
|
||
|
|
```
|
||
|
|
PuzzleS/PuzzleManager.cs
|
||
|
|
Movement/FollowerController.cs
|
||
|
|
Input/PlayerTouchController.cs
|
||
|
|
Interactions/SaveableInteractable.cs
|
||
|
|
Data/CardSystem/CardSystemManager.cs
|
||
|
|
Core/SaveLoad/AppleMachine.cs
|
||
|
|
```
|
||
|
|
|
||
|
|
### Files Implementing IPausable (10+ files)
|
||
|
|
```
|
||
|
|
Sound/AudioManager.cs
|
||
|
|
Minigames/DivingForPictures/Player/PlayerController.cs
|
||
|
|
Minigames/DivingForPictures/DivingGameManager.cs
|
||
|
|
Minigames/DivingForPictures/Utilities/RockPauser.cs
|
||
|
|
Minigames/DivingForPictures/Tiles/TrenchTileSpawner.cs
|
||
|
|
+ others
|
||
|
|
```
|
||
|
|
|
||
|
|
**Total Estimated Migration:** ~25-30 files affected
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Appendix B: Performance Considerations
|
||
|
|
|
||
|
|
### Overhead Analysis (Streamlined ManagedBehaviour)
|
||
|
|
|
||
|
|
**Per-Component Cost:**
|
||
|
|
- Registration: One-time O(log n) insertion into sorted list (~microseconds)
|
||
|
|
- ManagedAwake broadcast: Once per component at boot (~milliseconds total)
|
||
|
|
- BootComplete broadcast: Once per component at boot (~milliseconds total)
|
||
|
|
- Event subscription tracking: Minimal memory overhead per subscription
|
||
|
|
- Unregistration: One-time O(n) removal (~microseconds)
|
||
|
|
|
||
|
|
**Total Overhead:** < 1% frame time at boot, zero overhead during game loop
|
||
|
|
|
||
|
|
**Full ManagedBehaviour Would Add:**
|
||
|
|
- OnManagedUpdate broadcast: Every frame, O(n) iteration
|
||
|
|
- OnManagedFixedUpdate broadcast: Every physics frame, O(n) iteration
|
||
|
|
- This is why we exclude it from the recommended approach
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Approval
|
||
|
|
|
||
|
|
**Awaiting Technical Review Team Decision**
|
||
|
|
|
||
|
|
Please review and approve/reject/request modifications for this proposal.
|
||
|
|
|
||
|
|
**Prepared by:** System Architect
|
||
|
|
**Review Requested:** November 3, 2025
|
||
|
|
**Decision Deadline:** [TBD]
|
||
|
|
|