Grid Placement separates runtime logic from scene/game context.
You usually interact with three layers:
GridPlacementHost— routes the active interaction.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
Use the shipped template/injector wiring unless your game has a reason to build the runtime in code. A normal project does not need to instantiate and wire every placement service manually.
Manual composition
For a code-built scene:
host.configure(session)For independent controllers:
host.register_session(controller_root, session, device_id)The host composes the service group from the active session and configuration. Consumers should use supported host/service entry points instead of depending on internal scene paths.
Context injection
Use contexts/providers for facts that come from the current game scene, for example:
- target
TileMapLayerorGridMapsurface; - 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 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.
Avoid replacing plugin services only to change naming or add logging.