Grid Placement separates runtime logic from scene/game context. This is the canonical guide for host/session composition beyond the starter setup.
You usually interact with three layers:
GridPlacementHost— routes the active interaction and composes runtime services.PlacementSession— stores per-player/controller state and configuration references.- Context/provider adapters — connect the current level, player, and game facts to placement validation/services.
Default path
For a standard single-session scene, use the host/session path directly:
- Add a
GridPlacementHostto the scene root or systems scene. - Assign
GridPlacementHost.sessionand enableauto_configure. - Assign
GridPlacementHost.grid_placement_bundle. - Assign each
GridPositioner2D.session(orGridPositioner3D.session) to thePlacementSessionowned by that player/controller. - Author
PlacementLevelContextandPlacementOwnerin the scene.PlacementLevelContextsays where objects land (level-owned);PlacementOwnersays who is placing (player/controller-owned). They are separate because levels and players often instance separately.
When GridPositioner2D.session is assigned, the positioner configures itself from that session and registers it with the nearest GridPlacementHost at runtime. With auto_configure enabled the host composes the services, registers the session, and binds scene consumers itself at _ready, so a single-session scene needs no script. A controller does that work instead when the game owns session lifetime.
A normal project also does not need to instantiate every placement service manually. The host composes the configured service group from the bundle/session. On a 3D-dimensions bundle it additionally builds the authoritative GRID object service itself from the bound level context, unless the scene already bound its own.
Explicit host configuration
Use explicit configuration when code owns the session lifecycle — split-screen or per-device sessions, sessions created at runtime, or sessions restored by save/load. Leave auto_configure off in this shape.
host.configure(session)For independent controllers:
host.register_session(controller_root, session, device_id)Unregister the controller/session when its owning scene or controller leaves. Keep one session per independent interaction; players that need separate selection, targeting, coordinate mode, or pending manipulation state should not share a session.
Consumers should use supported host/service entry points instead of depending on internal scene paths.
Binding scene consumers
GridPlacementHost.bind_scene_consumers(root, session) walks a scene subtree and
calls each consumer's existing resolve_placement_dependencies and
resolve_placement_runtime hooks. Controllers call it after configure() so UI,
previews, and helpers receive their dependencies without per-node scene exports. With
auto_configure enabled the host calls bind_scene_consumers() and
watch_scene_consumers() itself at _ready, rooted at the current scene.
Positioners self-register from their session export and are skipped.
Context injection
Use contexts/providers for facts that come from the current game scene, for example:
- target
TileMapLayerorGridMapsurface (plus themapslist once a 2D level uses more than one gameplay layer); - placed-object parent;
- placement owner/controller;
- game-owned reserved/occupied zones;
- inventory, cost, or world-state facts used by custom rules.
Do not copy those facts into long-lived plugin globals when their lifetime belongs to a level, session, or game system.
Shared placement world
Dimension-specific services still need to agree on the same committed placement world.
This matters for:
- GRID vs SMOOTH conflicts;
- CELL/EDGE/FACE/CORNER/TOP mount occupancy;
- SMOOTH socket occupancy;
- multiple sessions;
- save/restore.
Do not build a second occupancy registry that can commit conflicting placement state.
When to inject a custom service/provider
Add custom composition only when the project needs a real policy or integration point. Examples:
- a game-owned world-facts provider;
- custom placement validation rule;
- inventory/refund bridge;
- custom input/controller/session setup.
Non-node helpers are plain RefCounted objects that read what they need from a PlacementSession. Do not write new integration code around removed PlacementContainer compatibility types.
Avoid replacing plugin services only to change naming or add logging.
Troubleshooting composition
Check these before changing plugin code:
GridPlacementHostexists in the relevant scene/systems tree.- The host actually started:
auto_configureenabled withsessionassigned, or a controller that calledconfigure()andregister_session(). GridPositioner2D.sessionis assigned for scene-authored controller wiring.- The host and session use the intended
GridPlacementBundle. PlacementLevelContextandPlacementOwnerbelong to the active level/controller lifetime.- Scene consumers: verify
host.bind_scene_consumers(root, session)ran for the active controller scope.
Related guides
Using this in a game?
Grid Placement v6.3.0 — full source, playable demos, commercial license
The guide above is the same setup the shipped demos use. Try the build in your browser before you buy it.