Rooms and bases
Usage guide of build.modular: structures with the modular.room component have an inside, joined structures form a base, with the service, events, conditions and the base.shelter hook that changes what a room does to survival gauges.
Rooms and bases (build.modular) #
What it is for #
Pieces that join become a place. A structure of build.placement carrying the modular.room component has an inside: the player standing in it is indoors, and the room does to the survival gauges what its document says (a supply per second, a drain multiplier) for as long as they stay. Structures joined through their sockets form a base as soon as one of them is a room; the kit tells when the player enters and leaves a room or a base, when a base gains or loses a room, and when two bases are merged by a joining piece. What a room is and what it does is data: shelters, habitats, stations, houses, ships.
Turn it on #
gripforge_gamekit_install { project_id: "gkp_…", id: "build.placement" }
gripforge_gamekit_install { project_id: "gkp_…", id: "build.modular" }
A structure is a room when its buildable (a document of build.placement) carries modular.room: label (shown in the variable base.room, default the buildable name), inside ([width, height, depth] of the inner box, default the structure size; the box is centred, turned with the structure and rises from its floor), needs (for each survival.needs gauge, supply units per second and drain as a multiplier on the gauge’s own drain, 0 stops it; applied on entering, removed on leaving) and tags (free words, given back by rooms()). The player is inside while their position is in the box. A base is named after the smallest entity id among its pieces, so its id does not change as it grows. Make a corridor a room too, with the same needs, and the whole base is one inside.
{ "id": "cabin", "name": "Cabin", "size": [4, 3, 4],
"sockets": [{ "id": "door", "at": [0, 0, 2], "yaw": 0, "type": "door" }],
"components": { "modular.room": { "label": "Cabin", "needs": { "air": { "supply": 8, "drain": 0 } } } } }
First example #
<!-- test: kits/game_engine/host/tests/build_modular.rs::joined_structures_are_a_base_and_a_room_feeds_the_gauges --> A corridor and a habitat (a room giving warmth supply 5) are placed and joined through their sockets: the base appears with its rooms and center, the player entering the habitat feeds the gauge, and a save and reload bring the room back without announcing it.
build.placement.place("corridor", [0,0,0])
build.placement.place("hab", [0,0,0], 0, { "snapTo": { "entity": <corridor>, "socket": "e", "own": "w" } }) event: base.changed
build.modular.bases() -> [{ "id": <corridor>, "rooms": [<hab>], "structures": [<corridor>, <hab>], "center": [1.5, 0, 0] }]
player moves to [3,0,0] events: base.entered variable base.room = "Habitat" survival.needs.value("warmth") rises
Settings and defaults #
The kit has no setting and no collection of its own: what a room is comes from the buildables of build.placement, which a mod may add to or patch.
Services #
rooms()lists the rooms as{ entity, label, base, position, inside, tags }.bases()lists the bases as{ id, rooms, structures, center };baseOf(entity)gives the base of a structure or null.inside()gives the room the player stands in (or null) andcurrent()the base they are in (or null).
Variables: base.inside (the player is in a room) and base.room (its label). Conditions for scripts: inside_base (the player stands in a room) and base_has_rooms { count } (the largest base has at least that many rooms).
Events #
| Name | Detail |
|---|---|
base.entered | The player walked into a room; payload { room, base }. |
base.left | The player walked out of a room; payload { room }. |
base.joined | The player entered a base from outside; payload { base }. Going from a room to another room of the same base does not tell it. |
base.exited | The player left a base for outside; payload { base }. |
base.changed | A base gained or lost a room (a structure placed or taken down, two bases merged by a joining piece, one split in two); payload { base, rooms } with the rooms now (empty: the base is gone). |
Hooks and modding #
A game or a mod changes this decision with a document of its hooks list, without touching the kit:
base.shelter: asked when the player walked into a room (or came back in it after a load) and the room is about to act on one survival gauge: once per need of the room, when its effects are set, never while the player stays; payload{ room, base, label, need, drain, supply }; a tap may changedrain(the multiplier, 1 when the room gives none) andsupply(units per second, 0 none), or cancel so the room does nothing to that gauge. Not asked withoutsurvival.needs.
{ "id": "thin_air", "hook": "base.shelter", "match": { "need": "air" }, "mul": { "supply": 0.5 } }
When it does not do what you expect #
- A room does nothing to the gauges:
survival.needsis not installed, theneedsname does not match a gauge, or the player is not inside the box (checkinside()and theinsidesize). - Pieces do not form a base: no piece is a room yet, or their sockets are not joined (see
build.placement: sockets join when their types match, they are at the same point and face each other).
Limits #
- The kit creates and keeps nothing: rooms and bases are read from the structures, again after a load, and a load announces nothing.
- It decides nothing about building (that is
build.placement) and has no display module. Targets web and native players.
Versions #
1.1.0 (2026-10-10): the hook base.shelter; 1.0.0 (2026-10-04): first release. Requires build.placement 1.1 or later and game.engine; survival.needs is optional.