Building
Usage guide of build.placement: structures as documents placed with a see-through preview, cost and refund, sockets that join pieces, take-down and salvage, with settings, service, events, verbs and hooks.
Building and placement (build.placement) #
What it is for #
The player places structures in the world: pick one from the build menu, aim a see-through preview at the ground, turn it, confirm — its cost leaves the bag and it stands there, solid. A structure is a document: a name, a cost, a size, and the components it carries, so a placed workbench crafts, a placed generator supplies a need, a placed machine produces. Structures can list sockets: near a free one the preview snaps so that pieces join into a whole, and the joints are kept. Structures can be taken down for a refund, and things found in the world can be taken apart for their materials and for the knowledge of how to build them. Survival bases, modular buildings, farms, tower defence, city builders, housing.
Turn it on #
gripforge_gamekit_install { project_id: "gkp_…", id: "build.placement" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "build.placement", config: { "reach": 8, "refund": 0.5, "snapDistance": 3 } }
A structure is a document of the buildables collection: id and name (required), description, category (a heading of the menu), cost (up to 12 { item, count }, taken when placed), size ([width, height, depth] in metres, default 2 × 2 × 2), solid (blocks the player, default true), components (read by other kits: craft.station, need_source, machine…), tags, unlocked (false hides it until unlock_buildable or a salvage that names it), sockets (up to 24: { id, at, yaw, type }, local to the structure with its origin on the ground at its centre and +z its front; two sockets join when their types are equal, they are at the same point and face each other) and snap (required means it can only be placed joined to a free socket, default optional). One model per structure is the asset buildable (variant = the buildable id), origin on the ground at its centre, front toward +Z.
{ "id": "wall", "name": "Wall", "cost": [{ "item": "wood", "count": 2 }], "size": [2, 2, 0.4],
"sockets": [{ "id": "l", "at": [-1, 0, 0], "yaw": 270 }, { "id": "r", "at": [1, 0, 0], "yaw": 90 }] }
First example #
<!-- test: kits/game_engine/host/tests/build_placement.rs::a_preview_is_paid_stands_and_the_next_one_snaps_to_its_socket --> A wall costs two wood and has two sockets. Confirming without wood is blocked with the reason cost; after giving wood the first wall stands, the preview stays out and snaps to its free socket, the second wall joins it, and taking the second down refunds its wood and frees the joint.
begin("gate") -> false begin("wall") -> true confirm() -> { "reason": "cost" }
inventory.items.give("wood", 4) confirm() -> { "ok": true, "entity": <first> }
placing().snapped.to == <first> confirm() -> <second> connected(<first>) -> [<first>, <second>]
dismantle(<second>) -> true inventory.items.count("wood") -> 2 joints(<first>) -> {}
Settings and defaults #
| Setting | Default | Meaning |
|---|---|---|
reach | 6 | How far from the player a structure can be placed (metres) |
grid | 0.5 | Positions snap to this step (0: free) |
rotateStep | 45 | Degrees per rotate press |
refund | 1 | Share of the cost given back when a structure is taken down (0 to 1) |
freeBuild | false | Structures cost nothing (creative mode) |
maxStructures | 500 | Maximum structures standing at once (1 to 5000) |
snapDistance | 2.5 | A preview with sockets snaps to a free matching socket within this distance of the aim point (metres; 0: never) |
keyHints | false | The placing bar lists the live key bindings (place, rotate, cancel); off by default, since no key is shown on screen outside a tutorial: the bar then shows the structure and whether it fits |
A game or a mod may change all eight settings and add to or patch the buildables collection.
Default input actions: build_menu (B), build_confirm (left click or Enter), build_rotate (R), build_cancel (right click or Backspace) and build_dismantle (X); a player can remap them.
Services #
buildables()lists the structures;menu(open?)opens or closes the build menu;begin(id)starts a preview (false for a locked or unknown structure);cancel()drops it;placing()describes it, withsnappedwhen it joins a socket.aim(point | null)moves the preview,rotate(steps?)turns it (to the next side of a socket when snapped),confirm()pays and places it and answers{ ok, entity }or{ ok: false, reason }withreasonone ofcost,overlap,outside,far,limit,socket,locked,unknown.place(id, at, yaw?, { snapTo }?)stands a structure from a script with no cost and no reach;dismantle(entity)takes one down with the refund (false when a hook cancels);structures()lists the ones standing.unlock(id)andunlocked(id)reveal and test a locked structure;sockets(entity),joints(entity)andconnected(entity)read the sockets, the kept joints and the whole joined group of a structure.salvage(entity)takes apart something found in the world (an entity with thesalvagecomponent{ buildable, gives, label }): its items go to the bag and the buildable it names is unlocked; it answers{ ok: false }when refused;salvageable()lists what can be taken apart.
Variables: build.menu (menu open), build.placing (the structure being placed) and build.count (structures standing). Script verbs: the actions place_structure { buildable, at, yaw } and unlock_buildable { buildable }, and the condition structure_built { buildable, count }.
Events #
Events: build.started { buildable } (the preview is out), build.placed { buildable, entity, position, yaw }, build.blocked { buildable, reason } (the reasons above, or the reason of a build.place tap that cancelled, refused by default), build.cancelled { buildable }, build.removed { buildable, entity, refund }, build.unlocked { buildable } and build.salvaged { entity, buildable, gave } (what reached the bag and the buildable it names).
Hooks and modding #
A game or a mod changes these decisions with a document of its hooks list, without touching the kit:
build.place: the player confirms a preview that can stand there, before the structure is paid and placed; payload{ buildable, position, yaw, snapped, costFactor }; a tap may changecostFactor(a multiplier of every cost count: 1 the document, 0 free; counts are rounded, and above 1 the bag is checked again and a short one refuses withcost); cancelled, nothing is taken or placed andbuild.blockedcarries the tap’s reason. Not run forplace()andplace_structure(scripts: no cost, no reach).build.remove: a standing structure is about to be taken down; payload{ entity, buildable, refund }; a tap may changerefund(the share of the cost given back, from the setting) for this one; cancelled, it stays, nothing is given back anddismantleanswers false.build.salvage: something found in the world is about to be taken apart; payload{ entity, buildable }with the buildable it teaches (empty: none); cancelled, it stays, nothing is given or unlocked andsalvageanswers{ ok: false }.
{ "id": "half_price", "hook": "build.place", "match": { "buildable": "wall" }, "mul": { "costFactor": 0.5 } }
When it does not do what you expect #
confirm()answers a reason:cost(the bag is short),overlap(it touches a standing structure),outside(outside the world),far(beyondreach),limit(maxStructuresreached),socket(snap: requiredand no free socket in range),lockedorunknown.- The preview never snaps: the structure lists no
sockets, the neighbour has none free of the sametype, orsnapDistanceis 0.
Limits #
- Structures are saved with the game, with what is unlocked and the joints. The kit draws only the preview and the build menu; the rooms and bases made of joined pieces are the job of the next guide.
Versions #
1.4.0 (2026-10-23): keyHints added, off by default (migrated automatically); 1.3.0 (2026-10-10): hooks build.place, build.remove, build.salvage; 1.2.0: the salvage model slot; 1.1.0: sockets; 1.0.0 (2026-10-04): first release. Requires input.actions and game.engine.