Files
AppleHillsProduction/docs/bootstrap_readme.md
2025-10-21 14:20:09 +02:00

268 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Apple Hills Bootstrap System
A concise, code-first overview of the projects 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 oneoffs)
```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<InteractionSettings>();
Debug.Log($"DefaultPromptRange: {gameplay.DefaultPuzzlePromptRange}");
}, name: "Load Interaction Settings");
```
## Events, APIs, and Keys
- `CustomBoot` (static)
- `bool Initialised`
- `float CurrentProgress`
- `event Action<float> 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.