Resource nodes
Usage guide of resource.nodes: ore veins, bushes and crystals that give items, need tools, run out and grow back; seeded scatter, service, events, hooks and the resource_nodes collection.
Gatherable resources in your world (resource.nodes) #
What it is for #
resource.nodes manages the resource points of the world: ore veins, bushes, wrecks, crystals. A node gives an item a number of times, may need a tool, runs out and grows back. Nodes are placed by hand (a component on any entity) or scattered over the ground from a seed. The kit does not know what iron or berries are: a node is a document of the resource_nodes collection, and the item it gives belongs to inventory.items. Every node is an entity, so the save keeps what is left of it. Good for survival, crafting, farming, and any game where resources are collected. Machines can draw from nodes too: see Extraction.
Turn it on #
gripforge_gamekit_install { project_id: "gkp_…", id: "resource.nodes" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "resource.nodes",
config: { "seed": 7, "scatter": [ { "node": "iron_vein", "count": 30, "radius": 80 } ] } }
It requires game.engine. With interaction.system a node shows a prompt and using it gathers; with inventory.items the item goes into the bag. Without an inventory resource.gathered is still emitted, so another kit can act on it. Targets: web and the Rust kit host.
First example #
<!-- test: kits/game_engine/host/tests/resource_nodes.rs::a_node_runs_out_then_grows_back_or_is_removed -->
{ "id": "rock", "name": "Rock", "item": "stone", "count": 2, "uses": 2, "respawnSeconds": 0.5 }
Spawning this node and calling gather answers { ok: true, item: "stone", count: 2 }. After the second use the third call answers reason depleted, and the node is hidden (tags hidden, depleted). After respawnSeconds, resource.respawned fires and it is back with its uses. A node with no respawnSeconds (a bush) is removed from the world when it runs out. resource.gathered counts the units taken.
Data: the resource_nodes collection #
| Field | Type | Default | Meaning |
|---|---|---|---|
id, name, item | string | required | The node id, its name, the item given. |
count | integer 1 to 999 | 1 | Units per gather. |
uses | integer 1 to 999 | 1 | Gathers before the node runs out. |
respawnSeconds | number 0 to 86400 | none | Seconds to grow back; 0 or absent: gone for good. |
tool | string | none | An item the player must hold to gather (a pickaxe); never consumed. |
size | number 0.1 to 20 | 0.8 | Size of the stand-in box in metres. |
extractable | boolean | false | A machine standing on it may draw from it (resource.extraction). |
Models come from the asset slot resource_node, variant = the node id; without one a stand-in box is shown.
Placing nodes #
- Scattered (setting
scatter): the same seed gives the same world. An entry takesnode,count(required, up to 400),center([x, z], default where the player starts),radius(default most of the world),spacing(least distance to any other node, default 2.5) andworld(spread in that world only, on the first tick spent there, withtravel.worlds). Unknown node ids are skipped. - By hand: an archetype with the component
resource_node { node }, a project spawn of kindresourcecarryingresource.node, the actionspawn_resource { node, at }, or the servicespawn.
Settings and defaults #
| Setting | Type | Default | Meaning |
|---|---|---|---|
scatter | list (up to 40) | [] | Nodes spread over the ground when the game starts. |
seed | integer | 1 | Changes where the scattered nodes land. |
clearSpawn | number 0 to 100 | 4 | No scattered node closer than this (metres) to where the player starts. |
gatherLabel | string | Gather {name} | Prompt of a node. |
toolLabel | string | {name} — needs {tool} | Prompt when the tool is missing. |
Service, events and variables #
Service resource.nodes:
types(),nodes(): the node documents; the placed nodes withentity,node,left,depleted,position.gather(entity):{ ok, reason?, item?, count? }; reasons includeunknown,depleted,tool,full,refused.spawn(node, at, yaw?),deplete(entity),restore(entity).scope(id),scopeId(): the world scatter used bytravel.worlds.extract(entity, { consume? }):{ item, count, left }or null, for machines.
| Name | Detail |
|---|---|
resource.gathered | { node, entity, item, count, left }: the player took units; left is the gathers before it runs out. |
resource.blocked | { node, entity, reason, tool }: reason tool, full or refused. |
resource.depleted | { node, entity, respawnSeconds } (0: for good). |
resource.respawned | { node, entity }. |
resource.extracted | { node, entity, item, count, left }: a machine drew one gather. |
resource.gathered | Variable (number): resources gathered. |
It listens to interaction.requested, entity.spawned and inventory.changed.
Hooks and modding #
| Hook | Payload | Mutable | Cancelled |
|---|---|---|---|
resource.harvest | { node, entity, item, count, left } | count | Nothing gathered; resource.blocked with reason refused. |
resource.extract | { node, entity, item, count, left, consume } | count | extract answers null, nothing drawn. |
resource.deplete | { node, entity, respawnSeconds } | respawnSeconds | Not cancellable (0: gone for good). |
resource.respawn | { node, entity, item } | none | The node waits its respawnSeconds again. |
{ "id": "rich_veins", "hook": "resource.harvest", "match": { "node": "iron_vein" }, "mul": { "count": 2 } }
A mod may override scatter, seed, clearSpawn, gatherLabel and toolLabel, and add, patch or remove documents of resource_nodes.
When it does not do what you expect #
- Nothing is gathered,
resource.blockedwithtool: the player does not hold the item named bytool. full: the bag has no room for the item.- No node appears: check the node id in
scatter, and that the first tick has run. - The same node layout in every game: that is the seed; change
seed.
Limits #
- No stand-in model beyond a box: provide a
resource_nodeasset per node. - A node gives one item type.
Versions #
Kit 1.3.1; service resource.nodes 1.2.0. Worlds since 1.1.0, extraction since 1.2.0, hooks and moddable data since 1.3.0.