Skip to content

Grid Placement v6.3.0

Placer Ownership

Where the acting placer lives, how to bind it from the Inspector or from code, and which value wins.

Status
Current
Version
v6.3.0
Source updated
2026-10-29
Generated on
2026-10-29

6.3. These pages document the 6.3 release, where placeable is now entry (what changed) and PlacementOwner is deprecated (migration). Still on 6.2? Your version's guides ship inside the plugin itself, under addons/grid_placement/guides/; the 6.2 URLs on this site now redirect to this series.

Development docs. This page describes the unreleased 6.3 build.

The placer is the node placement acts through: the character or controller whose inventory, range, or cost rules apply. In 6.3 the PlacementSession owns that value. Targeting, validation, commit, manipulation, reporting and refund consumers all read it from the session rather than from a scene node.

Two ways to set it:

  1. Inspector (scene-authored setups). Assign placer_root on the GridPositioner2D or GridPositioner3D that already holds your session and camera. The positioner writes it to the session when it becomes ready.
  2. Code (controller-created, restored, headless, split-screen). Call session.set_placer_root(node) yourself. Nothing else has to exist in the scene.

Reading it back:

var actor:Node = session.get_placer_root()# null == actor-free

session.get_placer_root() is the only authoritative answer. If you need the node consumers act through — including the legacy adapter node — ask the provider: session.get_contexts().owner.get_effective_owner().

Precedence

Both paths write the same session value, so the rule is about who may overwrite whom. The positioner never clobbers a binding it did not write.

Situation session.get_placer_root()
Positioner has placer_root, session has nothing bound the positioner's node
Code called set_placer_root(actor) first the code-bound node; a non-null positioner value does not replace it
Positioner's placer_root is cleared cleared only when that exact node was what the session held
Only a legacy PlacementOwner exists its owner_root, through the legacy adapter
Legacy node and an explicit binding, values differ the explicit binding wins, and a runtime issue names both nodes
Nothing bound anywhere null — actor-free (see Actor-Free Placement)

A freed placer reads as null. Scene changes re-bind when the positioner becomes ready again, so do not cache the placer across a level load: ask the session each time.

Two sessions, two actors

Each session owns its own placer, which is what makes split-screen and multiplayer work: one positioner per session, each with its own placer_root, or one explicit set_placer_root call per session. The sessions may target the same grid; the placer never crosses between them.

# Split-screen: each player controller owns its session.
player_one_session.set_placer_root(player_one)
player_two_session.set_placer_root(player_two)

What the positioner does not decide

placer_root is not the camera and it is not the inventory owner. In 3D the camera is a separate assignment on the positioner; in every dimension the placer answers "who is acting", nothing more. Range, cost and unlock policy stay in the rules your game enables.

Diagnostics

session.get_runtime_issues() reports a missing placer only when an enabled rule needs one, and a legacy/explicit disagreement is reported by name:

No placer assigned but rule '<rule id>' requires one. Assign
GridPositioner2D/3D.placer_root or call PlacementSession.set_placer_root().

PlacementOwner 'PlacementOwner'.owner_root differs from the session placer
root 'Player'; the session binding wins. Remove the legacy PlacementOwner node
or clear one of the two.

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.