From 1a04f2a3d247e357d222cee0b2704d794b0784ea Mon Sep 17 00:00:00 2001 From: MacBuilder Date: Tue, 21 Oct 2025 13:37:14 +0200 Subject: [PATCH 1/3] FIxed annoying compiler error --- Assets/Scripts/Sound/NarratorVO.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Assets/Scripts/Sound/NarratorVO.cs b/Assets/Scripts/Sound/NarratorVO.cs index b6d273e0..742452c3 100644 --- a/Assets/Scripts/Sound/NarratorVO.cs +++ b/Assets/Scripts/Sound/NarratorVO.cs @@ -1,16 +1,14 @@ using UnityEngine; using UnityEngine.Audio; -using AudioSourceEvents; using System; using UnityEngine.Events; -public class NarratorVO : AudioSourceObserver +public class NarratorVO : MonoBehaviour { public AudioSource narratorAudioSource; public AudioResource firstNarration; public UnityEvent narrationFinished; - private IAudioEventSource _eventSource; // Start is called once before the first execution of Update after the MonoBehaviour is created void Start() @@ -20,8 +18,6 @@ public class NarratorVO : AudioSourceObserver void PlayNarrationAudio() { - _eventSource = narratorAudioSource.RequestEventHandlers(); - _eventSource.AudioStopped += NarrationFinished; narratorAudioSource.resource = firstNarration; narratorAudioSource.Play(); From 8e90878a97b0ce27ca340f630ea5838925197a51 Mon Sep 17 00:00:00 2001 From: MacBuilder Date: Tue, 21 Oct 2025 13:47:18 +0200 Subject: [PATCH 2/3] Updated diving controls and tutorial --- .../Tutorial/Animations/UIANIM_Tutorial2.anim | 272 ++++++++++++++++-- Assets/Prefabs/UI/Tutorial.prefab | 2 +- Assets/Settings/DivingMinigameSettings.asset | 2 +- 3 files changed, 246 insertions(+), 30 deletions(-) diff --git a/Assets/Art/UI/Tutorial/Animations/UIANIM_Tutorial2.anim b/Assets/Art/UI/Tutorial/Animations/UIANIM_Tutorial2.anim index 10a55bf2..7762943f 100644 --- a/Assets/Art/UI/Tutorial/Animations/UIANIM_Tutorial2.anim +++ b/Assets/Art/UI/Tutorial/Animations/UIANIM_Tutorial2.anim @@ -816,7 +816,7 @@ AnimationClip: inWeight: 0 outWeight: 0 - serializedVersion: 3 - time: 2.9666667 + time: 2.4666667 value: 1 inSlope: Infinity outSlope: Infinity @@ -825,7 +825,25 @@ AnimationClip: inWeight: 0 outWeight: 0 - serializedVersion: 3 - time: 5.633333 + time: 3.4 + value: 0 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 4.4333334 + value: 1 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 5.366667 value: 0 inSlope: Infinity outSlope: Infinity @@ -846,7 +864,7 @@ AnimationClip: serializedVersion: 2 m_Curve: - serializedVersion: 3 - time: 2.9666667 + time: 2.4666667 value: 336 inSlope: 0 outSlope: 0 @@ -855,7 +873,7 @@ AnimationClip: inWeight: 0.33333334 outWeight: 0.33333334 - serializedVersion: 3 - time: 3.3333333 + time: 2.8333333 value: 278.0001 inSlope: 0 outSlope: 0 @@ -864,7 +882,7 @@ AnimationClip: inWeight: 0.33333334 outWeight: 0.33333334 - serializedVersion: 3 - time: 5.0333333 + time: 3.1333334 value: 278.0001 inSlope: 0 outSlope: 0 @@ -873,8 +891,44 @@ AnimationClip: inWeight: 0.33333334 outWeight: 0.33333334 - serializedVersion: 3 - time: 5.633333 - value: 449 + time: 3.4 + value: 366 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 4.4333334 + value: 336 + inSlope: -62.857075 + outSlope: -62.857075 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 4.8 + value: 278.0001 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 5.1 + value: 278.0001 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 5.366667 + value: 366 inSlope: 0 outSlope: 0 tangentMode: 136 @@ -903,7 +957,7 @@ AnimationClip: serializedVersion: 2 m_Curve: - serializedVersion: 3 - time: 2.9666667 + time: 2.4666667 value: -411 inSlope: 0 outSlope: 0 @@ -912,7 +966,7 @@ AnimationClip: inWeight: 0.33333334 outWeight: 0.33333334 - serializedVersion: 3 - time: 3.3333333 + time: 2.8333333 value: -359.5001 inSlope: 0 outSlope: 0 @@ -921,7 +975,7 @@ AnimationClip: inWeight: 0.33333334 outWeight: 0.33333334 - serializedVersion: 3 - time: 5.0333333 + time: 3.1333334 value: -359.5001 inSlope: 0 outSlope: 0 @@ -930,8 +984,44 @@ AnimationClip: inWeight: 0.33333334 outWeight: 0.33333334 - serializedVersion: 3 - time: 5.633333 - value: -523 + time: 3.4 + value: -411 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 4.4333334 + value: -411 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 4.8 + value: -359.5001 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 5.1 + value: -359.5001 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 5.366667 + value: -411 inSlope: 0 outSlope: 0 tangentMode: 136 @@ -969,7 +1059,7 @@ AnimationClip: inWeight: 0 outWeight: 0 - serializedVersion: 3 - time: 3.3333333 + time: 2.8333333 value: 1 inSlope: Infinity outSlope: Infinity @@ -978,7 +1068,25 @@ AnimationClip: inWeight: 0 outWeight: 0 - serializedVersion: 3 - time: 5.0333333 + time: 3.1333334 + value: 0 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 4.8 + value: 1 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 5.1 value: 0 inSlope: Infinity outSlope: Infinity @@ -4149,7 +4257,7 @@ AnimationClip: inWeight: 0 outWeight: 0 - serializedVersion: 3 - time: 2.9666667 + time: 2.4666667 value: 1 inSlope: Infinity outSlope: Infinity @@ -4158,7 +4266,25 @@ AnimationClip: inWeight: 0 outWeight: 0 - serializedVersion: 3 - time: 5.633333 + time: 3.4 + value: 0 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 4.4333334 + value: 1 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 5.366667 value: 0 inSlope: Infinity outSlope: Infinity @@ -4179,7 +4305,7 @@ AnimationClip: serializedVersion: 2 m_Curve: - serializedVersion: 3 - time: 2.9666667 + time: 2.4666667 value: 336 inSlope: 0 outSlope: 0 @@ -4188,7 +4314,7 @@ AnimationClip: inWeight: 0.33333334 outWeight: 0.33333334 - serializedVersion: 3 - time: 3.3333333 + time: 2.8333333 value: 278.0001 inSlope: 0 outSlope: 0 @@ -4197,7 +4323,7 @@ AnimationClip: inWeight: 0.33333334 outWeight: 0.33333334 - serializedVersion: 3 - time: 5.0333333 + time: 3.1333334 value: 278.0001 inSlope: 0 outSlope: 0 @@ -4206,8 +4332,44 @@ AnimationClip: inWeight: 0.33333334 outWeight: 0.33333334 - serializedVersion: 3 - time: 5.633333 - value: 449 + time: 3.4 + value: 366 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 4.4333334 + value: 336 + inSlope: -62.857075 + outSlope: -62.857075 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 4.8 + value: 278.0001 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 5.1 + value: 278.0001 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 5.366667 + value: 366 inSlope: 0 outSlope: 0 tangentMode: 136 @@ -4236,7 +4398,7 @@ AnimationClip: serializedVersion: 2 m_Curve: - serializedVersion: 3 - time: 2.9666667 + time: 2.4666667 value: -411 inSlope: 0 outSlope: 0 @@ -4245,7 +4407,7 @@ AnimationClip: inWeight: 0.33333334 outWeight: 0.33333334 - serializedVersion: 3 - time: 3.3333333 + time: 2.8333333 value: -359.5001 inSlope: 0 outSlope: 0 @@ -4254,7 +4416,7 @@ AnimationClip: inWeight: 0.33333334 outWeight: 0.33333334 - serializedVersion: 3 - time: 5.0333333 + time: 3.1333334 value: -359.5001 inSlope: 0 outSlope: 0 @@ -4263,8 +4425,44 @@ AnimationClip: inWeight: 0.33333334 outWeight: 0.33333334 - serializedVersion: 3 - time: 5.633333 - value: -523 + time: 3.4 + value: -411 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 4.4333334 + value: -411 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 4.8 + value: -359.5001 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 5.1 + value: -359.5001 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 5.366667 + value: -411 inSlope: 0 outSlope: 0 tangentMode: 136 @@ -4302,7 +4500,7 @@ AnimationClip: inWeight: 0 outWeight: 0 - serializedVersion: 3 - time: 3.3333333 + time: 2.8333333 value: 1 inSlope: Infinity outSlope: Infinity @@ -4311,7 +4509,25 @@ AnimationClip: inWeight: 0 outWeight: 0 - serializedVersion: 3 - time: 5.0333333 + time: 3.1333334 + value: 0 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 4.8 + value: 1 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 5.1 value: 0 inSlope: Infinity outSlope: Infinity diff --git a/Assets/Prefabs/UI/Tutorial.prefab b/Assets/Prefabs/UI/Tutorial.prefab index 7e0a167f..7d60f71d 100644 --- a/Assets/Prefabs/UI/Tutorial.prefab +++ b/Assets/Prefabs/UI/Tutorial.prefab @@ -242,7 +242,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 0 + m_IsActive: 1 --- !u!4 &1831065641766120066 Transform: m_ObjectHideFlags: 0 diff --git a/Assets/Settings/DivingMinigameSettings.asset b/Assets/Settings/DivingMinigameSettings.asset index fb4d6b08..e9b98845 100644 --- a/Assets/Settings/DivingMinigameSettings.asset +++ b/Assets/Settings/DivingMinigameSettings.asset @@ -76,7 +76,7 @@ MonoBehaviour: m_PreInfinity: 2 m_PostInfinity: 2 m_RotationOrder: 4 - photoInputMode: 1 + photoInputMode: 0 paddingFactor: 1 minSizePercent: 0.15 maxSizePercent: 1 From 9b6dc0f61692e943aa375043f28a38814109c030 Mon Sep 17 00:00:00 2001 From: Michal Adam Pikulski Date: Tue, 21 Oct 2025 14:19:58 +0200 Subject: [PATCH 3/3] Add a playbook for using the boostrap system --- docs/bootstrap_readme.md | 267 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 docs/bootstrap_readme.md diff --git a/docs/bootstrap_readme.md b/docs/bootstrap_readme.md new file mode 100644 index 00000000..49a93aa9 --- /dev/null +++ b/docs/bootstrap_readme.md @@ -0,0 +1,267 @@ +# Apple Hills Bootstrap System + +A concise, code-first overview of the project’s bootstrap system. It covers how boot runs (runtime and editor), how to wait for boot to complete, how to register post-boot initialization, how to retrieve bootstrapped systems safely, and practical case studies. + +## Table of Contents +- [What This Solves](#what-this-solves) +- [Architecture at a Glance](#architecture-at-a-glance) +- [Quick Start (Code-First)](#quick-start-code-first) + - [Check/Wire Boot Completion](#checkwire-boot-completion) + - [Register Post-Boot Initialization](#register-post-boot-initialization) + - [Await Boot Asynchronously](#await-boot-asynchronously) + - [Retrieve Bootstrapped Systems Safely](#retrieve-bootstrapped-systems-safely) +- [Editor Workflow (Project Settings + Edit-Mode Boot)](#editor-workflow-project-settings--edit-mode-boot) + - [Enable/Disable Edit-Mode Boot](#enabledisable-edit-mode-boot) + - [What Happens in Edit Mode (Caveats)](#what-happens-in-edit-mode-caveats) +- [Case Studies](#case-studies) + - [UI Page Controller post-boot wiring](#ui-page-controller-post-boot-wiring) + - [Card System post-boot registration](#card-system-post-boot-registration) + - [Settings access after boot](#settings-access-after-boot) +- [Events, APIs, and Keys](#events-apis-and-keys) +- [Troubleshooting / FAQ](#troubleshooting--faq) +- [Paths & Namespaces](#paths--namespaces) +- [Change Log](#change-log) + +## What This Solves +- Centralizes startup of global systems via a data-driven list of prefabs. +- Guarantees an explicit moment when all bootstrapped systems are ready. +- Provides a robust way to run your own initialization code after boot, including priority ordering. +- Supports editor preview of the booted world without having to enter Play Mode. + +## Architecture at a Glance +- Runtime orchestrator: `CustomBoot` (static) + - Starts automatically via `RuntimeInitializeOnLoadMethod(BeforeSplashScreen)`. + - Loads `CustomBootSettings` with Addressables and instantiates `BootPrefabs` under a runtime container (`DontDestroyOnLoad`). + - Emits progress via `CustomBoot.OnBootProgressChanged` and completion via `CustomBoot.OnBootCompleted`. + - Calls `BootCompletionService.HandleBootCompleted()` when done to unlock post-boot actions. +- Boot data: `CustomBootSettings` (`ScriptableObject`) + - Field: `GameObject[] BootPrefabs` — prefabs to instantiate at boot (usually contain your singletons/services). + - Methods: `Initialise()`/`InitialiseSync()` instantiate prefabs and report progress; `Cleanup()` destroys them. +- Post-boot coordination: `BootCompletionService` (static) + - `bool IsBootComplete` — runtime flag. + - `event Action OnBootComplete` — notify late subscribers. + - `void RegisterInitAction(Action action, int priority = 100, string name = null)` — queue work to run after boot (priority: lower runs earlier). If boot has already completed, runs immediately. + - `Task WaitForBootCompletionAsync()` — await boot in async flows. +- Editor integration: `CustomBootEditorUtils`, `CustomBootSettingsProvider`, `CustomBootProjectSettings` + - Project settings UI to assign Addressable references for runtime/editor boot settings. + - Edit-mode boot toggle to preview booted state in the Scene view. + +## Quick Start (Code-First) + +### Check/Wire Boot Completion +```csharp +using Bootstrap; +using UnityEngine; + +public class BootGateExample : MonoBehaviour +{ + private void Awake() + { + if (BootCompletionService.IsBootComplete) + { + SafeStart(); + } + else + { + BootCompletionService.OnBootComplete += SafeStart; + } + } + + private void OnDestroy() + { + BootCompletionService.OnBootComplete -= SafeStart; + } + + private void SafeStart() + { + // Your code here will only run once all BootPrefabs have been instantiated. + Debug.Log("All systems ready – starting feature!"); + } +} +``` + +### Register Post-Boot Initialization +Register work to run once all bootstrapped systems are ready. Two equivalent approaches are supported: + +1) Inline lambda (great for small one‑offs) +```csharp +using Bootstrap; + +// Lower priority runs earlier; name is used in logs. +BootCompletionService.RegisterInitAction( + action: () => AnalyticsService.Instance.StartSession(), + priority: 50, + name: "Start Analytics Session" +); + +// Can also skip priority and name: +BootCompletionService.RegisterInitAction( + action: () => AnalyticsService.Instance.StartSession() +); +``` + +2) Full function callback (method group) +```csharp +using Bootstrap; +using UnityEngine; + +public class AnalyticsBootstrap : MonoBehaviour +{ + private void Awake() + { + // Pass a method group (no lambda needed). Helpful for reuse and testing. + BootCompletionService.RegisterInitAction( + action: InitAnalytics, + priority: 50, + name: "Init Analytics" + ); + + // Can also skip priority and name: + BootCompletionService.RegisterInitAction( + action: InitAnalytics + ); + } + + private void InitAnalytics() + { + AnalyticsService.Instance.StartSession(); + // You can call other setup methods here as needed + } +} +``` +Notes: +- Only the callback parameter is required. You can omit the priority and name parameters. If you don't have use for them, you probably should. +- If boot has already completed when you call `RegisterInitAction`, your callback runs immediately. +- Use `priority` to control ordering (lower numbers run earlier); `name` helps with log readability. + +### Await Boot Asynchronously +```csharp +using System.Threading.Tasks; +using Bootstrap; + +public class AsyncBootConsumer +{ + public async Task StartAfterBootAsync() + { + await BootCompletionService.WaitForBootCompletionAsync(); + // Now safe to query singletons installed by boot prefabs + var inv = CardSystemManager.Instance; // example + } +} +``` + +### Retrieve Bootstrapped Systems Safely +Boot usually instantiates service prefabs that expose global accessors (singletons or service locators). Always guard access behind boot completion. +```csharp +using Bootstrap; +using UnityEngine; + +public class UseServicesAfterBoot : MonoBehaviour +{ + private void Start() + { + BootCompletionService.RegisterInitAction(() => + { + // Example: get your services here + var pages = UI.Core.UIPageController.Instance; // created in a boot prefab or scene + var settings = AppleHills.Core.Settings.SettingsProvider.Instance; + Debug.Log("Services acquired and ready."); + }, priority: 100, name: "Acquire Services"); + } +} +``` + +## Editor Workflow (Project Settings + Edit-Mode Boot) + +- Project Settings UI: `Project/Custom Boot` (`CustomBootSettingsProvider`) + - Assign Addressables references for `RuntimeSettings` and `EditorSettings` in `CustomBootProjectSettings`. + - Backed by assets `CustomBootSettings_Runtime` and `CustomBootSettings_Editor` that list `BootPrefabs` to spawn. +- Asset management helper: `CustomBootSettingsUtil` + - Creates missing assets and Addressables groups/entries automatically: + - Runtime asset path: `Assets/Data/Bootstrap/Runtime/CustomBootSettings_Runtime.asset` + - Editor asset path: `Assets/Data/Bootstrap/Editor/CustomBootSettings_Editor.asset` + - Project settings asset path: `ProjectSettings/CustomBoot.asset` + - Addressables keys: `CustomBootSettings_Runtime`, `CustomBootSettings_Editor`. + +### Enable/Disable Edit-Mode Boot +- Menu toggle: `Bootstrap/Editor Initialise` (`CustomBootEditorUtils`). +- When enabled in Edit Mode (not Play), the system instantiates the `BootPrefabs` into the currently open scene so you can preview booted systems. + +### What Happens in Edit Mode (Caveats) +- `DontDestroyOnLoad` does not apply in edit mode; booted objects are added to the current scene. +- Entering Play Mode de-initializes any edit-mode boot and hands off to the runtime boot. +- Scene save is guarded: edit-mode boot de-initializes just before save to avoid polluting the scene, then re-initializes after. +- Changing the active scene in Edit Mode triggers de-init/re-init of edit-mode boot. + +## Case Studies + +### UI Page Controller post-boot wiring +`UIPageController` registers a post-boot hook: +```csharp +// Inside UIPageController.Awake() +Bootstrap.BootCompletionService.RegisterInitAction(InitializePostBoot); +``` +This guarantees input/transition wiring happens once systems from `BootPrefabs` are in place. + +### Card System post-boot registration +To ensure the card data/UI only touches `CardSystemManager` after boot: +```csharp +using Bootstrap; +using AppleHills.Data.CardSystem; + +BootCompletionService.RegisterInitAction(() => +{ + var mgr = CardSystemManager.Instance; + // subscribe to events, warm up caches, etc. +}, priority: 90, name: "CardSystem Init"); +``` + +### Settings access after boot +If your settings provider lives in a boot prefab, wait for boot before first access: +```csharp +using Bootstrap; +using AppleHills.Core.Settings; + +BootCompletionService.RegisterInitAction(() => +{ + var gameplay = SettingsProvider.Instance.GetSettings(); + Debug.Log($"DefaultPromptRange: {gameplay.DefaultPuzzlePromptRange}"); +}, name: "Load Interaction Settings"); +``` + +## Events, APIs, and Keys + +- `CustomBoot` (static) + - `bool Initialised` + - `float CurrentProgress` + - `event Action OnBootProgressChanged` + - `event Action OnBootCompleted` +- `BootCompletionService` (static) + - `bool IsBootComplete` + - `event Action OnBootComplete` + - `void RegisterInitAction(Action action, int priority = 100, string name = null)` + - `Task WaitForBootCompletionAsync()` +- Addressables keys + - `CustomBootSettings_Runtime` + - `CustomBootSettings_Editor` + +## Troubleshooting / FAQ +- My code runs before services exist: + - Wrap it in `BootCompletionService.RegisterInitAction(...)` or check `IsBootComplete` and subscribe to `OnBootComplete`. +- Boot never seems to complete in Edit Mode: + - Edit-mode boot is a preview; verify the menu toggle `Bootstrap/Editor Initialise` is enabled and that your `CustomBootSettings_Editor.asset` lists the necessary `BootPrefabs`. +- I get duplicate singletons after entering Play Mode: + - Edit-mode boot de-inits on entering Play. If you manually created objects, ensure you destroy them; prefer boot prefabs. +- Addressables key not found: + - Open `Project/Custom Boot` and ensure both runtime and editor settings assets exist and are assigned; let the utility create missing assets. + +## Paths & Namespaces +- Runtime scripts: `Assets/Scripts/Bootstrap/` + - `CustomBoot.cs`, `CustomBootSettings.cs`, `BootCompletionService.cs` +- Editor scripts: `Assets/Editor/Bootstrap/` + - `CustomBootSettingsProvider.cs`, `CustomBootEditorUtils.cs`, `CustomBootProjectSettings.cs`, `CustomBootSettingsUtil.cs` +- Addressables keys: `CustomBootSettings_Runtime`, `CustomBootSettings_Editor` +- Namespace: `Bootstrap` (runtime), `Editor.Bootstrap` (editor) + +## Change Log +- v1.0: Initial overview document with TOC, code-first playbooks, editor workflow, case studies, and API summary.