Spawning
Place entities in the world from the spawns collection, spawn.request events and scenes: spawn points, a cap on live entities, timed respawn, hooks to change or veto a spawn.
Spawning entities from data (spawn.system) #
What it is for #
spawn.system is the one door through which a game puts entities into the world from data. Each spawn entry names a kind (a vehicle, an NPC, a prop, a pickup...), a place and some tags; the kit that registered a factory for that kind builds the entity, and a kind without a factory becomes a bare entity. The kit spawns the project spawns collection at start, answers spawn.request events from triggers and scripts, keeps a cap on how many spawned entities are alive, and brings back those tagged respawn after a delay. With game.engine, a scene can carry its own spawns that come and go with it. It draws nothing: what a kind looks like belongs to the kit behind the factory.
Turn it on #
gripforge_gamekit_install { project_id: "gkp_…", id: "spawn.system" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "spawn.system",
config: { "respawnSeconds": 5, "maxEntities": 300 } }
It requires game.engine and provides the service spawn.entities. NPC, vehicle and prop kits register their factories with it.
First example #
<!-- test: kits/game_engine/host/tests/spawn_system.rs::the_spawns_collection_is_spawned_in_document_order --> Entries of the spawns collection are spawned in document order, so entity ids are the same on every run. An entry without a valid at is skipped:
{ "spawns": [
{ "id": "c", "kind": "crate", "at": [1, 0, 1], "tags": ["loot"] },
{ "kind": "ghost" },
{ "kind": "barrel", "at": [2, 0, 2], "yaw": 0.5, "components": { "hp": 3 } }
] }
This spawns a crate and a barrel (the ghost entry has no place). spawn.entities.count() answers 2, and spawn.entities.specOf("e1") returns the first entry.
A spawn entry #
{ kind, at, id?, yaw?, tags?, components?, archetype? } where at is a point [x, y, z], { zone } (a point inside the zone) or { entity, offset? } (next to another entity). components sets initial components, archetype names one to build from.
Settings #
| Setting | Type | Default | Meaning |
|---|---|---|---|
respawnSeconds | number, 0 to 120 | 3 | seconds before an entity tagged respawn comes back at its spawn point |
maxEntities | integer, 1 to 2048 | 256 | cap on live spawned entities; a spawn above it is skipped with a warning |
Services #
spawn.entities(service), methods:spawn(spec): spawns an entry and returns the new entity id, ornullif the entry is malformed (no stringkindor noat), the cap is reached, or a hook cancelled it.despawn(id): removes an entity on purpose: it is not respawned.respawn(id, at?): removes the entity and brings it back after the respawn delay, optionally at a newat.count(): live spawned entities.specOf(id): the entry that produced an entity, ornull.
Events #
spawn.request(listened): a spawn entry as payload. A trigger can write{ "emit": { "topic": "spawn.request", "payload": {...} } }; invalid payloads are ignored.entity.despawned(listened): an entity this kit spawned was destroyed; if it was not removed on purpose and carries therespawntag, it is queued to come back.spawn.spawned(event): an entity was created, payload{ entity, kind, tags }.spawn.despawned(event): a spawned entity is gone, payload{ entity, id, kind }; sent before any respawn is planned.
Hooks and modding #
A game (a hooks document) or a mod can change these decisions without touching the kit:
spawn.entity, payload{ kind, tags }: before an entity is spawned, after the cap;kindcan be changed (another factory), a cancel spawns nothing. Then the kernel hookengine.spawnis asked (archetypeandtagscan change, a cancel spawns nothing and uses no entity id).spawn.respawn, payload{ entity, kind, delay }: before a respawn is queued;delaycan be changed, a cancel means it does not come back.
{ "id": "no_respawn", "hook": "spawn.respawn", "match": { "kind": "boss" }, "cancel": true }
A mod can override respawnSeconds and maxEntities and add, patch or remove documents of the spawns collection.
Scenes #
With game.engine, a scene's data.spawns (same entries) are spawned on entering the scene and despawned on leaving it, with no respawn; pending respawns of that scene are dropped. The project spawns stay global. A load rebuilds each entity's scene.
Engines #
The same Rust module runs on the web, the native player and the Godot, Unity and Unreal wrappers.
When it does not do what you expect #
- Nothing appears: the entry has no string
kind, or no validat; ormaxEntitiesis reached; or a hook cancelled it. - An entity does not come back: it needs the tag
respawnand must not have been removed withdespawn(that means on purpose). - A respawn comes late: check
respawnSecondsand anyspawn.respawnhook that raisesdelay. - A kind appears as an empty entity: no kit registered a factory for it; install the kit that provides it.
Limits #
- It does not decide what a kind looks like or does; factories belong to other kits.
- Respawn brings back the original entry at its spawn point, not the entity's old state.
- Scene spawns never respawn.
Versions #
Kit version 1.4.0; the service spawn.entities is at 1.0.0. Since 1.4.0 an entity is created through the kernel's engine.spawn hook after spawn.entity.