4.7 KiB
Critical Bug Fix: Missing base.Awake() Calls
The Bug
When we added custom Awake() methods to singleton managers using the new keyword to hide the base class method, we forgot to call base.Awake(), which prevented ManagedBehaviour from registering components with LifecycleManager.
Root Cause
// BROKEN - Missing base.Awake() call
private new void Awake()
{
_instance = this;
// ... initialization
}
// ❌ ManagedBehaviour.Awake() NEVER CALLED!
// ❌ LifecycleManager.Register() NEVER CALLED!
// ❌ OnManagedAwake() NEVER INVOKED!
What should have happened:
ManagedBehaviour.Awake()registers component with LifecycleManager- LifecycleManager broadcasts
OnManagedAwake()after boot completion - Component receives lifecycle callbacks
What actually happened:
- Custom
Awake()hides base implementation - Component never registers with LifecycleManager
OnManagedAwake()never called ❌
The Fix
Added base.Awake() as the FIRST line in every custom Awake() method:
// FIXED - Calls base.Awake() to register
private new void Awake()
{
base.Awake(); // CRITICAL: Register with LifecycleManager!
_instance = this;
// ... initialization
}
// ✅ ManagedBehaviour.Awake() called!
// ✅ LifecycleManager.Register() called!
// ✅ OnManagedAwake() will be invoked!
Files Fixed (14 Total)
Core Systems
- ✅ GameManager.cs (Priority 10)
- ✅ SceneManagerService.cs (Priority 15)
- ✅ SaveLoadManager.cs (Priority 20)
- ✅ QuickAccess.cs (Priority 5)
Infrastructure
- ✅ InputManager.cs (Priority 25)
- ✅ AudioManager.cs (Priority 30)
- ✅ LoadingScreenController.cs (Priority 45)
- ✅ UIPageController.cs (Priority 50)
- ✅ PauseMenu.cs (Priority 55)
- ✅ SceneOrientationEnforcer.cs (Priority 70)
Game Systems
- ✅ ItemManager.cs (Priority 75)
- ✅ PuzzleManager.cs (Priority 80)
- ✅ CinematicsManager.cs (Priority 170)
- ✅ CardSystemManager.cs (Priority 60)
Impact
Before Fix ❌
- Singleton instances were set (
_instance = this) ✅ - Settings were initialized ✅
- BUT: Components never registered with LifecycleManager ❌
- Result:
OnManagedAwake()never called ❌ - Result: No lifecycle hooks (OnSceneReady, OnSceneUnloading, etc.) ❌
- Result: Auto-registration features (IPausable, etc.) broken ❌
After Fix ✅
- Singleton instances set ✅
- Settings initialized ✅
- Components registered with LifecycleManager ✅
OnManagedAwake()called in priority order ✅- All lifecycle hooks working ✅
- Auto-registration features working ✅
Why This Happened
When we moved singleton instance assignment from OnManagedAwake() to Awake(), we used the new keyword to hide the base class Awake method. However, hiding is not the same as overriding:
// Hiding (new) - base method NOT called automatically
private new void Awake() { }
// Overriding (override) - base method NOT called automatically
protected override void Awake() { }
// Both require EXPLICIT base.Awake() call!
We correctly used new (since ManagedBehaviour.Awake() is not virtual), but forgot to explicitly call base.Awake().
The Correct Pattern
For any ManagedBehaviour with a custom Awake():
public class MyManager : ManagedBehaviour
{
private static MyManager _instance;
public static MyManager Instance => _instance;
public override int ManagedAwakePriority => 50;
private new void Awake()
{
base.Awake(); // ✅ ALWAYS CALL THIS FIRST!
_instance = this;
// ... other early initialization
}
protected override void OnManagedAwake()
{
// Lifecycle hooks work now!
}
}
Testing Checklist
To verify the fix works:
- All files compile without errors
- Run from StartingScene - verify boot sequence works
- Check console for
[LifecycleManager] Registered [ComponentName]messages - Verify OnManagedAwake() logs appear (e.g., "XAXA" from LevelSwitch)
- Test scene switching - verify lifecycle hooks fire
- Test pause system - verify IPausable auto-registration works
- Test save/load - verify ISaveParticipant integration works
Key Lesson
When hiding a base class method with new, you MUST explicitly call the base implementation if you need its functionality!
// WRONG ❌
private new void Awake()
{
// Missing base.Awake()
}
// CORRECT ✅
private new void Awake()
{
base.Awake(); // Explicitly call base!
// ... custom logic
}
Status: ✅ FIXED - All 14 managers now properly call base.Awake() to ensure LifecycleManager registration!