Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Spawners, population and reservations

Worlds fill themselves with creatures under provable caps, never in any player’s view, and agents claim what they are about to use so two of them never fetch the same drop. The design and its rationale are in Talos E (docs/superpowers/specs/2026-09-27-talos-e-coordination-population-design.md) §8 and §11; this page is the current contract for what phase E1 built (the “hunt and fetch” slice: one spawner region with caps and the Ambient policy, and the minimal reservation the pet uses).

Source: manifold_ai::coord (crates/manifold-ai/src/coord/) (wasm-safe logic: registries, components, caps, the rate-limit queue, despawn bands, traces, the reservation table, the spawn atoms) and the server wiring in manifold_server_state::coord (crates/manifold-server-state/src/coord/) (the three systems, visibility, persistence metadata, console commands). Tests: the unit tests in manifold-ai, crates/manifold-ai/tests/determinism_guard.rs, the coord::tests module of manifold-server-state and game/flagship/tests/spawn_content.rs.

Data

Three server-side registries (the data stage):

RegistryDirectoryEntry
manifold-ai:spawn-categoryspawn_categories/SpawnCategory(id, per_player, per_region, counts_toward_hard_cap)
manifold-ai:spawn-rulespawn_rules/SpawnRule(id, archetype, category, weight, conditions, density: (per_region, category_per_region), distance: (min, max), persistence)
manifold-ai:spawnerspawners/a content-placed spawner: Spawner(id, shape: Region(min, max), source: Rules([...]), policy, max_alive, cadence, attempts_per_eval, respawn: (delay, catch_up_max), leash, enabled)

References (archetype, category, the rules) are checked with file and line. Durations are ticks (160) or seconds ("4s"). conditions is a gameplay condition in the spawn context set. E1 refuses the Encounter and Persistent policies, and every shape and source but Region and Rules, naming the phase that brings them.

Spawn atoms. A condition atom sees only its evaluation context, so the spawner measures the cell first and passes what it measured as set-by-caller values (SpawnFacts on A’s SpawnParams and SpawnContext); archetype variant conditions read the same facts. Registered through gameplay_extensions():

AtomArgumentsHolds when
manifold:sky_lightat_leastthe cell’s sky light is at least that (15 under open sky, 0 under an opaque block within 64 blocks: the server keeps no light maps)
manifold:surface_blockblockthe block under the creature’s feet has that key (checked against the world’s blocks at load)

Spawners

A spawner is an entity with manifold-ai:spawner (Spawner) and manifold-ai:spawner-state (SpawnerState: pending respawns as absolute ticks), both server-only and persisted, with Persistence::Saved. The first spawner pass after boot (after restore) creates one entity per content placement that has none; Spawner.placement remembers the key, so a restored spawner is never made twice.

Each creature carries SpawnedBy(spawner) (manifold-ai:spawned-by: exclusive, Remove on delete, Keep on unload, persisted as a link), whose reverse index is the spawner’s alive count; SpawnOrigin (policy, rule, category, the attributed player, spawn tick; transient); and Home (anchor cell, the spawner’s leash or the shape’s extent; persisted).

SpawnerSystem runs in the AI block (after ResolveActionHandles, before navigation) every tick:

  1. content placements become spawner entities (once);
  2. deaths in last tick’s CombatEvents.died schedule now + delay on their spawner (a creature-to-spawner map covers corpses despawned in the same tick);
  3. every enabled spawner whose shape a client subscribes to asks navigation to build around it (ServerNav.focus_requests);
  4. each due spawner (its cadence, staggered by durable id) evaluates: the allowance (max_alive minus the living, the queued and respawns not yet due, at most catch_up_max); nothing if no client subscribes to the shape; a rule by weight (DerivedRandom, site manifold-ai:spawn.rule); C’s find_spawn_cells over the box, at least distance.min from every player and hidden from every subscribed player; then per cell, in order, the rule’s conditions and the caps; accepted cells join the queue;
  5. the queue drains at each space’s rate limit through spawn_archetype_batch, in request order (tick, spawner id, ordinal).

Spawns are placed at the tick phase’s flush, so an archetype’s anim-setup hook gives the creature its ServerAnim in the flush that creates it.

Never in view. The eyes are every player whose client subscribes to the shape’s interest regions, however far (entity scope is a cube of 64-block regions reaching about 192 blocks). A viewer sees a point inside its 110° view cone (from its yaw and pitch) that one voxel ray from its eye reaches. ViewerSight is C’s LineOfSight over the world’s blocks until D’s line-of-sight service exists; /ai population shows the rays cast this tick. A queued spawn that waited re-checks that its cell is still standable and hidden, and is dropped otherwise (the next evaluation places again).

Caps and the rate limit

CapScopeDefault
Localcreatures of a category in the 27 regions around a player; a candidate passes if any player that can draw it is undercategory per_player (10)
Regioncreatures of a rule, and of its category, in the candidate’s regionrule density, category per_region
AmbientAmbient creatures in the space256 (PopulationConfig)
Fair shareabove 80 % of the ambient cap, the attributed player (the nearest subscriber) keeps at most cap × 0.8 / players

The census counts living ambient creatures and queued spawns when a spawner is due. PopulationConfig holds each space’s settings: the ambient cap, the encounter ceiling (1,000; directors spend it, E3) and the spawn rate limit (16 per tick).

Despawning

DespawnSystem checks each Ambient creature once a second (staggered by durable id); corpses are B’s.

SituationRule
no client subscribes to its region (whether or not its chunk is resident)despawn now
within 32 blocks of a playernever
engaged: a non-empty Targets, OwnedBy or a held reservationnever
idle less than 30 snot yet
visible to a subscribed player (the placement test)not while seen
otherwise2.5 % per check (DerivedRandom, site manifold-ai:despawn)

Ambient creatures are Persistence::Session: after a restart they are gone, and the saved spawner spawns afresh by its rules. For the same reason every band despawns as DespawnReason::Destroyed, including the one for a chunk that is no longer resident: the creature never returns under its id, so it is not Unloaded (entity core (docs/architecture/entity-core.md)).

Reservations

ReservationTable (a resource) holds claims keyed by target, slot (Whole, Slot, Job, Cell) and layer. A task posts ReservationRequests::claim(ClaimRequest::whole(holder, target)), renew or release; ReservationSystem resolves them every tick in one batch: releases, renewals, expiry (default 30 s unless renewed), then claims, the best score winning each target and ties going to the lower durable id. At most four claims per holder per tick (Throttled); a lost contest backs off 2 s, doubling to 16 s. A target’s capacity is its Reservable component, else 1. Outcomes (Granted, Renewed, Released, Denied(..), Lost(Expired | TargetGone | HolderGone)) are in ReservationOutcomes after the pass. The holder’s HeldReservations mirrors the table; its remove hook releases everything when the holder despawns, and the pass ends claims whose target despawned or whose holder died. Reservations are not saved.

Traces and console

CoordTraces keeps the last 32 records per spawner (attempts with the rule weights, each rejected cell and why, queue waits, spawns, despawns with their band) and per reservation holder. Admin commands:

CommandShows or does
/entity spawner listevery spawner, its shape, rules, alive count and queue
/entity spawner info <#id or key>its state and recent trace
/entity spawner eval <spawner>evaluates it now
/entity spawner reset <spawner>clears pending respawns and its queue
/ai reservations [#id]claims, optionally of one holder or target, with its trace
/ai populationper space: ambient count and cap, category counts, queue, rate limit, rays

Limits

  • PlayerAnchored and Points shapes, herds, Encounter and Persistent policies, promotion, directors and doAmbientSpawning are later phases.
  • Visibility rays are counted but not charged to D’s AI budget, and the traces are always-on rings until D’s decision trace sink exists.
  • No biome atom: the server has no biome source.