Final touchups to the lifecycle management

This commit is contained in:
Michal Pikulski
2025-11-11 10:53:09 +01:00
parent 0aa2270e1a
commit 9a6914b9bd
38 changed files with 62 additions and 229 deletions

View File

@@ -30,8 +30,6 @@ namespace Bootstrap
private float _sceneLoadingProgress = 0f; private float _sceneLoadingProgress = 0f;
private LogVerbosity _logVerbosity = LogVerbosity.Warning; private LogVerbosity _logVerbosity = LogVerbosity.Warning;
// Run very early - need to set up loading screen before other systems initialize
public override int ManagedAwakePriority => 5;
internal override void OnManagedAwake() internal override void OnManagedAwake()
{ {
@@ -83,10 +81,8 @@ namespace Bootstrap
Invoke(nameof(StartLoadingMainMenu), minDelayAfterBoot); Invoke(nameof(StartLoadingMainMenu), minDelayAfterBoot);
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
base.OnDestroy();
// Manual cleanup for events // Manual cleanup for events
if (initialLoadingScreen != null) if (initialLoadingScreen != null)
{ {

View File

@@ -37,8 +37,6 @@ namespace Cinematics
public PlayableDirector playableDirector; public PlayableDirector playableDirector;
public override int ManagedAwakePriority => 170; // Cinematic systems
internal override void OnManagedAwake() internal override void OnManagedAwake()
{ {
// Set instance immediately (early initialization) // Set instance immediately (early initialization)

View File

@@ -15,8 +15,6 @@ namespace Cinematics
private float _holdStartTime; private float _holdStartTime;
private bool _isHolding; private bool _isHolding;
private bool _skipPerformed; private bool _skipPerformed;
public override int ManagedAwakePriority => 180; // Cinematic UI
internal override void OnManagedStart() internal override void OnManagedStart()
{ {
@@ -32,10 +30,8 @@ namespace Cinematics
Logging.Debug("[SkipCinematic] Initialized"); Logging.Debug("[SkipCinematic] Initialized");
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
base.OnDestroy();
// Clean up subscriptions // Clean up subscriptions
UnsubscribeFromCinematicsEvents(); UnsubscribeFromCinematicsEvents();
} }

View File

@@ -34,8 +34,6 @@ namespace Core
public event Action OnGamePaused; public event Action OnGamePaused;
public event Action OnGameResumed; public event Action OnGameResumed;
// ManagedBehaviour configuration
public override int ManagedAwakePriority => 10; // Core infrastructure - runs early
internal override void OnManagedAwake() internal override void OnManagedAwake()
{ {

View File

@@ -47,8 +47,6 @@ namespace Core
// Broadcasts when any two items are successfully combined // Broadcasts when any two items are successfully combined
// Args: first item data, second item data, result item data // Args: first item data, second item data, result item data
public event Action<PickupItemData, PickupItemData, PickupItemData> OnItemsCombined; public event Action<PickupItemData, PickupItemData, PickupItemData> OnItemsCombined;
public override int ManagedAwakePriority => 75; // Item registry
internal override void OnManagedAwake() internal override void OnManagedAwake()
{ {
@@ -67,10 +65,8 @@ namespace Core
ClearAllRegistrations(); ClearAllRegistrations();
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
base.OnDestroy();
// Ensure we clean up any subscriptions from registered items when the manager is destroyed // Ensure we clean up any subscriptions from registered items when the manager is destroyed
ClearAllRegistrations(); ClearAllRegistrations();
} }

View File

@@ -6,12 +6,19 @@
/// </summary> /// </summary>
public enum LifecyclePhase public enum LifecyclePhase
{ {
/// <summary>
/// Called immediately during registration (during Awake).
/// Use for early initialization such as setting singleton instances.
/// NOT ordered - fires whenever Unity calls this component's Awake().
/// </summary>
ManagedAwake,
/// <summary> /// <summary>
/// Called once per component after bootstrap completes. /// Called once per component after bootstrap completes.
/// Guaranteed to be called after all bootstrap resources are loaded. /// Guaranteed to be called after all bootstrap resources are loaded.
/// For late-registered components, called immediately upon registration. /// For late-registered components, called immediately upon registration.
/// </summary> /// </summary>
ManagedAwake, ManagedStart,
/// <summary> /// <summary>
/// Called before a scene is unloaded. /// Called before a scene is unloaded.

View File

@@ -59,11 +59,11 @@ namespace Core.Lifecycle
#region State Flags #region State Flags
private bool isBootComplete = false; private bool isBootComplete;
private string currentSceneReady = ""; private string currentSceneReady = "";
// Scene loading state tracking // Scene loading state tracking
private bool isLoadingScene = false; private bool isLoadingScene;
private string sceneBeingLoaded = ""; private string sceneBeingLoaded = "";
private List<ManagedBehaviour> pendingSceneComponents = new List<ManagedBehaviour>(); private List<ManagedBehaviour> pendingSceneComponents = new List<ManagedBehaviour>();
@@ -120,17 +120,13 @@ namespace Core.Lifecycle
// Track which scene this component belongs to // Track which scene this component belongs to
componentScenes[component] = sceneName; componentScenes[component] = sceneName;
// ALWAYS add to managedAwakeList - this is the master list used for save/load // Add to all lifecycle lists (order of registration determines execution order)
InsertSorted(managedAwakeList, component, component.ManagedAwakePriority); managedAwakeList.Add(component);
sceneUnloadingList.Add(component);
// Register for all scene lifecycle hooks sceneReadyList.Add(component);
InsertSorted(sceneUnloadingList, component, component.SceneUnloadingPriority); saveRequestedList.Add(component);
InsertSorted(sceneReadyList, component, component.SceneReadyPriority); restoreRequestedList.Add(component);
InsertSorted(saveRequestedList, component, component.SavePriority); destroyList.Add(component);
InsertSorted(restoreRequestedList, component, component.RestorePriority);
InsertSorted(destroyList, component, component.DestroyPriority);
// Call OnManagedAwake immediately after registration (early initialization hook)
try try
{ {
component.OnManagedAwake(); component.OnManagedAwake();
@@ -146,7 +142,7 @@ namespace Core.Lifecycle
// Check if we're currently loading a scene // Check if we're currently loading a scene
if (isLoadingScene && sceneName == sceneBeingLoaded) if (isLoadingScene && sceneName == sceneBeingLoaded)
{ {
// Batch this component - will be processed in priority order when scene load completes // Batch this component - will be processed when scene load completes
pendingSceneComponents.Add(component); pendingSceneComponents.Add(component);
LogDebug($"Batched component for scene load: {component.gameObject.name} (Scene: {sceneName})"); LogDebug($"Batched component for scene load: {component.gameObject.name} (Scene: {sceneName})");
} }
@@ -282,10 +278,7 @@ namespace Core.Lifecycle
LogDebug($"Processing {pendingSceneComponents.Count} batched components for scene: {sceneBeingLoaded}"); LogDebug($"Processing {pendingSceneComponents.Count} batched components for scene: {sceneBeingLoaded}");
// Sort by ManagedAwake priority (lower values first) // Call OnManagedStart in registration order
pendingSceneComponents.Sort((a, b) => a.ManagedAwakePriority.CompareTo(b.ManagedAwakePriority));
// Call OnManagedStart in priority order
foreach (var component in pendingSceneComponents) foreach (var component in pendingSceneComponents)
{ {
if (component == null) continue; if (component == null) continue;
@@ -294,7 +287,7 @@ namespace Core.Lifecycle
{ {
component.OnManagedStart(); component.OnManagedStart();
HandleAutoRegistrations(component); HandleAutoRegistrations(component);
LogDebug($"Processed batched component: {component.gameObject.name} (Priority: {component.ManagedAwakePriority})"); LogDebug($"Processed batched component: {component.gameObject.name}");
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -309,7 +302,7 @@ namespace Core.Lifecycle
} }
/// <summary> /// <summary>
/// Broadcast OnSceneUnloading to components in the specified scene (reverse priority order). /// Broadcast OnSceneUnloading to components in the specified scene.
/// </summary> /// </summary>
public void BroadcastSceneUnloading(string sceneName) public void BroadcastSceneUnloading(string sceneName)
{ {
@@ -336,8 +329,8 @@ namespace Core.Lifecycle
} }
/// <summary> /// <summary>
/// Broadcast OnSceneReady to components in the specified scene (priority order). /// Broadcast OnSceneReady to components in the specified scene.
/// If scene loading mode is active, processes batched components first. /// Processes batched components first, then calls OnSceneReady on all components in that scene.
/// </summary> /// </summary>
public void BroadcastSceneReady(string sceneName) public void BroadcastSceneReady(string sceneName)
{ {
@@ -621,42 +614,6 @@ namespace Core.Lifecycle
#endregion #endregion
#region Helper Methods #region Helper Methods
/// <summary>
/// Insert component into list maintaining sorted order by priority.
/// Uses binary search for efficient insertion.
/// </summary>
private void InsertSorted(List<ManagedBehaviour> list, ManagedBehaviour component, int priority)
{
// Simple linear insertion for now (can optimize with binary search later if needed)
int index = 0;
for (int i = 0; i < list.Count; i++)
{
int existingPriority = GetPriorityForList(list[i], list);
if (priority < existingPriority)
{
index = i;
break;
}
index = i + 1;
}
list.Insert(index, component);
}
/// <summary>
/// Get the priority value for a component based on which list it's in.
/// </summary>
private int GetPriorityForList(ManagedBehaviour component, List<ManagedBehaviour> list)
{
if (list == managedAwakeList) return component.ManagedAwakePriority;
if (list == sceneUnloadingList) return component.SceneUnloadingPriority;
if (list == sceneReadyList) return component.SceneReadyPriority;
if (list == saveRequestedList) return component.SavePriority;
if (list == restoreRequestedList) return component.RestorePriority;
if (list == destroyList) return component.DestroyPriority;
return 100;
}
/// <summary> /// <summary>
/// Log debug message if debug logging is enabled. /// Log debug message if debug logging is enabled.

View File

@@ -8,46 +8,6 @@ namespace Core.Lifecycle
/// </summary> /// </summary>
public abstract class ManagedBehaviour : MonoBehaviour public abstract class ManagedBehaviour : MonoBehaviour
{ {
#region Priority Properties
/// <summary>
/// Priority for OnManagedStart (lower values execute first).
/// Default: 100
/// </summary>
public virtual int ManagedAwakePriority => 100;
/// <summary>
/// Priority for OnSceneUnloading (executed in reverse: higher values execute first).
/// Default: 100
/// </summary>
public virtual int SceneUnloadingPriority => 100;
/// <summary>
/// Priority for OnSceneReady (lower values execute first).
/// Default: 100
/// </summary>
public virtual int SceneReadyPriority => 100;
/// <summary>
/// Priority for OnSaveRequested (executed in reverse: higher values execute first).
/// Default: 100
/// </summary>
public virtual int SavePriority => 100;
/// <summary>
/// Priority for OnRestoreRequested (lower values execute first).
/// Default: 100
/// </summary>
public virtual int RestorePriority => 100;
/// <summary>
/// Priority for OnManagedDestroy (executed in reverse: higher values execute first).
/// Default: 100
/// </summary>
public virtual int DestroyPriority => 100;
#endregion
#region Configuration Properties #region Configuration Properties
/// <summary> /// <summary>
@@ -67,14 +27,19 @@ namespace Core.Lifecycle
/// Unique identifier for this component in the save system. /// Unique identifier for this component in the save system.
/// Default: "SceneName/GameObjectName/ComponentType" /// Default: "SceneName/GameObjectName/ComponentType"
/// Override ONLY for special cases (e.g., singletons like "PlayerController", or custom IDs). /// Override ONLY for special cases (e.g., singletons like "PlayerController", or custom IDs).
/// Cached on first access to avoid runtime allocation.
/// </summary> /// </summary>
public virtual string SaveId public virtual string SaveId
{ {
get get
{ {
string sceneName = gameObject.scene.IsValid() ? gameObject.scene.name : "UnknownScene"; if (_cachedSaveId == null)
string componentType = GetType().Name; {
return $"{sceneName}/{gameObject.name}/{componentType}"; string sceneName = gameObject.scene.IsValid() ? gameObject.scene.name : "UnknownScene";
string componentType = GetType().Name;
_cachedSaveId = $"{sceneName}/{gameObject.name}/{componentType}";
}
return _cachedSaveId;
} }
} }
@@ -83,6 +48,7 @@ namespace Core.Lifecycle
#region Private Fields #region Private Fields
private bool _isRegistered; private bool _isRegistered;
private string _cachedSaveId;
#endregion #endregion
@@ -107,13 +73,16 @@ namespace Core.Lifecycle
/// <summary> /// <summary>
/// Unity OnDestroy - automatically unregisters and cleans up. /// Unity OnDestroy - automatically unregisters and cleans up.
/// IMPORTANT: Derived classes that override OnDestroy MUST call base.OnDestroy() /// SEALED: Cannot be overridden. Use OnManagedDestroy() for custom cleanup logic.
/// </summary> /// </summary>
protected virtual void OnDestroy() private void OnDestroy()
{ {
if (!_isRegistered) if (!_isRegistered)
return; return;
// Call managed destroy hook
OnManagedDestroy();
// Unregister from LifecycleManager // Unregister from LifecycleManager
if (LifecycleManager.Instance != null) if (LifecycleManager.Instance != null)
{ {
@@ -149,7 +118,7 @@ namespace Core.Lifecycle
/// <summary> /// <summary>
/// Called once per component after bootstrap completes. /// Called once per component after bootstrap completes.
/// GUARANTEE: Bootstrap resources are available, all managers are initialized. /// GUARANTEE: Bootstrap resources are available, all managers are initialized.
/// For boot-time components: Called during LifecycleManager.BroadcastManagedStart (priority ordered). /// For boot-time components: Called during LifecycleManager.BroadcastManagedStart (registration order).
/// For late-registered components: Called immediately upon registration (bootstrap already complete). /// For late-registered components: Called immediately upon registration (bootstrap already complete).
/// Use for initialization that depends on other systems. /// Use for initialization that depends on other systems.
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes. /// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
@@ -161,7 +130,6 @@ namespace Core.Lifecycle
/// <summary> /// <summary>
/// Called before the scene this component belongs to is unloaded. /// Called before the scene this component belongs to is unloaded.
/// Called in REVERSE priority order (higher values execute first).
/// Use for scene-specific cleanup. /// Use for scene-specific cleanup.
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes. /// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
/// </summary> /// </summary>
@@ -172,7 +140,6 @@ namespace Core.Lifecycle
/// <summary> /// <summary>
/// Called after the scene this component belongs to has finished loading. /// Called after the scene this component belongs to has finished loading.
/// Called in priority order (lower values execute first).
/// Use for scene-specific initialization. /// Use for scene-specific initialization.
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes. /// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
/// </summary> /// </summary>
@@ -312,7 +279,6 @@ namespace Core.Lifecycle
/// <summary> /// <summary>
/// Called during OnDestroy before component is destroyed. /// Called during OnDestroy before component is destroyed.
/// Called in REVERSE priority order (higher values execute first).
/// NOTE: Most cleanup is automatic (managed events, auto-registrations). /// NOTE: Most cleanup is automatic (managed events, auto-registrations).
/// Only override if you need custom cleanup logic. /// Only override if you need custom cleanup logic.
/// Internal visibility allows LifecycleManager to call directly. Override in derived classes. /// Internal visibility allows LifecycleManager to call directly. Override in derived classes.

View File

@@ -24,9 +24,6 @@ namespace AppleHills.Core
#endregion Singleton Setup #endregion Singleton Setup
// Very early initialization - QuickAccess should be available immediately
public override int ManagedAwakePriority => 5;
#region Manager Instances #region Manager Instances
// Core Managers // Core Managers

View File

@@ -43,8 +43,6 @@ namespace Core.SaveLoad
public event Action<string> OnLoadCompleted; public event Action<string> OnLoadCompleted;
public event Action OnParticipantStatesRestored; public event Action OnParticipantStatesRestored;
// ManagedBehaviour configuration
public override int ManagedAwakePriority => 20; // After GameManager and SceneManagerService
internal override void OnManagedAwake() internal override void OnManagedAwake()
{ {
@@ -95,10 +93,8 @@ namespace Core.SaveLoad
// ...existing code... // ...existing code...
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
base.OnDestroy(); // Important: call base to unregister from LifecycleManager
if (_instance == this) if (_instance == this)
{ {
_instance = null; _instance = null;

View File

@@ -42,10 +42,8 @@ namespace Core
} }
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
base.OnDestroy();
if (_director != null) if (_director != null)
{ {
_director.stopped -= OnDirectorStopped; _director.stopped -= OnDirectorStopped;

View File

@@ -44,8 +44,6 @@ namespace Core
private LogVerbosity _logVerbosity = LogVerbosity.Debug; private LogVerbosity _logVerbosity = LogVerbosity.Debug;
private const string BootstrapSceneName = "BootstrapScene"; private const string BootstrapSceneName = "BootstrapScene";
// ManagedBehaviour configuration
public override int ManagedAwakePriority => 15; // Core infrastructure, after GameManager
internal override void OnManagedAwake() internal override void OnManagedAwake()
{ {
@@ -369,7 +367,7 @@ namespace Core
await LoadSceneAsync(newSceneName, progress); await LoadSceneAsync(newSceneName, progress);
CurrentGameplayScene = newSceneName; CurrentGameplayScene = newSceneName;
// PHASE 10: Broadcast scene ready - processes batched components in priority order, then calls OnSceneReady // PHASE 10: Broadcast scene ready - processes batched components, then calls OnSceneReady
Logging.Debug($"Broadcasting OnSceneReady for: {newSceneName}"); Logging.Debug($"Broadcasting OnSceneReady for: {newSceneName}");
LifecycleManager.Instance?.BroadcastSceneReady(newSceneName); LifecycleManager.Instance?.BroadcastSceneReady(newSceneName);

View File

@@ -18,9 +18,6 @@ namespace Core
public GameObject orientationPromptPrefab; public GameObject orientationPromptPrefab;
private LogVerbosity _logVerbosity = LogVerbosity.Warning; private LogVerbosity _logVerbosity = LogVerbosity.Warning;
// ManagedBehaviour configuration
public override int ManagedAwakePriority => 70; // Platform-specific utility
internal override void OnManagedAwake() internal override void OnManagedAwake()
{ {
// Set instance immediately (early initialization) // Set instance immediately (early initialization)
@@ -103,15 +100,13 @@ namespace Core
} }
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
// Unsubscribe from events to prevent memory leaks // Unsubscribe from events to prevent memory leaks
if (SceneManagerService.Instance != null) if (SceneManagerService.Instance != null)
{ {
SceneManagerService.Instance.SceneLoadCompleted -= OnSceneLoadCompleted; SceneManagerService.Instance.SceneLoadCompleted -= OnSceneLoadCompleted;
} }
base.OnDestroy(); // Important: call base
} }
/// <summary> /// <summary>

View File

@@ -43,8 +43,6 @@ namespace Data.CardSystem
public event Action<int> OnBoosterCountChanged; public event Action<int> OnBoosterCountChanged;
public event Action<CardData> OnPendingCardAdded; public event Action<CardData> OnPendingCardAdded;
public event Action<CardData> OnCardPlacedInAlbum; public event Action<CardData> OnCardPlacedInAlbum;
public override int ManagedAwakePriority => 60; // Data systems
internal override void OnManagedAwake() internal override void OnManagedAwake()
{ {

View File

@@ -32,9 +32,6 @@ namespace Dialogue
public bool IsCompleted { get; private set; } public bool IsCompleted { get; private set; }
public string CurrentSpeakerName => dialogueGraph?.speakerName; public string CurrentSpeakerName => dialogueGraph?.speakerName;
public override int ManagedAwakePriority => 150; // Dialogue systems
internal override void OnManagedStart() internal override void OnManagedStart()
{ {
// Get required components // Get required components
@@ -184,10 +181,8 @@ namespace Dialogue
return null; return null;
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
base.OnDestroy();
// Unregister from events // Unregister from events
if (PuzzleManager.Instance != null) if (PuzzleManager.Instance != null)
PuzzleManager.Instance.OnStepCompleted -= OnAnyPuzzleStepCompleted; PuzzleManager.Instance.OnStepCompleted -= OnAnyPuzzleStepCompleted;

View File

@@ -49,8 +49,6 @@ namespace Input
private ITouchInputConsumer defaultConsumer; private ITouchInputConsumer defaultConsumer;
private bool isHoldActive; private bool isHoldActive;
private LogVerbosity _logVerbosity = LogVerbosity.Warning; private LogVerbosity _logVerbosity = LogVerbosity.Warning;
public override int ManagedAwakePriority => 25; // Input infrastructure
internal override void OnManagedAwake() internal override void OnManagedAwake()
{ {
@@ -106,7 +104,7 @@ namespace Input
SwitchInputOnSceneLoaded(sceneName); SwitchInputOnSceneLoaded(sceneName);
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
// Unsubscribe from SceneManagerService events // Unsubscribe from SceneManagerService events
if (SceneManagerService.Instance != null) if (SceneManagerService.Instance != null)
@@ -114,7 +112,6 @@ namespace Input
SceneManagerService.Instance.SceneLoadCompleted -= OnSceneLoadCompleted; SceneManagerService.Instance.SceneLoadCompleted -= OnSceneLoadCompleted;
} }
base.OnDestroy();
// Input action cleanup happens automatically // Input action cleanup happens automatically
} }

View File

@@ -70,7 +70,6 @@ namespace Input
public override bool AutoRegisterForSave => true; public override bool AutoRegisterForSave => true;
// Scene-specific SaveId - each level has its own player state // Scene-specific SaveId - each level has its own player state
public override string SaveId => $"{gameObject.scene.name}/PlayerController"; public override string SaveId => $"{gameObject.scene.name}/PlayerController";
public override int ManagedAwakePriority => 100; // Player controller
internal override void OnManagedStart() internal override void OnManagedStart()
{ {

View File

@@ -41,9 +41,6 @@ namespace Interactions
// Action component system // Action component system
private List<InteractionActionBase> _registeredActions = new List<InteractionActionBase>(); private List<InteractionActionBase> _registeredActions = new List<InteractionActionBase>();
// ManagedBehaviour configuration
public override int ManagedAwakePriority => 100; // Gameplay base classes
/// <summary> /// <summary>
/// Register an action component with this interactable /// Register an action component with this interactable

View File

@@ -287,10 +287,8 @@ namespace Interactions
ItemManager.Instance?.RegisterItemSlot(this); ItemManager.Instance?.RegisterItemSlot(this);
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
base.OnDestroy();
// Unregister from slot manager // Unregister from slot manager
ItemManager.Instance?.UnregisterItemSlot(this); ItemManager.Instance?.UnregisterItemSlot(this);
} }

View File

@@ -50,10 +50,8 @@ namespace Interactions
ItemManager.Instance?.RegisterPickup(this); ItemManager.Instance?.RegisterPickup(this);
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
base.OnDestroy();
// Unregister from ItemManager // Unregister from ItemManager
ItemManager.Instance?.UnregisterPickup(this); ItemManager.Instance?.UnregisterPickup(this);
} }

View File

@@ -80,10 +80,8 @@ namespace Levels
} }
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
base.OnDestroy();
if (PuzzleManager.Instance != null) if (PuzzleManager.Instance != null)
{ {
PuzzleManager.Instance.OnAllPuzzlesComplete -= HandleAllPuzzlesComplete; PuzzleManager.Instance.OnAllPuzzlesComplete -= HandleAllPuzzlesComplete;

View File

@@ -104,7 +104,6 @@ namespace Minigames.DivingForPictures
public static DivingGameManager Instance => _instance; public static DivingGameManager Instance => _instance;
public override int ManagedAwakePriority => 190;
public override bool AutoRegisterPausable => true; // Automatic GameManager registration public override bool AutoRegisterPausable => true; // Automatic GameManager registration
internal override void OnManagedAwake() internal override void OnManagedAwake()
@@ -162,10 +161,8 @@ namespace Minigames.DivingForPictures
} }
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
base.OnDestroy(); // Handles auto-unregister from GameManager
// Unsubscribe from events when the manager is destroyed // Unsubscribe from events when the manager is destroyed
PlayerCollisionBehavior.OnDamageTaken -= OnPlayerDamageTaken; PlayerCollisionBehavior.OnDamageTaken -= OnPlayerDamageTaken;
OnMonsterSpawned -= DoMonsterSpawned; OnMonsterSpawned -= DoMonsterSpawned;

View File

@@ -106,8 +106,6 @@ public class FollowerController : ManagedBehaviour
private bool _hasRestoredHeldItem; // Track if held item restoration completed private bool _hasRestoredHeldItem; // Track if held item restoration completed
private string _expectedHeldItemSaveId; // Expected saveId during restoration private string _expectedHeldItemSaveId; // Expected saveId during restoration
public override int ManagedAwakePriority => 110; // Follower after player
internal override void OnManagedStart() internal override void OnManagedStart()
{ {
_aiPath = GetComponent<AIPath>(); _aiPath = GetComponent<AIPath>();

View File

@@ -83,10 +83,8 @@ namespace PuzzleS
} }
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
base.OnDestroy();
if (PuzzleManager.Instance != null && stepData != null) if (PuzzleManager.Instance != null && stepData != null)
{ {
PuzzleManager.Instance.UnregisterStepBehaviour(this); PuzzleManager.Instance.UnregisterStepBehaviour(this);

View File

@@ -93,8 +93,6 @@ namespace PuzzleS
// Track pending unlocks for steps that were unlocked before their behavior registered // Track pending unlocks for steps that were unlocked before their behavior registered
private HashSet<string> _pendingUnlocks = new HashSet<string>(); private HashSet<string> _pendingUnlocks = new HashSet<string>();
public override int ManagedAwakePriority => 80; // Puzzle systems
internal override void OnManagedAwake() internal override void OnManagedAwake()
{ {
@@ -138,10 +136,8 @@ namespace PuzzleS
LoadPuzzlesForScene(sceneName); LoadPuzzlesForScene(sceneName);
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
base.OnDestroy();
// Unsubscribe from SceneManagerService events // Unsubscribe from SceneManagerService events
if (SceneManagerService.Instance != null) if (SceneManagerService.Instance != null)
{ {

View File

@@ -40,8 +40,6 @@ public class AudioManager : ManagedBehaviour, IPausable
/// </summary> /// </summary>
public static AudioManager Instance => _instance; public static AudioManager Instance => _instance;
// ManagedBehaviour configuration
public override int ManagedAwakePriority => 30; // Audio infrastructure
public override bool AutoRegisterPausable => true; // Auto-register as IPausable public override bool AutoRegisterPausable => true; // Auto-register as IPausable
internal override void OnManagedAwake() internal override void OnManagedAwake()

View File

@@ -110,10 +110,8 @@ public class AppSwitcher : UIPage
); );
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
base.OnDestroy();
// Clean up tweens // Clean up tweens
slideInTween?.Stop(); slideInTween?.Stop();
slideOutTween?.Stop(); slideOutTween?.Stop();

View File

@@ -149,7 +149,7 @@ namespace UI.CardSystem
} }
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
// Unsubscribe from CardSystemManager // Unsubscribe from CardSystemManager
if (CardSystemManager.Instance != null) if (CardSystemManager.Instance != null)
@@ -181,9 +181,6 @@ namespace UI.CardSystem
// Clean up active cards // Clean up active cards
CleanupActiveCards(); CleanupActiveCards();
// Call base implementation
base.OnDestroy();
} }
private void OnExitButtonClicked() private void OnExitButtonClicked()

View File

@@ -70,16 +70,13 @@ namespace UI.CardSystem
} }
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
// Unsubscribe from CardSystemManager events to prevent memory leaks // Unsubscribe from CardSystemManager events to prevent memory leaks
if (CardSystemManager.Instance != null) if (CardSystemManager.Instance != null)
{ {
CardSystemManager.Instance.OnBoosterCountChanged -= OnBoosterCountChanged; CardSystemManager.Instance.OnBoosterCountChanged -= OnBoosterCountChanged;
} }
// Call base implementation
base.OnDestroy();
} }
/// <summary> /// <summary>

View File

@@ -76,10 +76,8 @@ namespace UI.CardSystem
gameObject.SetActive(false); gameObject.SetActive(false);
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
base.OnDestroy();
// Unsubscribe from dismiss button // Unsubscribe from dismiss button
if (_dismissButton != null) if (_dismissButton != null)
{ {

View File

@@ -308,10 +308,8 @@ namespace UI.CardSystem.DragDrop
#endregion #endregion
protected override void OnDestroy() private void OnDestroy()
{ {
base.OnDestroy();
if (_boosterDraggable != null) if (_boosterDraggable != null)
{ {
_boosterDraggable.OnBoosterOpened -= HandleBoosterOpened; _boosterDraggable.OnBoosterOpened -= HandleBoosterOpened;

View File

@@ -107,10 +107,8 @@ namespace UI.CardSystem.DragDrop
// Card-specific visual effects when dragging ends // Card-specific visual effects when dragging ends
} }
protected override void OnDestroy() private void OnDestroy()
{ {
base.OnDestroy();
if (_cardDraggable != null) if (_cardDraggable != null)
{ {
_cardDraggable.OnCardDataChanged -= HandleCardDataChanged; _cardDraggable.OnCardDataChanged -= HandleCardDataChanged;

View File

@@ -15,9 +15,6 @@ namespace UI.Core
[Header("Page Settings")] [Header("Page Settings")]
public string PageName; public string PageName;
// UI pages load after UI infrastructure (UIPageController is priority 50)
public override int ManagedAwakePriority => 200;
// Events using System.Action instead of UnityEvents // Events using System.Action instead of UnityEvents
public event Action OnTransitionInStarted; public event Action OnTransitionInStarted;
public event Action OnTransitionInCompleted; public event Action OnTransitionInCompleted;

View File

@@ -37,8 +37,6 @@ namespace UI.Core
private PlayerInput _playerInput; private PlayerInput _playerInput;
private InputAction _cancelAction; private InputAction _cancelAction;
public override int ManagedAwakePriority => 50; // UI infrastructure
internal override void OnManagedAwake() internal override void OnManagedAwake()
{ {
// Set instance immediately (early initialization) // Set instance immediately (early initialization)
@@ -50,10 +48,8 @@ namespace UI.Core
Logging.Debug("[UIPageController] Initialized"); Logging.Debug("[UIPageController] Initialized");
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
base.OnDestroy();
// Clean up cached instances // Clean up cached instances
foreach (var cachedPage in _prefabInstanceCache.Values) foreach (var cachedPage in _prefabInstanceCache.Values)
{ {

View File

@@ -52,9 +52,6 @@ namespace UI
/// Singleton instance of the LoadingScreenController. No longer creates an instance if one doesn't exist. /// Singleton instance of the LoadingScreenController. No longer creates an instance if one doesn't exist.
/// </summary> /// </summary>
public static LoadingScreenController Instance => _instance; public static LoadingScreenController Instance => _instance;
// ManagedBehaviour configuration
public override int ManagedAwakePriority => 45; // UI infrastructure, before UIPageController
internal override void OnManagedAwake() internal override void OnManagedAwake()
{ {

View File

@@ -27,9 +27,6 @@ namespace UI
[SerializeField] private UnityEngine.UI.Button devOptionsButton; [SerializeField] private UnityEngine.UI.Button devOptionsButton;
[SerializeField] private GameObject mainOptionsContainer; [SerializeField] private GameObject mainOptionsContainer;
[SerializeField] private GameObject devOptionsContainer; [SerializeField] private GameObject devOptionsContainer;
// After UIPageController (50)
public override int ManagedAwakePriority => 55;
internal override void OnManagedAwake() internal override void OnManagedAwake()
{ {
@@ -76,10 +73,8 @@ namespace UI
// This only fires once for DontDestroyOnLoad objects, so we handle scene loads in OnManagedAwake // This only fires once for DontDestroyOnLoad objects, so we handle scene loads in OnManagedAwake
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
base.OnDestroy();
// Unsubscribe when destroyed // Unsubscribe when destroyed
if (SceneManagerService.Instance != null) if (SceneManagerService.Instance != null)
{ {

View File

@@ -172,10 +172,8 @@ namespace UI
} }
} }
protected override void OnDestroy() internal override void OnManagedDestroy()
{ {
base.OnDestroy();
// Unsubscribe from events // Unsubscribe from events
if (_uiPageController != null) if (_uiPageController != null)
{ {

View File

@@ -30,7 +30,6 @@ namespace UI.Tutorial
private bool _canAcceptInput; private bool _canAcceptInput;
private Coroutine _waitLoopCoroutine; private Coroutine _waitLoopCoroutine;
public override int ManagedAwakePriority => 200; // Tutorial runs late, after other systems
internal override void OnManagedStart() internal override void OnManagedStart()
{ {