Recipes
Timers countdowns cooldowns and enemy waves
A round clock ticks down, enemies arrive in waves, or an ability recharges after a cooldown.
TimerComponent is a real atomic (pack timer.v1); its runtime fires RuntimeTimerFired on a server-owned interval. There is no RespawnTimerComponent or SpawnPoolComponent; those are this same pattern.engine v1.0.234since script-semantic-patch-ops.v1, action-catalog.v1.0.232, timer.v1, spawn.v1, match.v1, persistence.v1Copy for LLM
Use this for
a round countdown or match clock; ability cooldowns and regen tickers; spawning enemies in timed waves; anything that repeats or fires after a delay on a server-owned schedule
Not for
reacting to player input (see input-mapping-actions-bindings); persistent save data across sessions (see saves-and-persistence); the win or lose transition itself (see match-flow-and-scoreboards)
Pairs with: Match flow phases scoreboards and win conditions, Spawn points checkpoints and respawn flow, UI HUD panels widgets and world nameplates, Projectiles bullets and ranged weapons
The recipe
Author with project_apply_script_semantic_patch using the ai_safe op pack.
- Attach the clock:
project_add_componentaTimerComponentwith{ "timerKey":"round", "intervalSeconds": 1, "repeating": true, "maxFirings": 0 }(0 means unlimited;intervalSecondsminimum is 0.01). - Subscribe:
addTimerHandler{ "handlerKey":"onRoundTick", "timerKey":"round" }. The runtime delivers thetimerKeyand the firing iteration to the handler. - Countdown: seed the remaining seconds with
writeTypedStateValue{ "field":"timeLeft", "valueType":"number", "value": 60 }, then each fireincrementNumericState{ "field":"timeLeft", "by": -1 }andwireHudStateBindingit to the HUD. When it reaches 0,declareWinConditionor transition the match phase (see match-flow-and-scoreboards). - Enemy waves: use a slower timer (for example
intervalSeconds: 20). Each fire,spawnEntityFromTemplate{ "prefabKey": <enemy> }a batch at spawn points, andincrementNumericStateawavecounter to scale the next batch. - Cooldown: a one-shot delay is a
TimerComponentwithrepeating: falseandmaxFirings: 1, or a last-used timestamp compared against the current tick; set areadyboolean withsetBooleanStatewhen the cooldown elapses.
Pitfalls
intervalSecondshas a floor of 0.01; do not expect sub-10ms timers.- The timer is server-owned and authoritative; every client sees the same fires. Do not run a parallel client clock.
- Keep the countdown value and the wave counter in durable state, not a local variable, so they survive a reload and read consistently on the HUD.
- A repeating timer with
maxFirings: 0never stops on its own; disable it (patchenabled: false) when the round ends or waves are cleared, or it keeps spawning. - Give each timer a distinct
timerKey; one entity can carry several timers andaddTimerHandlerroutes by that key.
Verify
simulation_run(qa.run.start) to watch the countdown decrement to zero and a wave spawn on each interval.project_get_graph_snapshotto confirm theTimerComponentand the timer handler are on the entity.