document the player-input design in architecture.md
This commit is contained in:
@@ -124,13 +124,31 @@ Within a single simulation tick, subsystems run in this fixed order. The order i
|
||||
Three product targets plus tests:
|
||||
|
||||
- `lib/` — simulation + config. Depends on Qt Core + Qt Gui, toml++, tinyexpr. No QtWidgets.
|
||||
- `ui/` — QtWidgets + `QOpenGLWidget` code: header bar, game world view, selection panel, build button bar. Depends on `lib` and on Qt's OpenGL widgets module.
|
||||
- `ui/` — QtWidgets + `QOpenGLWidget` code: header bar, game world view, selection panel, build button bar, controls panel. Depends on `lib` and on Qt's OpenGL widgets module.
|
||||
- `ui/selection/` — the selection panel's contents. `SelectionPanel` itself only arbitrates between the two selection categories, picks a card from the catalog (`SelectionContentFactory`), and hosts one at a time; each kind of selection has its own `SelectionContent` subclass assembled from shared parts (REQ-UI-SELECTION-CARD, REQ-UI-SELECTION-CONTENT).
|
||||
- `app/` — thin `main()` that creates the simulation, the UI, and wires them together. Depends on `ui`.
|
||||
- `tests/` — Catch2 tests. Links only against `lib`.
|
||||
|
||||
Directory discipline inside `lib/` keeps the internal sim/config seam clear; sim code must not reach into config parsing and vice versa.
|
||||
|
||||
## Player Input
|
||||
|
||||
Every player control is declared once, in `lib/core/ControlAction.h`, and read by three consumers that must never disagree about it:
|
||||
|
||||
* **`ControlsPanel`** asks which actions apply and draws a row per action (REQ-UI-CONTROLS-CONTENT).
|
||||
* **`InputMapper`** resolves a key press to an action and fires the event that action stands for.
|
||||
* **`GameWorldView`** resolves a mouse gesture to an action and runs the branch that carries it out.
|
||||
|
||||
The file declares; it never performs. It holds no simulation access, fires no events, and names nothing — display strings live in `ui/ControlActionText.h`, which renders each badge from the binding the resolver actually matches, so a chip cannot claim a key that does nothing. What an action *does* stays in the widget that always did it: the drag state machines, hit-testing, and command enqueuing were not moved.
|
||||
|
||||
Three invariants are easy to break here:
|
||||
|
||||
* **Do not add a shortcut straight to `InputMapper`'s switch or `mousePressEvent`'s branches.** Add the action and its binding to the table; the handler switches on the resolved action. A binding added directly is invisible to the panel, which is the drift the table exists to prevent. (Build hotkeys and `F3`/`F4` are deliberate exceptions, documented in the header and in REQ-UI-CONTROLS-ACCURACY.)
|
||||
* **Availability and display are different questions.** An action can be live in a context the panel does not advertise it in — `Ctrl`+click with an empty selection is the standing example. `isControlActionAvailable` answers the first, the per-context row lists answer the second, and `ControlActionTest` asserts the pairing that matters: every row's bindings resolve back to that row's action.
|
||||
* **Gesture state is shared, not owned by an action.** Whether a belt drag is in progress decides what the right mouse button means, so it lives on `BuildModeController` where the resolver can see it — as does the hovered-transfer flag. `m_boxSelecting` is likewise one gesture serving two actions (box select and deconstruct area).
|
||||
|
||||
`ControlContext` is a plain snapshot rather than references to the live controllers, which is what keeps the rules testable without a world and stops an action reaching into the simulation: if a rule needs a fact, the fact is named in the struct and the caller supplies it. When bindings become player-configurable, only the binding tables in `ControlAction.cpp` turn from hard-coded data into loaded data.
|
||||
|
||||
## Belt Subsystem
|
||||
|
||||
Belts and splitters are their own specialized subsystem. Belt items are **not** entities — they are transient data flowing through the belt representation. They do not have identities that persist across ticks.
|
||||
|
||||
Reference in New Issue
Block a user