Modules
The Modules system runs small initialization units before the first scene loads. It provides ordering and discovery only; ownership, shutdown, and per-frame behavior remain the responsibility of the initialized service.
Use a RuntimeModule when a subsystem must register global services or warm
process-wide state before scene content starts. Do not use it as a replacement
for scene lifecycle components.
Define a Runtime Module
Derive from RuntimeModule, implement Initialize, and override Order when
the module depends on another startup step:
using Ceres.Modules;
using UnityEngine;
using UnityEngine.Scripting;
[Preserve]
public sealed class TelemetryModule : RuntimeModule
{
public override int Order => 200;
public override void Initialize()
{
Debug.Log("Telemetry services initialized.");
}
}
Modules are instantiated with Activator.CreateInstance, so each concrete type
must have an accessible parameterless constructor. Initialization runs in
ascending Order; the default order is 100.
Initialize is synchronous. Start asynchronous work explicitly from the module
or delegate it to a project-owned startup coordinator when later systems must
await completion.
Startup Contract
An internal loader marked with
RuntimeInitializeOnLoadMethod(BeforeSceneLoad) performs startup in this order:
- Prepare packaged config files through the Configs module.
- Load
ModuleConfig. - Resolve module types from the explicit list or by assembly scanning.
- Instantiate the modules, sort them by
Order, and callInitialize()once.
ModuleConfig.Modules is authoritative when it contains at least one entry. An
empty list falls back to scanning loaded non-Editor assemblies for every
non-abstract RuntimeModule subtype.
Configure the explicit list in Project Settings > Ceres > Module Settings. Register All scans the current project and writes the discovered types to the project config.
Use the explicit list for IL2CPP builds. It avoids depending on runtime assembly
scanning and gives the build pipeline concrete serialized type references.
Apply Unity's PreserveAttribute or an equivalent linker rule to module types
whose only reachability is reflective construction.
Ordering and Dependencies
Order is the only dependency mechanism supplied by the module loader. Keep
the values coarse enough to insert another module later:
public sealed class NetworkModule : RuntimeModule
{
public override int Order => 100;
public override void Initialize() { }
}
public sealed class MatchmakingModule : RuntimeModule
{
public override int Order => 200;
public override void Initialize() { }
}
Modules with the same order have no documented relative order. Assign distinct orders when one module requires another to be initialized first.
The loader does not catch exceptions from constructors or Initialize. A
failure stops the remaining startup sequence, so surface configuration errors
with enough context to diagnose them.
Module Configuration
ModuleConfig is a normal Ceres config stored at Ceres.Modules. It contains:
| Member | Purpose |
|---|---|
Modules |
Explicit list of serialized RuntimeModule types. |
MetaData |
Project-defined string key/value data available during startup. |
The module array does not determine execution order; each constructed module's
Order property does. Invalid serialized types are skipped while resolving the
explicit list.
Project code may read or update metadata through the standard Configs API:
using Ceres.Modules;
var config = ModuleConfig.Get();
config.MetaData["environment"] = "staging";
config.Save();
Use metadata only for small startup values. Structured subsystem settings
belong in their own Config<TConfig> type.
Related API: RuntimeModule and ModuleConfig.