gmp(M02): extract local player movement
Work-Package: M02-GMP-MOVEMENT-001 Agent: sindo-main-codex Tests: local movement and player input regressions; asset-free scene; renderer dry-run; coordinate, streaming, documentation and coordination gates Fidelity: preserves current sandbox speed, acceleration, sprint and camera-relative flight behavior; build-12340 parity remains unverified
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
# Local Player Movement
|
||||
|
||||
## Metadata
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Status | Implemented |
|
||||
| Target/work package | M02 / M02-GMP-MOVEMENT-001 |
|
||||
| Owners | Gameplay local movement state; scene composition owns the instance |
|
||||
| Last verified | `working tree`, 2026-07-14 |
|
||||
| Profiles/capabilities | Current render sandbox; production/debug profile gate pending |
|
||||
|
||||
## Purpose
|
||||
|
||||
Own current local velocity, acceleration and sandbox flight state independently
|
||||
of the player scene. Convert an immutable `MoveIntent` plus an explicit
|
||||
Godot-world movement basis into deterministic per-tick displacement without
|
||||
querying terrain, cameras, input devices or visual assets.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Apply world transforms or own a `CharacterBody3D`.
|
||||
- Query terrain height, collision, water or slopes.
|
||||
- Implement jump, fall, swim, server prediction or reconciliation.
|
||||
- Select the player basis versus camera-pivot basis; the scene adapter owns that decision.
|
||||
- Claim build-12340 movement fidelity from sandbox regression alone.
|
||||
|
||||
## Context and boundaries
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Input[MoveIntent] --> Movement[LocalPlayerMovementController]
|
||||
Basis[Explicit local movement Basis] --> Movement
|
||||
Delta[Physics delta seconds] --> Movement
|
||||
Movement --> Displacement[Godot-world displacement]
|
||||
Movement --> Velocity[Read-only velocity state]
|
||||
Scene[ThirdPersonWowController] --> Basis
|
||||
Displacement --> Scene
|
||||
Scene --> Transform[Player world transform]
|
||||
Scene --> Terrain[Ground snap adapter]
|
||||
Velocity --> Presentation[Visual facing and animation adapter]
|
||||
```
|
||||
|
||||
Allowed dependencies:
|
||||
|
||||
- `MoveIntent` from the gameplay input boundary.
|
||||
- Godot value types `Basis` and `Vector3` for renderer world-space direction math.
|
||||
- Main-thread scene adapter for basis selection and displacement application.
|
||||
|
||||
Forbidden dependencies:
|
||||
|
||||
- `Node`, `Resource`, `Input`, `Camera3D`, `ADTLoader` or scene lookup.
|
||||
- World-coordinate conversion or manual ADT/tile formulas.
|
||||
- Character assets, animation players, materials, packets or server state.
|
||||
|
||||
## Public API
|
||||
|
||||
| Symbol | Kind | Purpose | Thread/lifetime | Errors |
|
||||
|---|---|---|---|---|
|
||||
| `LocalPlayerMovementController.new(...)` | Constructor | Sets explicit speeds, acceleration and sandbox sprint multiplier | Created by composition root; retained for player scene lifetime | Caller owns configuration validation |
|
||||
| `godot_world_velocity_units_per_second` | Read-only state | Current Godot-world velocity after the last update | Stable until next mutation on owning thread | None |
|
||||
| `is_flight_enabled` | Read-only state | Current sandbox free-flight mode | Stable until toggle | None |
|
||||
| `toggle_sandbox_flight()` | Command | Toggles flight and clears velocity | Owning physics/input thread | Returns new flight state |
|
||||
| `advance(move_intent, godot_world_movement_basis, delta_seconds)` | Stateful update | Accelerates toward requested velocity and returns displacement for the tick | Owning physics thread; one call per tick | Negative delta is treated as zero |
|
||||
|
||||
Constructor units:
|
||||
|
||||
| Parameter | Unit/meaning |
|
||||
|---|---|
|
||||
| `run_speed_units_per_second` | Forward Godot units per second |
|
||||
| `backward_speed_units_per_second` | Backward Godot units per second |
|
||||
| `strafe_speed_units_per_second` | Lateral Godot units per second |
|
||||
| `flight_vertical_speed_units_per_second` | Sandbox vertical Godot units per second |
|
||||
| `acceleration_units_per_second_squared` | Velocity change per second |
|
||||
| `sandbox_sprint_multiplier` | Dimensionless debug multiplier |
|
||||
|
||||
## Inputs and outputs
|
||||
|
||||
| Direction | Contract/data | Producer | Consumer | Ownership | Thread/lifetime |
|
||||
|---|---|---|---|---|---|
|
||||
| Input | `MoveIntent` | `PlayerInputSource` | Movement controller | Immutable caller-held value | One physics tick |
|
||||
| Input | Godot-world `Basis` | Player scene adapter | Movement controller | Value copy | One physics tick |
|
||||
| Input | Delta seconds | Godot physics loop | Movement controller | Scalar value | One physics tick |
|
||||
| Input | Flight toggle command | Remappable sandbox action via scene adapter | Movement controller | Synchronous command | Input event dispatch |
|
||||
| Output | Displacement `Vector3` | Movement controller | Player scene adapter | Value copy | Applied in same tick |
|
||||
| Output | Velocity `Vector3` | Movement controller | Facing/animation adapter | Read-only value copy | Until next update |
|
||||
| Output | Flight state | Movement controller | Basis/terrain scene adapter | Read-only boolean | Until next toggle |
|
||||
|
||||
Side effects:
|
||||
|
||||
- Mutates only controller-owned velocity and flight state.
|
||||
- Does not mutate scene tree, transforms, resources, filesystem, network or cache.
|
||||
- The scene adapter remains responsible for transform mutation and ground snap.
|
||||
|
||||
## Data flow
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Intent[MoveIntent axes] --> Target[Calculate target velocity]
|
||||
Basis[Player or camera-pivot Basis] --> Directions[Forward/right directions]
|
||||
Directions --> Target
|
||||
Config[Speeds and sprint multiplier] --> Target
|
||||
Previous[Owned velocity] --> Integrate[move_toward by acceleration × delta]
|
||||
Target --> Integrate
|
||||
Integrate --> Current[Updated velocity]
|
||||
Current --> Step[velocity × delta]
|
||||
Step --> Displacement[Scene-applied displacement]
|
||||
```
|
||||
|
||||
## Lifecycle/state
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> GroundedSandbox
|
||||
GroundedSandbox --> FlyingSandbox: toggle / clear velocity
|
||||
FlyingSandbox --> GroundedSandbox: toggle / clear velocity
|
||||
GroundedSandbox --> GroundedSandbox: advance
|
||||
FlyingSandbox --> FlyingSandbox: advance
|
||||
```
|
||||
|
||||
The names describe the existing sandbox mode only. They are not authoritative
|
||||
gameplay movement states and do not imply terrain contact or server permission.
|
||||
|
||||
## Main sequence
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Input as PlayerInputSource
|
||||
participant Scene as ThirdPersonWowController
|
||||
participant Move as LocalPlayerMovementController
|
||||
participant Present as Facing/Animation adapter
|
||||
Input-->>Scene: MoveIntent
|
||||
Scene->>Move: advance(intent, selected basis, delta)
|
||||
Move-->>Scene: displacement
|
||||
Scene->>Scene: apply global position and ground snap
|
||||
Scene->>Move: godot_world_velocity_units_per_second
|
||||
Scene->>Present: horizontal motion
|
||||
```
|
||||
|
||||
## Ownership, threading and resources
|
||||
|
||||
- The player scene creates and exclusively owns one movement controller.
|
||||
- Velocity and flight state have the same lifetime as that controller.
|
||||
- All mutations currently occur on the main input/physics thread.
|
||||
- Read-only value returns are copies; consumers cannot mutate owned state.
|
||||
- No Nodes, Resources, RIDs, files, jobs or worker threads are created.
|
||||
- The supplied `Basis` is a Godot-world direction basis, not a typed world-position contract or coordinate conversion.
|
||||
|
||||
## Errors, cancellation and recovery
|
||||
|
||||
| Failure | Detection | Behavior | Diagnostic | Recovery |
|
||||
|---|---|---|---|---|
|
||||
| Negative physics delta | `advance` guard | Returns zero displacement; velocity unchanged | Unit regression | Resume with valid non-negative delta |
|
||||
| Missing scene basis owner | Scene composition defect | Controller cannot be called correctly | Scene/parser error or boundary test | Restore explicit scene dependency |
|
||||
| Flight toggle during motion | Command path | Velocity clears before next step | State-transition regression | Continue from zero velocity |
|
||||
| Missing terrain data | Outside module | Scene skips existing ground snap | Existing terrain diagnostics | TerrainQuery extraction will own policy |
|
||||
|
||||
There is no asynchronous cancellation, retry or rollback. Recreating the
|
||||
controller resets velocity and flight state deterministically.
|
||||
|
||||
## Configuration and capabilities
|
||||
|
||||
| Setting/capability | Default | Profile | Runtime mutable | Effect |
|
||||
|---|---|---|---|---|
|
||||
| Forward speed | `7.0` units/s | Current sandbox | Fixed for controller lifetime | Target forward velocity |
|
||||
| Backward speed | `4.5` units/s | Current sandbox | Fixed for controller lifetime | Target backward velocity |
|
||||
| Strafe speed | `4.5` units/s | Current sandbox | Fixed for controller lifetime | Target lateral velocity |
|
||||
| Acceleration | `28.0` units/s² | Current sandbox | Fixed for controller lifetime | Acceleration and deceleration |
|
||||
| Flight vertical speed | `7.0` units/s | Sandbox debug | Fixed for controller lifetime | Vertical free-flight target |
|
||||
| Sprint multiplier | `6.0` | Sandbox debug | Fixed for controller lifetime | Multiplies planar and vertical targets |
|
||||
| Camera-relative basis | Selected only while flight is enabled | Sandbox debug | Per tick | Preserves existing pitched flight direction |
|
||||
|
||||
## Persistence, cache and migration
|
||||
|
||||
Movement state is transient and not serialized. No schema, cache, migration or
|
||||
saved settings change is introduced. Future reconnect/replay state requires a
|
||||
separate versioned movement snapshot contract.
|
||||
|
||||
## Diagnostics and observability
|
||||
|
||||
- Logs: verifier emits `LOCAL_PLAYER_MOVEMENT PASS` or named invariant failures.
|
||||
- Metrics: none yet; update is constant-time vector math.
|
||||
- Debug views: current character facing and animation remain observable scene outputs.
|
||||
- Correlation IDs: not applicable to synchronous local sandbox state.
|
||||
|
||||
## Verification
|
||||
|
||||
- Unit/contract: `src/tools/verify_local_player_movement.gd` covers forward,
|
||||
backward, strafe, rotated basis, acceleration, deceleration, sprint, flight,
|
||||
pitched camera basis, state reset and invalid delta.
|
||||
- Boundary: verifier rejects Node/Input/Camera/ADT dependencies and movement
|
||||
integration/state remaining in the player scene.
|
||||
- Scene integration: `verify_player_input.gd` drives the asset-free player
|
||||
regression scene through forward motion and immediate flight toggle.
|
||||
- Fidelity evidence: default values and formulas are regression-locked against
|
||||
the pre-extraction sandbox. No original-client comparison is claimed.
|
||||
- Performance budget: constant-time vector math, no per-tick I/O or scene lookup;
|
||||
`MoveIntent` allocation remains owned by the input package.
|
||||
|
||||
## Extension points
|
||||
|
||||
- Terrain/collision policy can consume displacement without changing input or velocity ownership.
|
||||
- A future server-aware predictor may replace this controller behind the scene composition boundary.
|
||||
- A typed movement snapshot may expose deterministic replay state when M08/M09 require it.
|
||||
- Sandbox debug capability gating can reject sprint/flight before commands reach this controller.
|
||||
|
||||
## Capability status
|
||||
|
||||
| Capability | Status | Evidence | Gap/next step |
|
||||
|---|---|---|---|
|
||||
| Scene-free local velocity state | Implemented | Pure controller and source boundary regression | Integrate target checklist after review |
|
||||
| Existing planar acceleration/speeds | Implemented | Exact numeric unit cases and real scene regression | Compare with build 12340 before fidelity claim |
|
||||
| Existing camera-relative free flight | Implemented | Pitched-basis and toggle/reset cases | Restrict to sandbox profile |
|
||||
| Terrain/collision movement policy | Planned | Outside module by design | Extract `TerrainQuery` next |
|
||||
| Jump/fall/swim | Planned | M02/M09 roadmap | Requires terrain/liquid and server contracts |
|
||||
| Prediction/reconciliation | Planned | M08/M09 roadmap | Requires movement snapshot/network contract |
|
||||
|
||||
## Known gaps and risks
|
||||
|
||||
- Numeric defaults preserve the existing sandbox but are not original-client evidence.
|
||||
- Configuration is captured at scene `_ready`; runtime mutation of exported speed
|
||||
properties does not reconfigure an existing controller.
|
||||
- Ground snap remains in the player scene until `TerrainQuery` extraction.
|
||||
- Sprint and free flight still lack a typed sandbox capability gate.
|
||||
- The module uses Godot math value types; a future engine-independent gameplay
|
||||
predictor may require scalar/domain movement contracts.
|
||||
|
||||
## Source map
|
||||
|
||||
| Path | Responsibility |
|
||||
|---|---|
|
||||
| `src/gameplay/movement/local_player_movement_controller.gd` | Owned velocity/flight state and deterministic integration |
|
||||
| `src/scenes/player/third_person_wow_controller.gd` | Composition, basis selection, displacement/terrain/presentation adapters |
|
||||
| `src/tools/verify_local_player_movement.gd` | Pure numeric, state-transition and dependency regression |
|
||||
| `src/tests/scenes/player_input_regression.tscn` | Asset-free integrated player fixture |
|
||||
| `src/tools/verify_player_input.gd` | Input-to-movement scene regression |
|
||||
|
||||
## Related decisions and references
|
||||
|
||||
- ADR: none; this follows the existing M02 decomposition boundary.
|
||||
- Upstream/reference: `targets/02-player-decomposition.md`,
|
||||
`targets/roadmap/04-gameplay-systems.md`, `docs/ARCHITECTURE.md`.
|
||||
Reference in New Issue
Block a user