Recipes
Manager scripts driving many objects from one system
You have a crowd, a swarm, a field of pickups, or a wave of enemies that all behave the same. Put ONE manager script on ONE entity that drives the whole cohort, instead of attaching a script to every member. This is the default shape for a homogeneous population.
engine v1.0.234since script-semantic-patch-ops.v1, action-catalog.v1.0.232, world.v1, spawn.v1, mutation.v1, persistence.v1Copy for LLM
Use this for
one server-side script that controls a whole population of objects; a spawner or director that drives many behavior-less entities; central orchestration instead of a script per entity; batch updates over a group
Not for
a single self-driven mover (see moving-platforms-and-elevators); per-player input behavior (see input-mapping-actions-bindings); the match phase and scoreboard (see match-flow-and-scoreboards)
Pairs with: Timers countdowns cooldowns and enemy waves, Spawn points checkpoints and respawn flow, NPC and enemy navigation chase and patrol behavior, Match flow phases scoreboards and win conditions
The recipe
Author with project_apply_script_semantic_patch using the ai_safe op pack. The manager is an entity with a ScriptComponent.
- Tag the cohort: give every member a shared tag (for example
mob) so one query finds them all. - Enumerate on a beat:
addTickHandler{ "handlerKey":"onManage" }(or a coarseraddTimerHandlerfor slow updates). Inside,findEntitiesByTag{ "tag":"mob", "assignTo":"mobs", "limit": 64 }, or use the pagedctx.world.queryin a GessaScript body for larger sets (pass itsnextCursorback verbatim to page). - Act on each member:
forEachEntityInResult{ "arrayRef":"mobs" }whose body uses only the loop-intent ops (despawnEntity,emitCustomEvent,incrementNumericState,attachComponentWithValidatedDefaults). For richer per-member work (move, retarget), iterate in a GessaScript body and callctx.entity.patchComponenton each. - Spawn and cull centrally: keep the population at a target size by
spawnEntityFromTemplatewhen short anddespawnEntitythe excess or the dead, all from the one manager. - Shared state: hold cohort-level counters (alive count, wave number) in durable state with
incrementNumericStateso the manager and the HUD read one truth.
Pitfalls
forEachEntityInResult.bodyaccepts ONLY the four loop-intent ops; anything richer must run in areplaceScriptFromGessaScriptbody iterating the result.- Bound every scan: cap
findEntitiesByTaglimitandforEachEntityInResultmaxIterations(both cap at 1000) and pagectx.world.queryrather than pulling everything each tick. - The collision and per-tick budgets cap at 1000 entities; a manager that keeps spawning without culling will hit the ceiling.
- Run the manager on the authority; do not also run a client copy or the cohort double-updates.
Verify
simulation_run(qa.run.start) to watch the manager spawn, update, and cull the cohort over several ticks.project_get_graph_snapshotto confirm the single managerScriptComponentand its tick or timer handler.