Skip to content

Placement Chain

The placement chain is the coordinated sequence of systems that transform player intent (cursor position + selected placeable) into a validated, instantiated object in the game world.

StepSystem / ComponentResponsibility
1Input / Actions (GBActions)Map user input (select, rotate, confirm, cancel)
2Targeting (GridTargetingState + GridTargetingSystem)Convert raw pointer position → snapped grid coordinate / normal
3Placeable Selection (UI)Present selectable items (PlaceableList / Action Bar)
4Rule Aggregation (PlacementValidator)Merge global + placeable + contextual rules
5Indicator Mapping (IndicatorManager)Generate tile indicators & diagnostics (IndicatorSetupReport)
6User Feedback (Indicators / Cursor / Build Log)Visualize valid vs invalid regions; textual reasons via build log
7Confirmation (BuildingSystem)Spawn final instance from template (with PlaceableInstance)
8Post Actions (ManipulationSystem)Move / rotate / flip / demolish / info-inspect existing objects

PlacementValidator.get_combined_rules() merges:

  • Base/global rules (project‑wide constraints)
  • Placeable-specific rules (e.g., must be on ground, cannot overlap category)
  • Context rules (environment or mode driven)

The merged list is then used to produce two paths:

  1. Tile checks (subclasses of TileCheckRule) → indicator generation.
  2. Non-tile rules → logical validation gating final placement.

The IndicatorManager.setup_indicators() call triggers:

  1. IndicatorManager.reset() — clears previous indicators.
  2. Mapping each tile rule across the candidate area.
  3. Creating RuleCheckIndicator scenes (template from GBTemplates.rule_check_indicator).
  4. Building an IndicatorSetupReport for diagnostics.

Metrics captured in the report guide debugging (counts, distinct tiles, shape owners) and are logged in verbose mode.

When the player attempts placement:

  1. PlacementValidator.validate() evaluates rule set.
  2. If valid, BuildingSystem (or similar high-level system) instantiates the final object (often via factory logic or resource reference in Placeable).
  3. A PlaceableInstance component is attached to track source metadata (for save/load & manipulation).

In addition to visual indicators and cursor state, placement success/failure and validation messages are emitted to the build log (logger output) by default. This provides a textual audit trail for rule failures (e.g., out of bounds, collision, insufficient resources) useful for debugging or surfacing in a custom UI panel. Consumers can hook into the logger or extend the PlacementValidator to route these messages into in‑game notification systems.

Rotation or flipping input updates either the preview entity or internal parameters used by rules (for bounding box, collision queries, etc.). Indicators update on each change since the manager resets and regenerates.

  • Avoid regenerating indicators when pointer hasn’t changed tile.
  • Cache combined rule lists when possible (existing code derives per attempt; can optimize later).
  • Use lightweight tile iteration; prefer integer grid math utilities (GBGeometryMath, etc.).
  • Add a custom PlacementRule to inject environment logic (biome, terrain flags, resource costs).
  • Provide specialized indicator templates (e.g., gradient intensity for distance falloff rules).
  • Inject additional debugging lines into IndicatorSetupReport.to_summary_string() for profiling.

Common failure sources:

SymptomLikely CauseMitigation
No indicatorsMissing tile rules or template reference nullEnsure GBTemplates.rule_check_indicator set
All tiles invalidGlobal exclusion rule triggeredInspect combined rule list & order
Slow placementLarge area + many tile rulesReduce rule redundancy; batch queries

Last updated: 2025-08-20

Beyond initial placement, the flow supports post-placement commands exposed through the Manipulation System.

Action column values below reference the exported property names on the GBActions resource (configured in your GBConfig): moving_mode, demolish_mode, info_mode, off_mode, and the confirmation action confirm_build (used for BOTH building and manipulation commits). The optional confirm_manipulation property presently maps to the same default input (&“confirm”) but the current implementation only checks confirm_build inside _perform_manipulation_actions().

Mode toggles are stateful: pressing (e.g.) moving_mode a second time (or off_mode) exits back to neutral OFF mode. Confirm semantics differ slightly per command.

CommandPurposePrimary Action (GBActions)Confirmation CycleFlow Impact
MoveReposition an existing placed instancemoving_mode (toggle)1st Confirm (confirm_build) = start move (creates copy); 2nd Confirm = validate & commit; Off/Cancel abortsCreates a temporary preview using the instance’s data; runs full rule validation before commit; original stays until commit or cancel
DemolishRemove an existing instancedemolish_mode (toggle)Single Confirm (confirm_build) executes demolish immediately (no copy)Validates optional removal constraints then removes target & refreshes indicators
InfoInspect metadata (cost, type, adjacency)info_mode (toggle)No confirm needed (read-only)Reads stored PlaceableInstance data; may highlight / name display; never mutates
ExitLeave any active manipulation modeoff_mode (or re‑press current mode)ImmediateCancels active move (frees copy, re‑enables physics) or exits demolish/info state
PhaseUser InputInternal Call / StateNotes
1Target object under cursor (hover/select)_states.manipulation.active_manipulatable setTarget acquisition comes from targeting system signals.
2Press moving_mode_states.mode.current = MOVEToggles MOVE mode on. Second press (or off_mode) will exit.
3Press confirm_build (first time)try_move()_start_move()Clones source → move copy parented (often under positioner) → rules set up → source physics layers disabled.
4Adjust position / rotate / flip (optional)Indicator refresh via targeting + transform ops_transform_input handles rotation/flip actions if enabled.
5Press confirm_build (second time)try_placement() → validation + commitOn success: move copy freed, original teleported to new transform, physics re‑enabled.
6Exit (implicit)_finish() / mode may auto remain in MOVEAfter commit, mode stays in MOVE; press off_mode to fully exit if desired.

Cancel Path: Press off_mode (or re‑press moving_mode) before second confirm → cancel() frees copy and restores physics; no transform applied.

PhaseInputInternalResult
1Press demolish_modeToggle mode (OFF ↔ DEMOLISH)Ready state
2Press confirm_builddemolish() → validates demolishable + _finish()Object removed, indicators refreshed
3(Optional) Exit modeoff_mode or re‑press demolish_modeReturn to neutral
PhaseInputInternalResult
1Press info_modeToggle mode (OFF ↔ INFO)Enables info inspection overlay / name display (non-mutating)
2Hover objectsExternal systems surface dataBuild chain not re-run; may reuse indicators for highlight
3Exitoff_mode or re‑press info_modeReturn to neutral
  • confirm_build is used for BOTH: (a) building a new object and (b) advancing or committing MOVE / DEMOLISH flows inside _perform_manipulation_actions().
  • confirm_manipulation currently exists but is not queried; if you want a distinct key for manipulation commits, update _perform_manipulation_actions() to check it (or remap confirm_build).

During an active MOVE (after the first confirm created the copy):

  • Rotation uses rotate_left / (optionally rotate_right if implemented in _transform_input — current snippet only shows rotate_left).
  • Horizontal flip: flip_horizontal (requires both global enable + per-manipulatable capability flag).
  • Vertical flip: flip_vertical (same gating rules).

Failures to flip emit a ManipulationData failure event with specific messages (target_not_flippable_*).

  • Starting a move without a valid manipulatable sets FAILED status with a diagnostic message.
  • If rule setup fails during _start_move(), no copy persists and status is FAILED.
  • Cancel always re‑enables previously disabled physics layers.
  • Demolish gracefully handles already deleted targets (marks FAILED & warns).
  • Active move prevents target_changed handling (ignores new hover picks until complete or cancel).

Provide contextual tooltip text that changes on the first vs second confirm in MOVE mode (e.g., “Confirm to start move” → “Confirm to place”). This reduces user confusion over dual-stage confirm semantics.

Move uses the same placement chain steps (1–7) but skips selection UI; the target instance becomes the current placeable for the duration of the move session. Demolish bypasses indicator generation (unless showing affected area) and executes a simplified validation path. Info is read‑only: it never mutates state, but may highlight tiles using existing indicators.

See also: systems/manipulation_system.md for per-command state transitions. Related detailed flow: systems/building_system_process.md.


Support / Purchase Hub: Linktree – All Grid Builder Links