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-> Triggersset_active_manipulatableor 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/rotationof the Move Copy (interpolating from Targeting System).
- Updating
- Physics:
- Disabling/Enabling collision layers via
PhysicsLayerManager(delegated).
- Disabling/Enabling collision layers via
- Indicators:
- Setting up / Tearing down
RuleCheckIndicators (delegated toIndicatorManager).
- Setting up / Tearing down
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:
- Decide Validation Rules: It must not contain logic like “can I place here?” or “is this object movable?”. This belongs in
ManipulationService2DorManipulationStateMachine. - Manage Internal Data State: It should not manually construct
ManipulationDatastructs if possible; it should ask theManipulationService2Dto create them. - Directly Mutate Other Systems: It should not directly call
TargetingSystemto 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:
- Receives Input.
- Forwards to Service/Orchestrator.
- Receives Description of Effects.
- Applies Effects.