Area lifecycle
Area lifecycle — two independent axes​
An Area instance has two independent state axes that must not be conflated:
| Axis | Driver |
|---|---|
| Loaded / Unloaded | Any player inside (spectators count), any linked area loaded, or AreaForceActivateService |
| Activated / Deactivated | At least one non-spectator player inside (AreaPlayerComputingService.countActiveCurrentPlayers > 0) |
A spectator alone produces (Loaded, Deactivated): the Area instance stays in memory and components remain visible, but LaserTask / victory checks / scheduled actions do not run.
Orchestration​
Transitions are owned by AreaLifecycleService:
activateAreadeactivateAreaunloadAreaAndLinkedAreas
They are driven by AreaPeriodicUpdateController — a 10-tick AreaTask orchestrator running 7 services in a fixed order:
PLAYER_COMPUTING
→ EXIT_NOTIFICATION
→ LIFECYCLE
→ ENTRY_NOTIFICATION
→ PLAYER_COUNT_NOTIFICATION
→ VICTORY_CONDITION
→ LASER_AMBIENT_SOUND
The AreaTask cadence is the only reason most area-scoped state changes happen at all.
Cleanup discipline at unload​
Every singleton holding state keyed by areaId must be purged when an area unloads, otherwise the detached Area graph stays GC-pinned.
Two existing paths cover this:
AreaLifecycleService.unloadAreaAndLinkedAreas→cleanupAreaSingletons(area)— purges:AreaComponentManager(entity-UUID → component map)AreaPlayerComputingService(player tracking maps)ComponentSyncService.unloadSyncsForAreafor sync state
AreaResetController.reset(area)(called bydeactivateArea, runs on every deactivation including spectator-only) — purges:AreaVictoryManagerComponentCounterUpdateServiceTemporaryBlockServicePortalManager- the per-area part of
BonusRegistry
Adding a new singleton with per-area state​
Adding a new singleton that keys state by areaId requires registering it in one of these two paths:
AreaResetController.OrderedStep— for state that should reset on deactivation.cleanupAreaSingletons— for state that must survive the deactivated/loaded gap and only drop on unload.
If you skip this, the area graph leaks: components disappear from the world but their per-area state stays in memory until the JVM dies.