Bootstrap
Automatic framework startup — registers all 23 services in dependency order before the first scene loads.
Automatic framework startup · Runs once, before the first scene loads · Registers all 23 services · Cannot be replaced
What it does
Bootstrap is the framework's automatic startup routine. It registers all 23 services in dependency order, removes internal GameObjects left over from a previous Play session (relevant only when Domain Reload is disabled in the Editor), and warms up the Logger. You never call it — Unity calls it automatically before the first scene loads, and it runs exactly once per Play session.
When startup finishes, the Unity Console shows this line:
bootstrap complete (v2.1.0, 23 services)
If you see that line, the framework is up and every service is ready to use.
Quick example
The most common real usage is: you never call Bootstrap directly. By the time your own Awake runs, every service is already registered — just resolve and use them.
using CommonGameSystem.Core;
using UnityEngine;
[DefaultExecutionOrder(100)] // Run AFTER framework startup — the attribute goes on the class
public class GameController : MonoBehaviour
{
void Awake()
{
// Bootstrap.Run has already fired. All services are registered.
// Resolve once and cache the references.
var time = ServiceLocator.Resolve<ITimeService>();
var pool = ServiceLocator.Resolve<IObjectPoolService>();
var bus = ServiceLocator.Resolve<IEventBus>();
// DeltaTime is a method: you pick the clock you want.
Debug.Log($"Gameplay: {time.DeltaTime(Clock.Gameplay)}, " +
$"unscaled: {time.UnscaledDeltaTime(Clock.Gameplay)}");
}
}
In an EditMode test, Bootstrap has normally already run — its startup hook fires for the test domain too — so you can resolve services directly:
using CommonGameSystem.Core;
using NUnit.Framework;
public class BootstrapSmokeTests
{
[Test]
public void Bootstrap_RegistersCoreServices()
{
// Bootstrap.Run already fired for the test domain. Resolve and assert.
Assert.IsNotNull(ServiceLocator.Resolve<ILogger>());
Assert.IsNotNull(ServiceLocator.Resolve<IObjectPoolService>());
Assert.IsTrue(Bootstrap.HasRun);
}
}
Full API surface
There is nothing to resolve. Bootstrap fires automatically through Unity's [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] hook. It runs before any scene Awake and before any of your code touches the Service Locator.
namespace CommonGameSystem.Core
{
public static class Bootstrap
{
// Entry point — Unity calls this automatically (do NOT invoke directly).
public static void Run();
// Registers the settings-persistence backend. Public so automated
// tests can inject a stub; not part of normal use.
public static void RegisterConfigurationPersistence();
// Diagnostic-only (read-only — set internally). Editor-only:
// these two properties do not exist in player builds.
public static bool HasRun { get; }
public static int RunCount { get; }
}
}
| Member | What it does |
|---|---|
Run() | The startup entry point. Unity invokes it once per Play session, before the first scene loads. Calling it yourself a second time throws ServiceAlreadyRegisteredException. |
RegisterConfigurationPersistence() | Registers the storage backend the Configuration service saves settings through: the Save/Load service when it is active, Unity's PlayerPrefs otherwise. Public only so tests can exercise the fallback; not part of normal use. |
HasRun | true once startup has completed at least once. Read-only, Editor only — wrap references in #if UNITY_EDITOR or keep them inside Editor/test assemblies. |
RunCount | Cumulative count of startup runs (climbs across Editor Play sessions when Domain Reload is disabled). Read-only, Editor only. |
The 23 services, in registration order
Bootstrap starts the services below, in this order. Each one is an interface you resolve with ServiceLocator.Resolve<T>(), and each has its own reference page.
- ServiceLocator — the registry every other service lives in; the one class you call to get any service. See Service Locator.
- ILogger — categorized logging with per-category filters. See Logger.
- IObjectPoolService — prefab pooling. See Object Pool.
- ITimeService — per-clock time, pause, and slow motion (Gameplay/UI/Background clocks). See Time.
- IEventBus — type-safe publish/subscribe between systems. See Event Bus.
- ISaveService — JSON save files with safe atomic writes and slots. See Save/Load.
- IConfiguration — typed settings groups with change events. See Configuration.
- IInputService — input action-map contexts and key rebinding. See Input.
- IAudioService — music, sound effects, and voice over an AudioMixer. See Audio.
- IPanelStack — UI panel push/pop with gamepad and keyboard focus. See UI Framework.
- ISceneService — async scene loading with a loading screen, cancel support, and additive load/unload. See Scene Flow.
- ILocalizationService — key-to-string lookup and runtime language switching. See Localization.
- IAchievementService — local stats and achievements with automatic unlocks. See Achievements.
- IScheduler — After/Every/NextFrame timers and run-on-main-thread dispatch. See Scheduler.
- ITweenService — pause-aware value tweening with 31 easings. See Tween.
- IAssetProvider — Addressables loading with reference counting. See Asset Provider.
- IRandomService — seeded, repeatable random numbers with named streams. See Random.
- IStateMachineService — flat finite-state-machine factory. See FSM.
- IPushdownStackService — stacked game-state scopes (pause menu over gameplay, and so on). See Pushdown Stack.
- ITweenSequenceService — ordered and parallel tween timelines. See Tween Sequencing.
- IAddressableSceneService — additive scenes loaded from Addressables. See Addressable Scene.
- IDeferredBus — queue events now, flush them later. See Deferred Event Queue.
- ICommandRegistry — runtime command registry (the console UI is yours to build). See Command Registry.
Internal helper registrations
Bootstrap also registers a few internal helpers so automated tests can swap them out: the settings-persistence backend, three built-in settings validators, and the input key map source. Game code never resolves these directly, and they are not part of the 23-service count.
Behavior & edge cases
-
Runs once. Calling
Bootstrap.Run()twice in one Play session throwsServiceAlreadyRegisteredException. Unity's hook guarantees it fires exactly once per Play entry — you never need to call it. -
Main thread only. The startup hook runs on Unity's main thread. Debug builds assert this; a violation is caught early and aborts Play.
-
Cleanup before registration. Before registering services, Bootstrap removes internal framework GameObjects left over from the previous Play session. This only matters when Domain Reload is disabled in the Editor (Project Settings → Editor → "Enter Play Mode Settings"); with Domain Reload on, each Play session starts with a clean hierarchy anyway. The framework finds its own leftover objects by an internal marker component and destroys them with
Object.Destroy— at end of frame, not immediately — so PlayMode tests shouldyield return nullafter startup to let the destroy settle. The marker component is framework-internal; do not attach it yourself. -
Logger warm-up. During startup, Bootstrap makes one Logger call on the main thread. That call primes the static
Loggerhelpers so later calls from worker threads (for example, save-file I/O) are safe. -
Startup failures stop Play. Services created later in the sequence receive their dependencies through constructors. If a constructor throws, the exception propagates and Play aborts immediately — problems surface at startup, not minutes later.
-
Editor shutdown hook. In the Editor only, Bootstrap watches for Play mode exit and disposes all disposable services in reverse registration order. Player builds do not ship this hook — they rely on normal process teardown.
-
Bootstrap itself cannot be replaced — it is the code that starts everything else. Every service it registers can be replaced, though, and each service ships with a Null (no-op) implementation you can swap in as a one-line off-switch:
// Example: silence all diagnostics ServiceLocator.Replace<ILogger>(new NullLogger()); // Example: disable audio entirely ServiceLocator.Replace<IAudioService>(new NullAudio()); // Example: stub the scene service for testing ServiceLocator.Replace<ISceneService>(new NullSceneService());One caveat for the Logger: the static
Loggerhelpers cache their backend during startup, so a mid-session replacement does not retarget them. To mute logging at runtime, setLogger.MinimumLevel = LogLevel.Offinstead — see Logger for details.
Related pages
- Service Locator — how to get any service
- Logger — diagnostics, and why mid-session backend swaps need care
- Getting Started — install, first scene, and verifying the boot log line
- Manual: What You Get — package layout and the full feature tour
- Manual: Troubleshooting — what to check when the boot log line does not appear