diff --git a/.gitignore b/.gitignore index 6229a730..b6aa0b2e 100644 --- a/.gitignore +++ b/.gitignore @@ -104,3 +104,6 @@ InitTestScene*.unity* .vscode/launch.json .vscode/settings.json .idea/.idea.AppleHillsProduction/.idea/indexLayout.xml + +# WIP docs +/docs/wip/ diff --git a/Assets/Scripts/UI/CardSystem/DragDrop/BoosterPackVisual.cs b/Assets/Scripts/UI/CardSystem/DragDrop/BoosterPackVisual.cs index 27278b5d..4783140d 100644 --- a/Assets/Scripts/UI/CardSystem/DragDrop/BoosterPackVisual.cs +++ b/Assets/Scripts/UI/CardSystem/DragDrop/BoosterPackVisual.cs @@ -307,9 +307,11 @@ namespace UI.CardSystem.DragDrop } #endregion - - private void OnDestroy() + + protected override void OnDestroy() { + base.OnDestroy(); + if (_boosterDraggable != null) { _boosterDraggable.OnBoosterOpened -= HandleBoosterOpened; diff --git a/Assets/Scripts/UI/CardSystem/DragDrop/CardDraggableVisual.cs b/Assets/Scripts/UI/CardSystem/DragDrop/CardDraggableVisual.cs index 2d8f4f68..50b3e3fb 100644 --- a/Assets/Scripts/UI/CardSystem/DragDrop/CardDraggableVisual.cs +++ b/Assets/Scripts/UI/CardSystem/DragDrop/CardDraggableVisual.cs @@ -106,9 +106,11 @@ namespace UI.CardSystem.DragDrop base.OnDragEndedVisual(); // Card-specific visual effects when dragging ends } - - private void OnDestroy() + + protected override void OnDestroy() { + base.OnDestroy(); + if (_cardDraggable != null) { _cardDraggable.OnCardDataChanged -= HandleCardDataChanged; diff --git a/docs/managed_behavior/architecture_overview.md b/docs/managed_behavior/architecture_overview.md new file mode 100644 index 00000000..9030e86c --- /dev/null +++ b/docs/managed_behavior/architecture_overview.md @@ -0,0 +1,93 @@ +# ManagedBehaviour System - Architecture Overview + +**Version:** 2.0
+**Updated:** 11.11.2025 + + +--- + +## What is the ManagedBehaviour System? + +Lifecycle orchestration framework that provides guaranteed execution order and deterministic lifecycle management for Unity components. + +### Problems Solved + +We've had quite a few things shoe-stringed together in various ways and dependant on references to each other. +Due to undefined initialization order - null references during access to yet uninitialized resources was becoming a problem. + +### What You Get + +- **Guaranteed Initialization Order** - Managers ready before components that depend on them +- **Deterministic Lifecycle Hooks** - Predictable callbacks at key moments +- **Automatic Registration** - No boilerplate for wiring up systems +- **Scene Lifecycle Events** - Built-in hooks for scene load/unload +- **Save/Load Coordination** - Centralized collection of save data +- **Bootstrap Integration** - Components know when bootstrap completes + +--- + +## Architecture Principles + +### 1. Centralized Orchestration + +Single `LifecycleManager` singleton coordinates all lifecycle events. Components auto-register and receive callbacks at appropriate times. + +### 2. Sealed Framework Methods + +`Awake()` and `OnDestroy()` are sealed. Use `OnManagedAwake()` and `OnManagedDestroy()` instead. Prevents forgetting to call `base.Awake()`. + +### 3. Two-Phase Initialization + +- **Early (`OnManagedAwake()`)**: During Unity's Awake, before bootstrap. Use for singleton setup. +- **Late (`OnManagedStart()`)**: After bootstrap completes. All managers guaranteed ready. + +### 4. Registration Order Execution + +Execution follows Unity's natural Awake order. No priority numbers to manage. + +### 5. Automatic Cleanup + +Framework handles unregistration automatically. Override `OnManagedDestroy()` only if you need custom cleanup. + +--- + +## Lifecycle Flow Diagrams + +### Boot Sequence + +![Boot Sequence](../media/boot_sequence.png) + +### Scene Transition Flow + +![Scene Transition Flow](../media/Scene_transition_flow.png) + +### Component Lifecycle (Individual Component) + +![Component Lifecycle](../media/component_lifecycle.png) + +--- + +## Class Diagram + +![Class Diagram](../media/class_diagram.png) + +--- +## Key Guarantees + +### Guaranteed + +1. **Bootstrap Completion** - `OnManagedStart()` always fires after bootstrap completes +2. **Manager Availability** - All manager singletons exist when `OnManagedStart()` is called +3. **Scene Lifecycle** - `OnSceneReady()` fires after scene load, `OnSceneUnloading()` before unload +4. **Automatic Registration** - Can't forget to register (Awake is sealed) +5. **Automatic Cleanup** - Can't forget to unregister (OnDestroy is sealed) +6. **Save/Load Coordination** - All save participants called in one pass + +### Not Guaranteed + +1. **Initialization Order Between Components** - `OnManagedAwake()` follows Unity's unpredictable Awake order +2. **Thread Safety** - All methods must run on main thread +3. **Performance** - Broadcasting to 1000+ components may have overhead +4. **SaveId Uniqueness** - Developer responsible for unique SaveIds + + diff --git a/docs/managed_behavior/technical_reference.md b/docs/managed_behavior/technical_reference.md new file mode 100644 index 00000000..aa56aec7 --- /dev/null +++ b/docs/managed_behavior/technical_reference.md @@ -0,0 +1,377 @@ +# ManagedBehaviour System - Technical Reference + +**Version:** 2.0
+**Updated:** 11.11.2025 + +--- + +## Overview + +The ManagedBehaviour system provides a deterministic, ordered lifecycle management framework for Unity MonoBehaviours. This document provides complete technical documentation of all classes, methods, and APIs. + +--- + +## Core Classes + +### ManagedBehaviour (Abstract Base Class) + +**Namespace:** `Core.Lifecycle` +**Inherits:** `MonoBehaviour` +**Location:** `Assets/Scripts/Core/Lifecycle/ManagedBehaviour.cs` → [View Source](../../Assets/Scripts/Core/Lifecycle/ManagedBehaviour.cs) + +Abstract base class that all managed components must inherit from. Provides automatic registration with LifecycleManager and ordered lifecycle callbacks. + +#### Lifecycle Hook Methods + +Override these `internal virtual` methods to customize component behavior at different lifecycle stages. Called automatically by `LifecycleManager`. + +
+Click to see more details + +##### `OnManagedAwake()` +```csharp +internal virtual void OnManagedAwake() +``` +**Called:** During registration (within Unity's Awake phase) +**Execution Order:** Natural Unity script execution order (not guaranteed between components) +**Use For:** +- Setting singleton instances (`_instance = this`) +- Early GetComponent calls +- One-time initialization that doesn't depend on other systems + +**Timing Guarantees:** +- ✅ GameObject and component exist +- ✅ Scene is loaded +- ❌ Other components may not be initialized yet +- ❌ Bootstrap may not be complete + +##### `OnManagedStart()` +```csharp +internal virtual void OnManagedStart() +``` +**Called:** After bootstrap completes (for boot components) or immediately after registration (for late-registered components) +**Execution Order:** Registration order +**Use For:** +- Initialization that depends on other managers +- Accessing singleton instances safely +- Setting up cross-system dependencies + +**Timing Guarantees:** +- ✅ All managers are initialized +- ✅ Bootstrap resources are available +- ✅ Safe to access `GameManager.Instance`, `AudioManager.Instance`, etc. + +##### `OnSceneUnloading()` +```csharp +internal virtual void OnSceneUnloading() +``` +**Called:** Before scene unload +**Execution Order:** Registration order +**Use For:** +- Scene-specific cleanup +- Saving temporary scene state + +**Timing Guarantees:** +- ✅ Scene is still loaded +- ✅ Other components in scene still exist + +##### `OnSceneReady()` +```csharp +internal virtual void OnSceneReady() +``` +**Called:** After scene load completes +**Execution Order:** Registration order +**Use For:** +- Scene-specific initialization +- Finding scene objects +- Setting up scene-specific state + +**Timing Guarantees:** +- ✅ All scene GameObjects are loaded +- ✅ Batched components have received `OnManagedStart()` + +##### `OnSceneSaveRequested()` +```csharp +internal virtual string OnSceneSaveRequested() +``` +**Called:** Before scene unload during scene transitions +**Returns:** Serialized scene-specific data (JSON string), or `null` if nothing to save +**Use For:** +- Level progress +- Object positions +- Puzzle states +- Temporary scene data + +**⚠️ Important:** Must return synchronously. + +##### `OnSceneRestoreRequested(string serializedData)` +```csharp +internal virtual void OnSceneRestoreRequested(string serializedData) +``` +**Called:** After scene load, during `OnSceneReady` phase +**Parameters:** +- `serializedData` - Previously saved data from `OnSceneSaveRequested()` + +**Use For:** +- Restoring level progress +- Setting object positions +- Restoring puzzle states + +**⚠️ Important:** Must execute synchronously. Do not use coroutines or async/await. + +##### `OnSceneRestoreCompleted()` +```csharp +internal virtual void OnSceneRestoreCompleted() +``` +**Called:** After all `OnSceneRestoreRequested()` calls complete +**Timing:** Always called after scene load, whether save data exists or not +**Use For:** +- Post-restore initialization +- First-time initialization (when no save data exists) +- Triggering events after state is restored + +**Common Pattern:** +```csharp +internal override void OnSceneRestoreCompleted() +{ + if (!_hasPlayed) // Check if this is first time + { + PlayIntroAudio(); + _hasPlayed = true; + } +} +``` + +##### `OnGlobalSaveRequested()` +```csharp +internal virtual string OnGlobalSaveRequested() +``` +**Called:** Once before save file is written to disk +**Returns:** Serialized global persistent data (JSON string), or `null` +**Use For:** +- Player inventory +- Unlocked features +- Card collections +- Persistent progression + +**Timing:** Called once per game save (not per scene transition) + +##### `OnGlobalRestoreRequested(string serializedData)` +```csharp +internal virtual void OnGlobalRestoreRequested(string serializedData) +``` +**Called:** Once on game boot after save file is read +**Parameters:** +- `serializedData` - Previously saved data from `OnGlobalSaveRequested()` + +**Use For:** +- Restoring player inventory +- Restoring unlocked features +- Restoring persistent progression + +**Timing:** Called once on boot, not during scene transitions + +##### `OnGlobalLoadCompleted()` +```csharp +internal virtual void OnGlobalLoadCompleted() +``` +**Called:** Once on game boot after all global restore operations complete +**Use For:** +- Triggering UI updates after load +- Broadcasting load events +- Post-load initialization + +##### `OnGlobalSaveStarted()` +```csharp +internal virtual void OnGlobalSaveStarted() +``` +**Called:** Once before save file is written +**Use For:** +- Final validation before save +- Cleanup operations before save + +##### `OnManagedDestroy()` +```csharp +internal virtual void OnManagedDestroy() +``` +**Called:** During `OnDestroy`, before unregistration +**Execution Order:** Registration order +**Use For:** +- Unsubscribing from events +- Releasing resources +- Custom cleanup logic + +**Note:** Most cleanup is automatic (auto-registrations are handled by framework). +
+ +#### Configuration Properties + +Virtual properties that control automatic behaviors like pause registration and save system participation. + +
+Click to see more details + +##### `AutoRegisterPausable` +```csharp +public virtual bool AutoRegisterPausable => false; +``` +**Type:** `bool` +**Default:** `false` +**Description:** If true and component implements `IPausable`, automatically registers with `GameManager.Instance` during initialization. Automatic unregistration occurs on destruction. + +##### `AutoRegisterForSave` +```csharp +public virtual bool AutoRegisterForSave => false; +``` +**Type:** `bool` +**Default:** `false` +**Description:** If true, component participates in the save/load system. Should override `OnSceneSaveRequested()` and `OnSceneRestoreRequested()` or global equivalents. + +##### `SaveId` +```csharp +public virtual string SaveId { get; } +``` +**Type:** `string` +**Default:** `"{SceneName}/{GameObjectName}/{ComponentType}"` +**Description:** Unique identifier for this component in the save system. Cached on first access for performance. Override for singletons (e.g., `"PlayerController"`) or custom IDs. + +**⚠️ Warning:** GameObject name changes at runtime will NOT update the cached SaveId. +
+ +### Private Lifecycle Methods +
+Click to see more details + +##### `Awake()` +```csharp +private void Awake() +``` +**Visibility:** `private` (sealed, cannot be overridden) +**Called By:** Unity +**Description:** Automatically registers component with `LifecycleManager`. Calls `OnManagedAwake()` during registration. + +**⚠️ Important:** This method is sealed. Use `OnManagedAwake()` for early initialization. + +##### `OnDestroy()` +```csharp +private void OnDestroy() +``` +**Visibility:** `private` (sealed, cannot be overridden) +**Called By:** Unity +**Description:** Calls `OnManagedDestroy()`, unregisters from `LifecycleManager`, and handles auto-unregistrations. + +**⚠️ Important:** This method is sealed. Use `OnManagedDestroy()` for custom cleanup. +
+ +--- + +## LifecycleManager (Singleton Orchestrator) + +**Namespace:** `Core.Lifecycle` +**Inherits:** `MonoBehaviour` +**Location:** `Assets/Scripts/Core/Lifecycle/LifecycleManager.cs` → [View Source](../../Assets/Scripts/Core/Lifecycle/LifecycleManager.cs) + +Central orchestrator that manages all `ManagedBehaviour` components and broadcasts lifecycle events. + +### Static Properties + +##### `Instance` +Singleton instance. Created automatically by `CustomBoot` before bootstrap begins. + +### Public Methods + +Core methods for registration, lifecycle broadcasting, and save/restore operations. Most are called automatically by the framework. + +
+Click to see more details + +##### `Register(ManagedBehaviour component)` +```csharp +public void Register(ManagedBehaviour component) +``` +Registers a component with the lifecycle system. **Called automatically from `ManagedBehaviour.Awake()`.** + +##### `Unregister(ManagedBehaviour component)` +```csharp +public void Unregister(ManagedBehaviour component) +``` +Unregisters a component. **Called automatically from `ManagedBehaviour.OnDestroy()`.** + +##### `OnBootCompletionTriggered()` +```csharp +public void OnBootCompletionTriggered() +``` +Called by `CustomBoot` after bootstrap completes. Broadcasts `OnManagedStart()` to all registered components. + +##### `BeginSceneLoad(string sceneName)` +```csharp +public void BeginSceneLoad(string sceneName) +``` +Activates scene loading batching mode. Called by `SceneManagerService` when loading a scene. + +##### `BroadcastSceneReady(string sceneName)` +```csharp +public void BroadcastSceneReady(string sceneName) +``` +Processes batched components and broadcasts `OnSceneReady()` to all components in the scene. Called by `SceneManagerService` after scene load. + +##### `BroadcastSceneUnloading(string sceneName)` +```csharp +public void BroadcastSceneUnloading(string sceneName) +``` +Broadcasts `OnSceneUnloading()` to all components in the specified scene. Called by `SceneManagerService` before scene unload. + +##### `BroadcastSceneSaveRequested()` +```csharp +public Dictionary BroadcastSceneSaveRequested() +``` +Broadcasts `OnSceneSaveRequested()` to all components with `AutoRegisterForSave == true`. Returns dictionary of SaveId → serialized data. + +##### `BroadcastSceneRestoreRequested(Dictionary saveData)` +```csharp +public void BroadcastSceneRestoreRequested(Dictionary saveData) +``` +Distributes save data to components by matching `SaveId`, then broadcasts `OnSceneRestoreCompleted()`. + +##### `BroadcastGlobalSaveRequested()` +```csharp +public Dictionary BroadcastGlobalSaveRequested() +``` +Broadcasts `OnGlobalSaveRequested()` to all components with `AutoRegisterForSave == true`. Returns dictionary of SaveId → serialized data. + +##### `BroadcastGlobalRestoreRequested(Dictionary saveData)` +```csharp +public void BroadcastGlobalRestoreRequested(Dictionary saveData) +``` +Distributes save data to components by matching `SaveId`, then broadcasts `OnGlobalLoadCompleted()`. + +##### `BroadcastGlobalSaveStarted()` +```csharp +public void BroadcastGlobalSaveStarted() +``` +Broadcasts `OnGlobalSaveStarted()` to all components with `AutoRegisterForSave == true`. + +## LifecyclePhase (Enum) + +**Namespace:** `Core.Lifecycle` +**Location:** `Assets/Scripts/Core/Lifecycle/LifecycleEnums.cs` → [View Source](../../Assets/Scripts/Core/Lifecycle/LifecycleEnums.cs) + +Defines the different lifecycle phases for documentation and tooling purposes. + +```csharp +public enum LifecyclePhase +{ + ManagedAwake, // During registration (Awake) + ManagedStart, // After bootstrap or late registration + SceneUnloading, // Before scene unload + SceneReady, // After scene load + SaveRequested, // Before scene unload (save) + RestoreRequested, // After scene load (restore) + ManagedDestroy // During OnDestroy +} +``` + +--- + + + diff --git a/docs/managed_behavior/use_cases_quick_start.md b/docs/managed_behavior/use_cases_quick_start.md new file mode 100644 index 00000000..564681ff --- /dev/null +++ b/docs/managed_behavior/use_cases_quick_start.md @@ -0,0 +1,522 @@ +# ManagedBehaviour System - Quick Start & Use Cases + +**TL;DR:** Inherit from `ManagedBehaviour` instead of `MonoBehaviour`. Override lifecycle hooks instead of Awake/OnDestroy. Get guaranteed initialization order and automatic registration. + +--- + +## Table of Contents + +1. [Lifecycle Methods Summary](#lifecycle-methods-summary) +2. [Quick Reference - Common Use Cases](#quick-reference---common-use-cases) +3. [Getting Started Examples](#getting-started-examples) +4. [Detailed Use Cases](#detailed-use-cases) +5. [Common Patterns](#common-patterns) +6. [Migration Checklist](#migration-checklist) +7. [Troubleshooting](#troubleshooting) +8. [Best Practices](#best-practices) +9. [FAQ](#faq) + +--- + +## Summary + +**ManagedBehaviour in 3 Sentences:** + +Inherit from `ManagedBehaviour` to get automatic lifecycle management with guaranteed initialization order. Use `OnManagedStart()` to safely access manager singletons, and use built-in save/load hooks for persistence. The framework handles registration and cleanup automatically - you just override the hooks you need. + +**When to Use:** +- ✅ Singleton managers +- ✅ Components that access managers +- ✅ Components that need save/load +- ✅ Components that need scene lifecycle events + +**When to Skip:** +- ❌ Simple self-contained components +- ❌ Third-party code (can't change base class) +- ❌ Performance-critical code with no dependencies + +**But can I still use regular MonoBehaviour?!**
+_Yes!_ Only use ManagedBehaviour when you need its features (manager access, save/load, etc.) + + +--- + +## Lifecycle Methods Summary + +1. **OnManagedAwake()** - Called during Unity's Awake phase; use for **internal setup** and GetComponent calls. +2. **OnManagedStart()** - Called after bootstrap completes; **safe to access** manager singletons. +3. **OnSceneReady()** - Called after scene finishes loading; use for scene-specific initialization. +4. **OnSceneUnloading()** - Called before scene unloads; use for scene cleanup. +5. **OnSceneSaveRequested()** - Returns serialized scene-specific data before scene transitions. +6. **OnSceneRestoreRequested(data)** - Receives saved scene data after scene loads. +7. **OnSceneRestoreCompleted()** - Called after all scene restore operations complete. +8. **OnGlobalSaveRequested()** - Returns serialized persistent data when game saves. +9. **OnGlobalRestoreRequested(data)** - Receives persistent data on game boot. +10. **OnGlobalLoadCompleted()** - Called after all global restore operations complete on boot. +11. **OnGlobalSaveStarted()** - Called before save file is written; use for pre-save validation. +12. **OnManagedDestroy()** - Called during OnDestroy; use for cleanup and event unsubscription. + +--- + +## Quick Reference - Common Use Cases + +### Access Manager Singleton Safely +```csharp +internal override void OnManagedStart() +{ + GameManager.Instance.DoSomething(); // Safe - managers guaranteed ready +} +``` + +### Create Singleton Manager +```csharp +private static MyManager _instance; +public static MyManager Instance => _instance; + +internal override void OnManagedAwake() +{ + _instance = this; +} +``` + +### Save Scene Progress +```csharp +public override bool AutoRegisterForSave => true; + +internal override string OnSceneSaveRequested() +{ + return JsonUtility.ToJson(myData); +} + +internal override void OnSceneRestoreRequested(string data) +{ + myData = JsonUtility.FromJson(data); +} +``` + +### Auto-Register as Pausable +```csharp +public class MyComponent : ManagedBehaviour, IPausable +{ + public override bool AutoRegisterPausable => true; + + public void Pause() { /* pause logic */ } + public void Resume() { /* resume logic */ } +} +``` + +### Scene-Specific Initialization +```csharp +internal override void OnSceneReady() +{ + FindObjectsInScene(); + InitializeLevel(); +} +``` + +### Cleanup on Destroy +```csharp +internal override void OnManagedDestroy() +{ + EventBus.OnSomething -= HandleEvent; +} +``` + +--- + +## Getting Started Examples + +### 1. Basic Component + +```csharp +using Core.Lifecycle; + +public class MyComponent : ManagedBehaviour +{ + internal override void OnManagedAwake() + { + // Early initialization (singleton setup, GetComponent) + Debug.Log("MyComponent awakened"); + } + + internal override void OnManagedStart() + { + // Late initialization (safe to access managers) + Debug.Log("MyComponent started - managers are ready"); + } +} +``` + +### 2. Singleton Manager + +```csharp +using Core.Lifecycle; + +public class MyManager : ManagedBehaviour +{ + private static MyManager _instance; + public static MyManager Instance => _instance; + + internal override void OnManagedAwake() + { + _instance = this; // Set singleton early + } + + internal override void OnManagedStart() + { + // All other managers are ready here + AudioManager.Instance.PlaySound("ManagerReady"); + } +} +``` + +### 3. Component with Save/Load + +```csharp +using Core.Lifecycle; + +public class PuzzleComponent : ManagedBehaviour +{ + public override bool AutoRegisterForSave => true; + public override string SaveId => "MyPuzzle"; // Custom ID + + private bool _isSolved; + + internal override string OnSceneSaveRequested() + { + return JsonUtility.ToJson(new { isSolved = _isSolved }); + } + + internal override void OnSceneRestoreRequested(string data) + { + var saveData = JsonUtility.FromJson(data); + _isSolved = saveData.isSolved; + } + + [System.Serializable] + private class SaveData + { + public bool isSolved; + } +} +``` + +### 4. Component with Cleanup + +```csharp +using Core.Lifecycle; + +public class EventSubscriber : ManagedBehaviour +{ + internal override void OnManagedStart() + { + GameManager.Instance.OnGamePaused += HandlePause; + } + + internal override void OnManagedDestroy() + { + // Automatic cleanup + if (GameManager.Instance != null) + GameManager.Instance.OnGamePaused -= HandlePause; + } + + private void HandlePause() { } +} +``` + +--- + +## Detailed Use Cases + +### Use Case 1: Accessing Singleton Managers Safely + +**Problem:** Accessing `GameManager.Instance` in `Awake()` might fail if GameManager hasn't initialized yet. + +**Solution:** +```csharp +public class Player : ManagedBehaviour +{ + // ❌ DON'T: Risky in OnManagedAwake (managers may not be ready) + internal override void OnManagedAwake() + { + // var settings = GameManager.Instance.GetSettings(); // RISKY! + } + + // ✅ DO: Safe in OnManagedStart (managers guaranteed ready) + internal override void OnManagedStart() + { + var settings = GameManager.Instance.GetSettings(); // SAFE! + ApplySettings(settings); + } +} +``` + +--- + +### Use Case 2: Scene-Specific Initialization + +**Problem:** Need to initialize something after a scene finishes loading. + +**Solution:** +```csharp +public class LevelManager : ManagedBehaviour +{ + internal override void OnSceneReady() + { + // Scene is fully loaded, all objects exist + FindObjectiveMarkers(); + SpawnEnemies(); + PlayLevelMusic(); + } +} +``` + +--- + +### Use Case 3: Saving Player Progress + +**Problem:** Need to save level progress when transitioning between scenes. + +**Solution:** +```csharp +public class LevelProgress : ManagedBehaviour +{ + public override bool AutoRegisterForSave => true; + public override string SaveId => "LevelProgress"; + + private int _checkpointIndex; + private float _timeElapsed; + + internal override string OnSceneSaveRequested() + { + return JsonUtility.ToJson(new + { + checkpoint = _checkpointIndex, + time = _timeElapsed + }); + } + + internal override void OnSceneRestoreRequested(string data) + { + var save = JsonUtility.FromJson(data); + _checkpointIndex = save.checkpoint; + _timeElapsed = save.time; + } + + internal override void OnSceneRestoreCompleted() + { + // Restore complete, trigger UI update + UpdateProgressUI(); + } +} +``` + +--- + +### Use Case 4: Global Persistent Data (Inventory) + +**Problem:** Need to save player inventory across all scenes. + +**Solution:** +```csharp +public class InventoryManager : ManagedBehaviour +{ + public override bool AutoRegisterForSave => true; + public override string SaveId => "Inventory"; + + private List _items = new List(); + + internal override string OnGlobalSaveRequested() + { + // Save to global save file (not scene-specific) + return JsonUtility.ToJson(new { items = _items }); + } + + internal override void OnGlobalRestoreRequested(string data) + { + // Restore from global save file on boot + var save = JsonUtility.FromJson(data); + _items = new List(save.items); + } + + internal override void OnGlobalLoadCompleted() + { + // All global data loaded, safe to initialize UI + RefreshInventoryUI(); + } +} +``` + +--- + +### Use Case 5: Auto-Registering as Pausable + +**Problem:** Component implements `IPausable` and needs to register with `GameManager`. + +**Solution:** +```csharp +public class AnimatedCharacter : ManagedBehaviour, IPausable +{ + public override bool AutoRegisterPausable => true; + + // IPausable implementation + public void Pause() + { + // Pause animations + } + + public void Resume() + { + // Resume animations + } +} +// No manual registration needed - automatic! +``` + +--- + +### Use Case 6: Scene Cleanup + +**Problem:** Need to clean up scene-specific state before transitioning. + +**Solution:** +```csharp +public class ParticleSpawner : ManagedBehaviour +{ + private List _activeParticles = new List(); + + internal override void OnSceneUnloading() + { + // Clean up before scene unloads + foreach (var particle in _activeParticles) + { + if (particle != null) + Destroy(particle); + } + _activeParticles.Clear(); + } +} +``` + +--- + +### Use Case 7: First-Time vs Restored State + +**Problem:** Need to play intro animation only on first visit, not when restoring from save. + +**Solution:** +```csharp +public class LevelIntro : ManagedBehaviour +{ + public override bool AutoRegisterForSave => true; + + private bool _hasPlayedIntro; + + internal override string OnSceneSaveRequested() + { + return JsonUtility.ToJson(new { hasPlayed = _hasPlayedIntro }); + } + + internal override void OnSceneRestoreRequested(string data) + { + var save = JsonUtility.FromJson(data); + _hasPlayedIntro = save.hasPlayed; + } + + internal override void OnSceneRestoreCompleted() + { + // This fires whether we restored or not + if (!_hasPlayedIntro) + { + PlayIntroAnimation(); + _hasPlayedIntro = true; + } + } +} +``` + +--- + + +## Common Patterns + +### Pattern: Manager Singleton +```csharp +public class MyManager : ManagedBehaviour +{ + private static MyManager _instance; + public static MyManager Instance => _instance; + + internal override void OnManagedAwake() + { + _instance = this; + } +} +``` + +### Pattern: Event Subscription +```csharp +internal override void OnManagedStart() +{ + EventBus.OnSomething += HandleEvent; +} + +internal override void OnManagedDestroy() +{ + EventBus.OnSomething -= HandleEvent; +} +``` + +### Pattern: Save/Restore +```csharp +public override bool AutoRegisterForSave => true; + +internal override string OnSceneSaveRequested() +{ + return JsonUtility.ToJson(myData); +} + +internal override void OnSceneRestoreRequested(string data) +{ + myData = JsonUtility.FromJson(data); +} +``` + +### Pattern: Custom SaveId +```csharp +// For singletons or special cases +public override string SaveId => "PlayerInventory"; + +// For scene-specific instances +public override string SaveId => $"{gameObject.scene.name}/MySpecialObject"; +``` + +## Troubleshooting + +### "NullReferenceException when accessing Manager.Instance" +**Problem:** Accessing singleton in `OnManagedAwake()` +**Solution:** Move to `OnManagedStart()` where managers are guaranteed ready + +### "My SaveId is colliding with another component" +**Problem:** Two components have same GameObject name and type +**Solution:** Override `SaveId` property with unique value + +### "My component isn't receiving lifecycle callbacks" +**Problem:** Not inheriting from `ManagedBehaviour` +**Solution:** Ensure class inherits `ManagedBehaviour` (not plain `MonoBehaviour`) + +### "Save data isn't persisting" +**Problem:** `AutoRegisterForSave` is false +**Solution:** Set `public override bool AutoRegisterForSave => true;` + +### "OnSceneRestoreCompleted isn't firing" +**Problem:** Missing implementation +**Solution:** Override the method even if just logging for now + +--- + +**Quick Links:** +- [Technical Reference](01_technical_reference.md) - Complete API documentation +- [Architecture Overview](02_architecture_overview.md) - System design and principles + + diff --git a/docs/media/Scene_transition_flow.png b/docs/media/Scene_transition_flow.png new file mode 100644 index 00000000..b9e77c39 Binary files /dev/null and b/docs/media/Scene_transition_flow.png differ diff --git a/docs/media/boot_sequence.png b/docs/media/boot_sequence.png new file mode 100644 index 00000000..c92d7405 Binary files /dev/null and b/docs/media/boot_sequence.png differ diff --git a/docs/media/class_diagram.png b/docs/media/class_diagram.png new file mode 100644 index 00000000..0ca7fd51 Binary files /dev/null and b/docs/media/class_diagram.png differ diff --git a/docs/media/component_lifecycle.png b/docs/media/component_lifecycle.png new file mode 100644 index 00000000..671bd71b Binary files /dev/null and b/docs/media/component_lifecycle.png differ