Adding a tool
A tool is a piece of equipment the player holds and uses — the mining hammer-drill today, maybe a welder, scanner or cutter tomorrow.
Tool base class yetThere is currently one tool, so there is no formal Tool base class. MiningTool
(scenes/normal_player/mining_tool.gd) is the reference implementation, and the generic,
reusable piece is the EquipmentMount (scenes/normal_player/equipment_mount.gd). This
page describes the pattern to follow; copying MiningTool's structure is the fastest start.
See the recommendation at the end about factoring a base class.
The pieces
| Piece | Role |
|---|---|
EquipmentMount (equipment_mount.gd) | Generic hand mount: holds one item under the player's hand and orients it (follows the camera pitch, or aims its tip at a world point). Reusable by any tool/weapon — open/closed, you don't touch the items themselves. |
The tool node (e.g. MiningTool) | A Node3D child of the player holding the tool logic: equip/stow, per-frame update, the action, and its networking. |
| The action channel | How a tool action reaches the server and the other clients — the same client→server channel the player uses (see Props network management). |
1. Where to put the model
Tool models live under assets/models/equipments/tools/<category>/ (e.g. the drill is
assets/models/equipments/tools/mining/hammerdrill.glb). Follow
Files structure and
3D models.
2. The tool node
Add a Node3D-derived script as a child of the player (like $MiningTool), following the
MiningTool shape:
setup(camera_pivot, camera)— called from the player's_ready: cache the camera, get theEquipmentMount, andhold()the tool model in it.toggle_equip()— bound to an input action (the drill usestoggle_tool): shows / hides the held model.update_local(delta)— called each frame for the local player: aim, animate, detect when the action triggers.- State flags the player reads — e.g.
is_aiming,is_perforating. The player uses them to slow movement and freeze the mouse while aiming / using the tool.
The model is held and oriented by the EquipmentMount, placed through exported offsets (hand
offset, item offset / rotation / scale) — you don't move the model node by hand.
3. The tool action (networking)
A tool action is server-authoritative, like everything else. The pattern:
- The local tool emits a
sync_requestedsignal carrying the action data; the player connects it toclient_send_action_to_server, so the tool stays decoupled from the socket. - The server receives it in
server_action_receivedand applies the effect (the drill fractures the aimed rock). - The equipped tool and its visible state are replicated as player properties (the drill
uses a
toolsproperty + the cameraheadpitch) so other clients see you holding and using it. Remote clients apply it through the tool'sapply_remote(data), and the server sets the equipped tool viaserver_set_tool(...).
Any property you replicate for the tool (tools, head, …) must be declared in
player_def.json, or it is dropped silently. See
Replication definition files.
4. Stowing
If the tool must disappear in some states (the drill stows while the player carries an ore),
expose a set_stowed(value) and call it from the player when that state changes.
Tools follow the body (belt holster)
A stowed tool is holstered on the animated body so it moves with it (walk / crouch / jump) instead of floating at a fixed offset from the body origin. The mechanism is shared and DRY:
- The puppet exposes
player.belt_mount— aBoneAttachment3Don the hip bone, created once by theCharacterAnimator(see Character animation). It follows the animation for free. - Each tool holsters onto it with its OWN offset. The mount (the bone) is shared; the offset —
where that tool sits on the belt — is per-tool. The mining tool's
Stowgroup (stow_offset/stow_rotation_deg) is that belt pose. A new tool just readsplayer.belt_mountand supplies its own offset; no duplicated bone-finding code.
The local owner doesn't see his own stowed tool (first-person clutter); it's the remote avatars that show the holstered tool following the body. Tune the offset with a second client watching.
Recommendation
Because MiningTool is the only tool today, equip/stow, the EquipmentMount wiring and the
sync_requested plumbing all live in one script. When a second tool arrives, factor those
shared parts into a small Tool base class so a new tool only implements its own action —
the same way GenericProp factors carriable props.