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.

Source: module-kits:kits/build_modular/usage/en.mdView Markdown source

Also read offline — CLI: grip-forge docs build-modularMCP tool: gripforge_docs { "topic": "build-modular" }

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) and current() 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 #

NameDetail
base.enteredThe player walked into a room; payload { room, base }.
base.leftThe player walked out of a room; payload { room }.
base.joinedThe player entered a base from outside; payload { base }. Going from a room to another room of the same base does not tell it.
base.exitedThe player left a base for outside; payload { base }.
base.changedA 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 change drain (the multiplier, 1 when the room gives none) and supply (units per second, 0 none), or cancel so the room does nothing to that gauge. Not asked without survival.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.needs is not installed, the needs name does not match a gauge, or the player is not inside the box (check inside() and the inside size).
  • 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.