Grid Placement

ManipulationSystem Boundary Contract

Responsibilities

ManipulationSystem is a Godot-facing adapter and orchestrator of effects. It bridges the gap between the Godot SceneTree (Signals, Input, Nodes) and the pure backend logic (ManipulationService2D, ManipulationStateMachine).

1. Event Listener (Inputs)

It listens for state changes and user input that trigger manipulation workflows.

  • Input: _unhandled_input (Keyboard/Mouse) -> Triggers Mode Toggle, Rotation, Flip, Demolish.
  • Signal: _states.targeting.target_changed -> Triggers set_active_manipulatable or clears it.
  • Signal: _states.mode.mode_changed -> Triggers cancellation of active manipulation if mode switches (e.g. to OFF).
  • Signal: _states.building.preview_changed -> Triggers setup of “Build Preview” manipulation data.

2. Effect Executor (Outputs)

It executes side effects requested by the backend. It does NOT decide what to do, only how to do it in Godot.

  • Scene Tree Ops:
    • Spawning/Despawning Move Copies.
    • Reparenting nodes.
    • Queue Freeing nodes (Demolish).
  • Transforms:
    • Updating global_position / rotation of the Move Copy (interpolating from Targeting System).
  • Physics:
    • Disabling/Enabling collision layers via PhysicsLayerManager (delegated).
  • Indicators:
    • Setting up / Tearing down RuleCheckIndicators (delegated to IndicatorManager).

3. State Publisher

  • Emits signals for UI/Feedback: move_indicators_ready.
  • Updates GBStates.manipulation.data (via Service).

Non-Responsibilities (The “Anti-Contract”)

ManipulationSystem must NOT:

  1. Decide Validation Rules: It must not contain logic like “can I place here?” or “is this object movable?”. This belongs in ManipulationService2D or ManipulationStateMachine.
  2. Manage Internal Data State: It should not manually construct ManipulationData structs if possible; it should ask the ManipulationService2D to create them.
  3. Directly Mutate Other Systems: It should not directly call TargetingSystem to force a retarget. It should request state changes.

Boundaries & Seams

| Boundary | Interaction | Owner | | asc | asc | asc | | Input -> Logic | _unhandled_input -> _orchestrator.rotate() / _service.toggle_mode() | ManipulationSystem | | Logic -> State | Service updates _states.manipulation.data | ManipulationService2D | | Logic -> Effect | Service returns commands / effects -> System applies them | ManipulationSystem | | Scene -> Backend | target_changed (Node) -> set_active_manipulatable(Manipulatable) | ManipulationSystem |

Refactoring Goal

Move all “decision making” (if/else blocks checking states, validation) into ManipulationService2D / ManipulationStateMachine. ManipulationSystem becomes a dumb terminal that:

  1. Receives Input.
  2. Forwards to Service/Orchestrator.
  3. Receives Description of Effects.
  4. Applies Effects.