Placement Workflow

This guide explains the Grid Building 5.0.8 placement workflow.

Version note: This guide is validated for Grid Building 5.0.8. The workflow is unchanged from 5.0.4. See Patch Notes for specifics.

5.0.8 is node-centric: scene nodes, composition container wiring, and stateful services/systems cooperate to place objects. This workflow represents the complete lifecycle of a placement action.

In 5.0.8, placement is driven by node/state interactions:

  1. Build entry
    • UI or game code calls BuildingSystem.enter_build_mode(placeable).
  2. Input/Targeting
    • GridPositioner2D and TargetingShapeCast2D update targeting state.
  3. Rule Validation
    • Rules evaluate against runtime context.
  4. Indicator Sync
    • Preview/indicator feedback reflects current validity.
  5. Commit/Reject
    • BuildingSystem.try_build() finalizes or rejects the action.

Detailed Placement Workflow

Phase 1: Preparation & Validation Setup

Before placement can occur, the system must have a valid placeable and a ready scene context.

  • System Entry
    • Call building_system.enter_build_mode(placeable).
  • Dependency Guard
    • The building system checks whether it is ready to build.
  • Selected Placeable
    • selected_placeable is assigned.
  • Preview Cleanup
    • Previous preview state is cleared.
  • Manipulation Reset
    • If a manipulation parent exists, it is reset before creating the new preview.
  • Mode Switch
    • Mode changes to BUILD.
  • Preview Setup
    • A preview instance is created and placement setup runs for the selected rules.

5.0.4 update: Recursive cleanup in BuildingSystem is now guarded by _cleaning_up to prevent double-cleanup when called from multiple exit paths (e.g., mode changes during cleanup).

Phase 2: Runtime Validation

As the user moves the cursor, the active preview and its indicators are validated continuously.

  • Positioning
    • GridPositioner2D moves the preview root to tile centers.
  • Target acquisition
    • TargetingShapeCast2D updates the targeted object.
  • Rule context
    • Rules receive GridTargetingState.
  • Checks
    • Bounds.
    • Collisions.
    • Placeable-specific constraints.
    • Optional gameplay rules such as SpendMaterialsRuleGeneric for inventory or cost spending.
  • Result generation
    • Rules return RuleResult.
    • Placement issues aggregate into PlacementReport.

5.0.4 update: CollisionUtilities.does_indicator_overlap_shape() now correctly computes shape-owner transforms including per-shape local offsets (added shape_owner_id parameter).

Phase 3: Execution & Commit

When the user confirms placement, the system attempts to commit the action.

  • Input path
    • Build confirmation is handled by build input or explicit calls into the build system.
  • Final validation
    • The active placement must still be valid.
  • Instantiation
    • The final scene instance is created from the placeable/template path.
  • pre_instance_added signal (new in 5.0.4)
    • BuildingState.pre_instance_added is declared on BuildingState but emitted by BuildingSystem after scene instantiation but before add_child().
    • This allows external code to configure instances before _ready() runs.
  • Placement parent
    • The object is added under the configured GBLevelContext.objects_parent.
  • Apply hooks
    • Rules that implement side effects can run apply().
  • Cleanup
    • Preview/indicator state is cleaned up.

Common Pitfalls

  • Direct property assignment
    • Avoid driving placement by mutating selected_placeable directly.
  • Missing level context
    • No objects_parent means final placement has nowhere valid to go.
  • Dirty state
    • Resource deductions and game-state side effects belong after successful placement.
  • Preview confusion
    • Preview objects are not the same as committed placed objects.

State Management

A robust workflow relies on the shared runtime state being the source of truth.

  • Do not duplicate validation logic in your UI.
  • Drive placement from system entry points.
  • Keep UI reactive to states/systems rather than reconstructing placement truth independently.

What Plugin Users Should Remember

  • Starting placement is a system call, not just a state change.
  • Level wiring is part of the workflow contract.
  • Placement rules are part of the runtime loop, not just static configuration.
  • Targeting and manipulation interact with placement through shared state.