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

293 lines
8.9 KiB
Markdown

# Bootstrapped Manager Initialization Review - Summary
## Overview
Performed a comprehensive review of all bootstrapped singleton managers to ensure critical initialization happens in `Awake()` rather than `OnManagedAwake()`, making infrastructure available when other components' `OnManagedAwake()` runs.
## Key Principle
**Awake() = Infrastructure Setup**
- Singleton instance registration
- Critical service initialization (settings, scene tracking, input setup)
- Component configuration
- State that OTHER components depend on
**OnManagedAwake() = Dependent Initialization**
- Initialization that depends on OTHER managers
- Event subscriptions to other managers
- Non-critical setup
## Managers Updated
### 1. GameManager (Priority 10) ✅
**Moved to Awake():**
- Settings provider creation
- Settings initialization (InitializeSettings, InitializeDeveloperSettings)
- Verbosity settings loading
**Rationale:** Other managers need settings in their OnManagedAwake(). Settings MUST be available early.
**Impact:** All other managers can now safely call `GameManager.GetSettingsObject<T>()` in their OnManagedAwake().
```csharp
private new void Awake()
{
_instance = this;
// Create settings providers - CRITICAL for other managers
SettingsProvider.Instance.gameObject.name = "Settings Provider";
DeveloperSettingsProvider.Instance.gameObject.name = "Developer Settings Provider";
// Load all settings synchronously - CRITICAL infrastructure
InitializeSettings();
InitializeDeveloperSettings();
_settingsLogVerbosity = DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>().settingsLogVerbosity;
_managerLogVerbosity = DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>().gameManagerLogVerbosity;
}
```
### 2. SceneManagerService (Priority 15) ✅
**Moved to Awake():**
- Scene tracking initialization (InitializeCurrentSceneTracking)
- Bootstrap scene loading
**Kept in OnManagedAwake():**
- Loading screen reference (depends on LoadingScreenController instance)
- Event setup (depends on loading screen)
- Verbosity settings
**Rationale:** Scene tracking is critical state. Loading screen setup depends on LoadingScreenController's instance being set first.
```csharp
private new void Awake()
{
_instance = this;
// Initialize current scene tracking - CRITICAL for scene management
InitializeCurrentSceneTracking();
// Ensure BootstrapScene is loaded
var bootstrap = SceneManager.GetSceneByName(BootstrapSceneName);
if (!bootstrap.isLoaded)
{
SceneManager.LoadScene(BootstrapSceneName, LoadSceneMode.Additive);
}
}
protected override void OnManagedAwake()
{
// DEPENDS on LoadingScreenController instance
_loadingScreen = LoadingScreenController.Instance;
SetupLoadingScreenEvents();
_logVerbosity = DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>().sceneLogVerbosity;
}
```
### 3. InputManager (Priority 25) ✅
**Moved to Awake():**
- Verbosity settings loading
- Settings reference initialization
- PlayerInput component setup
- Input action subscriptions
- Initial input mode setup
**Kept in OnManagedAwake():**
- SceneManagerService event subscriptions (depends on SceneManagerService instance)
**Rationale:** Input system MUST be functional immediately. Event subscriptions to other managers wait until OnManagedAwake().
```csharp
private new void Awake()
{
_instance = this;
// Load settings early (GameManager sets these up in its Awake)
_logVerbosity = DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>().inputLogVerbosity;
_interactionSettings = GameManager.GetSettingsObject<IInteractionSettings>();
// Set up PlayerInput component and actions - CRITICAL for input to work
playerInput = GetComponent<PlayerInput>();
// ... set up actions and subscriptions
// Initialize input mode for current scene
SwitchInputOnSceneLoaded(SceneManager.GetActiveScene().name);
}
protected override void OnManagedAwake()
{
// DEPENDS on SceneManagerService instance
if (SceneManagerService.Instance != null)
{
SceneManagerService.Instance.SceneLoadCompleted += OnSceneLoadCompleted;
}
}
```
### 4. SaveLoadManager (Priority 20) ✅
**Moved to Awake():**
- Critical state initialization (IsSaveDataLoaded, IsRestoringState)
**Kept in OnManagedAwake():**
- Discovery of saveables
- Loading save data (depends on settings)
**Rationale:** State flags should be initialized immediately. Discovery and loading depend on settings and scene state.
```csharp
private new void Awake()
{
_instance = this;
// Initialize critical state immediately
IsSaveDataLoaded = false;
IsRestoringState = false;
}
protected override void OnManagedAwake()
{
// Discovery and loading depend on settings and scene state
DiscoverInactiveSaveables("RestoreInEditor");
if (DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>().useSaveLoadSystem)
{
Load();
}
}
```
### 5. LoadingScreenController (Priority 45) ✅
**Moved to Awake():**
- Container reference setup
- Initial state (hidden, inactive)
**Rationale:** SceneManagerService (priority 15) needs to access LoadingScreenController.Instance in its OnManagedAwake(). The loading screen MUST be properly configured before that.
```csharp
private new void Awake()
{
_instance = this;
// Set up container reference early
if (loadingScreenContainer == null)
loadingScreenContainer = gameObject;
// Ensure the loading screen is initially hidden
if (loadingScreenContainer != null)
{
loadingScreenContainer.SetActive(false);
}
}
```
### 6. PauseMenu (Priority 55) ✅
**Moved to Awake():**
- CanvasGroup component setup
- Initial state (hidden, non-interactive)
**Kept in OnSceneReady():**
- Event subscriptions to SceneManagerService and UIPageController
**Rationale:** Component configuration should happen immediately. Event subscriptions wait for scene ready.
### 7. SceneOrientationEnforcer (Priority 70) ✅
**Moved to Awake():**
- Verbosity settings loading
- Scene loaded event subscription
- Initial orientation enforcement
**Rationale:** Orientation enforcement should start immediately when scenes load.
## Critical Dependencies Resolved
### Before This Review
```
SceneManagerService.OnManagedAwake() → tries to access LoadingScreenController.Instance
→ NULL if LoadingScreenController.OnManagedAwake() hasn't run yet!
```
### After This Review
```
All Awake() methods run (order doesn't matter):
- GameManager.Awake() → Sets up settings
- SceneManagerService.Awake() → Sets up scene tracking
- InputManager.Awake() → Sets up input system
- LoadingScreenController.Awake() → Sets up loading screen
- etc.
Then OnManagedAwake() runs in priority order:
- GameManager.OnManagedAwake() (10)
- SceneManagerService.OnManagedAwake() (15) → LoadingScreenController.Instance is GUARANTEED available
- InputManager.OnManagedAwake() (25) → SceneManagerService.Instance is GUARANTEED available
- etc.
```
## Design Guidelines Established
### What Goes in Awake()
1. ✅ Singleton instance assignment (`_instance = this`)
2. ✅ Critical infrastructure (settings, scene tracking)
3. ✅ Component setup (`GetComponent`, initial state)
4. ✅ State initialization that others depend on
5. ✅ Subscriptions to Unity events (SceneManager.sceneLoaded)
### What Goes in OnManagedAwake()
1. ✅ Event subscriptions to OTHER managers
2. ✅ Initialization that depends on settings
3. ✅ Non-critical setup
4. ✅ Logging (depends on settings)
### What Stays in OnSceneReady()
1. ✅ Scene-specific initialization
2. ✅ Event subscriptions that are scene-dependent
## Compilation Status
**No compilation errors**
⚠️ **Only pre-existing naming convention warnings**
## Impact
### Before
- Race conditions possible if managers accessed each other's instances
- Settings might not be available when needed
- Input system might not be configured when accessed
- Loading screen might not be set up when SceneManagerService needs it
### After
- All critical infrastructure guaranteed available in OnManagedAwake()
- Settings always available for all managers
- Input system always functional
- Loading screen always configured
- Clean separation: Awake = infrastructure, OnManagedAwake = orchestration
## Testing Recommendations
1. ✅ Test boot sequence from StartingScene
2. ✅ Test level switching via LevelSwitch
3. ✅ Verify loading screen shows correctly
4. ✅ Verify input works after scene loads
5. ✅ Check console for any null reference exceptions
## Files Modified
1. GameManager.cs
2. SceneManagerService.cs
3. InputManager.cs
4. SaveLoadManager.cs
5. LoadingScreenController.cs
6. PauseMenu.cs
7. SceneOrientationEnforcer.cs
---
**Status**: ✅ COMPLETE - All bootstrapped managers properly initialized with correct Awake/OnManagedAwake separation