docs
Systems
Infrastructure
ApplicationSystem
Key Components

ApplicationCoordinator

The main manager for the application. It is an abstract MonoBehaviour, so each project creates a concrete subclass and attaches it to a root GameObject in the startup scene.

Responsibilities:

  • Singleton and persistence: In Awake, the first instance becomes Instance, is marked DontDestroyOnLoad, and is registered with InitializationRegistry as both a sync and an async initializable. Duplicates are destroyed.
  • Startup sequencing: Init creates the ApplicationLogicManager. InitAsync subscribes InitializeApplication to SaffronLibrarySignals.SystemsReady through the SignalBus and awaits InitializeVolumeState.
  • Project hooks: Subclasses implement RegisterPlatformModules, RunPlatformModules, InitializeStartupPresentation, InitializeVolumeState, CreateLifecycleHandler, and CreateLifecycleAdapter.
  • Query answering: ProcessQuery answers focus-duration queries and writes the result to CoreParamKeys.Duration.

Interaction with dependencies:

  • SignalBus (through ServiceLocator) notifies the coordinator when SystemsReady is raised.
  • InitializationRegistry and InitializationManager decide when Init and InitAsync run.
  • ApplicationFlowController forwards Application-domain queries to ProcessQuery.

ApplicationFlowController

The FlowController for Domain.Application. It is the connection between the query bus and the coordinator.

Responsibilities:

  • Registers the command handler for Domain.Application through the base class.
  • Registers OnQuery with the QueryBus for Domain.Application.
  • Forwards each query to ApplicationCoordinator.Instance.ProcessQuery.
  • Has an empty HandleCommand, because no commands are routed through this domain.

Interaction with dependencies:

  • FlowController (base class) registers with the CommandBus during Init.
  • QueryBus routes queries to OnQuery.
  • ServiceLocator provides the bus registry used to reach the QueryBus.

ApplicationLifecycleHandler

The abstract base for project lifecycle handlers. It implements IApplicationLifecycleHandler.

Responsibilities:

  • Its OnFocusChanged method raises the standard focus-changed event through ApplicationEventFactory before calling the project hook. Projects cannot override OnFocusChanged.
  • Projects implement ProcessFocusChanged to react to focus changes.

Interaction with dependencies:

  • ApplicationEventFactory raises the event on Domain.Application through the EventBus.
  • ApplicationCoordinator receives the handler through SetLifecycleHandler during startup.

UnityLifecycleAdapter

A MonoBehaviour that connects Unity's application callbacks to the framework. It implements IApplicationLifecycleAdapter.

Responsibilities:

  • Its private OnApplicationFocus forwards focus changes to the handler set through Initialize, if one is set.
  • Its private OnApplicationQuit calls ApplicationEventFactory.OnApplicationQuit.
  • GetRealtimeSinceStartup returns Time.realtimeSinceStartup, so ApplicationCoordinator and ApplicationLogicManager use the same clock.

Interaction with dependencies:

  • ApplicationCoordinator calls Initialize during its lifecycle setup.
  • The adapter raises events through ApplicationEventFactory, which uses the EventBus.

IApplicationLifecycleHandler and IApplicationLifecycleAdapter

The two contracts that separate engine code from project code.

  • IApplicationLifecycleHandler receives OnFocusChanged(bool) calls. ApplicationLifecycleHandler is the standard implementation.
  • IApplicationLifecycleAdapter provides Initialize(handler) and GetRealtimeSinceStartup(). UnityLifecycleAdapter is the Unity implementation.

Projects that run on another engine implement the adapter for that engine, and the rest of the system stays unchanged.

ApplicationLogicManager

A plain C# class that owns focus-loss timing.

  • SetFocusLossTime(float) records the time focus was lost.
  • GetFocusLossDuration(float) returns the elapsed time since that record.

It is created by ApplicationCoordinator.Init and stored in the protected logicManager field. It has no MonoBehaviour dependency.

ApplicationEventFactory and ApplicationQueryFactory

Two static factories that build messages for Domain.Application.

  • ApplicationEventFactory raises the focus-changed and quit events through BusUtility.Raise.
  • ApplicationQueryFactory builds the focus-duration query and returns its answer through BusUtility.AskAndGet.

Both use ApplicationParamKeys for subject and state values. Both depend on the bus system to deliver messages.

ServiceLocator

A static class that holds the BusRegistry for global access. InitializationManager sets it during bootstrap, and ApplicationFlowController, ApplicationCoordinator, and the factories read it through GetBusRegistry.

ApplicationFlowService

A static partial class with content-agnostic helpers. Its one method, ResetLocalData, clears PlayerPrefs and then calls an optional reload action supplied by the caller. Projects can extend the class in other files.

Event and key types

  • ApplicationEventVerb (Changed, Quit) describes what happened.
  • ApplicationSubjects (Focus, Application) describes what the message is about.
  • ApplicationKeyNames and ApplicationParamKeys define the names and typed keys used in Params.
  • ApplicationConstants.PausedGameSpeed provides the time scale value used to pause game time.