feat/player-movement #2

Merged
Serkyo merged 45 commits from feat/player-movement into dev 2026-08-22 05:56:53 +00:00
Owner

What does this PR do?

Implements an end-to-end, server-authoritative, client-predicted player movement system over the voxel terrain with reconciliation and camera smoothing.

An exhaustive breakdown of every change made in this branch across all crates and subsystems:

1. Core Collision & Voxel Query (crates/shared)

  • Block Extent Conventions (world::bounds): Centralized half-open block extent arithmetic ([i, i + 1)) so floor inverts extents consistently across collision, meshing, and culling.
  • VoxelQuery Trait (movement::query): Added spatial query abstraction returning Option<BlockId> where None indicates an unloaded chunk (treated as a solid obstacle rather than air to prevent falling through the void).
  • AABB Colliders & Stances (movement::collider): Defined player bounding boxes across three stances according to ADR 0012 (Standing: 0.75×1.75 m, Crouching: 0.75×1.25 m, Crawling/Sliding: 0.75×0.75 m).
  • Swept AABB Collision (movement::sweep): Substepped, axis-separated collision resolution in fixed order (X, Y, Z) with blocker classification (Blocker::Solid, Blocker::Unloaded).
  • Attempt-and-Revert Step-Up (movement::sweep): Clear low obstacles up to 1.2 voxels (0.6 m) by attempting elevated forward displacement and reverting to ground-level sweep if blocked.

2. Deterministic Locomotion Controller (crates/shared)

  • Fixed Timestep: Evaluates physics at a fixed 60 Hz rate (dt = 1/60s) without variable delta time.
  • Tuned Movement Profile (movement::profile): Configured locomotion ladder speeds (Sneak: 1.5 m/s, Walk: 4.0 m/s, Run: 6.0 m/s, Sprint: 8.5 m/s, Slide initial: 10.0 m/s), gravity (32 m/s²), jump apex times, and stance heights.
  • Dedicated Deceleration Ramp: Separate 90 u/s² ground deceleration rate so speed is shed quickly upon releasing input or downshifting gaits instead of coasting.
  • Air Control & Wall Momentum: Clamped air control preserving horizontal momentum during airborne wall contact (clearing velocity only while grounded).
  • Coyote Time: Grace window for jumping when running off slopes or ledges.
  • Downhill Ground Following (snap_to_ground): Downward snap (1 voxel) to maintain ground contact when descending stepped slopes.
  • Committed Slide Refinements: Lengthened slide travel downhill, slide cancellation into run upon releasing crouch key, and slide termination when colliding with solid geometry (>10% horizontal speed loss).
  • Stance Refusal Rules: Prohibits standing up if ceiling clearance is insufficient.
  • Traversal Events (movement::state): Emits discrete events for footstep pacing, jumps, landings, fall distance tracking, and slide state transitions.
  • Precision Coordinate Math (world::entity): Added EntityPos::delta subtracting integer chunk anchors before f32 conversion for precision at large distances.

3. Prediction & Reconciliation Engine (crates/shared)

  • Prediction Ring Buffer (movement::prediction): Fixed 60-tick ring buffer storing unacknowledged (InputFrame, MovementState) pairs with wrapping sequence tick comparisons (tick_is_newer) and overflow protection.
  • Reconciliation Engine (movement::reconcile): Compares authoritative snapshots against local prediction buffer. Checks motion/stance match, position distance (1 cm squared threshold), and velocity error.
  • State Rewind & Replay: On divergence, replays all buffered unacknowledged ticks forward from the authoritative state.
  • Unloaded Stall Flag: Returns halted_unloaded flag in StepOutcome to inform client/server if movement stopped due to chunk streaming boundaries.

4. Networking & Protocols (crates/net, crates/shared)

  • QUIC Stream Purpose Tagging (net::runtime): Added one-byte stream layout tags to prevent acceptor races across multi-stream connections.
  • Dedicated Input Stream (net::input): Carries client InputFrame payloads with sequence ticks, 2D normalized movement vectors, and held/pressed action bitfields.
  • Dedicated Authority Stream (net::authority): Streams authoritative PlayerState snapshots with full movement state and last acknowledged client tick.
  • Protocol Version Bump: Incremented PROTOCOL_VERSION to 4 for full movement state serialization.

5. Authoritative Server Architecture (crates/server)

  • Per-Session Player Management (server::player): Spawns and tracks player entities per active connection.
  • Surface Spawn Scan: Origin column raycasting against world bounds to place spawning players safely on top of terrain.
  • Authoritative Tick Execution (server::main): Steps movement controller at 60 Hz against chunk stores exposed as VoxelQuery.
  • Idempotent Input Queue (PendingInput): Ingests input frames by tick, rejecting duplicate, late, or already-simulated frames.

6. Client Prediction, Input & Presentation (crates/client)

  • Fixed-Rate Input Sampling (client::input): 60 Hz input sampler with latched keypresses and swapped sprint/sneak keybinding fix.
  • Redundant Input Packet Transmission: Sends current tick with a tail of the last 4 unacknowledged frames (REDUNDANT_FRAMES = 4) to withstand packet loss.
  • Client Prediction System (client::prediction): Local simulation against client chunk storage with replay reconciliation.
  • Camera Mounting & Eye Interpolation (client::camera): Decoupled mouse-look from movement tick; mounts eye at predicted position with tick interpolation fraction (alpha).
  • Render-Only Camera Smoothing:
    • Exponential decay (~50 ms) for visual position error correction (< 1.0 m) avoiding visual teleports.
    • Symmetric stair-step climbing and descent smoothing (~100 ms) preventing jarring eye dips across blocky terrain.
  • Debug & Telemetry (client::debug, client::stats): Added prediction metrics to overlay (pred line) and F1 + P keybinding to test desync recovery via artificial 3-block displacement.

7. Documentation & Housekeeping

  • ADR 0012 (docs/adr/0012-player-collider-dimensions.md): Formally recorded player collider dimensions, stance boxes, and half-scale units.
  • ADR 0002 & Architecture Map Updates (docs/): Updated documentation cross-references.
  • Codebase Cleanliness: Reorganized file-level constant declarations to the top of files across client, renderer, shared, and test suites.

Why is this change necessary?

Prior to this PR, the client used a free-fly debug camera with no collision, physics, or network synchronization. This PR establishes the core movement foundation:

  1. Zero Input Latency: Local prediction provides instantaneous feedback for player movement actions.
  2. Server Authority & Anti-Cheat: Physics and movement authority reside entirely on the server; client input cannot forge positions or bypass collision.
  3. Smooth Voxel Traversal: Half-scale voxels (0.5 m) inherently create stepped inclines. Automated step-ups, ground snapping, substepping, and visual stair smoothing eliminate snagging, clipping, and camera jitter on stepped terrain.

Scope of Changes

client, server, networking, renderer, shared, workspace

Testing

  • Automated Test Suite:
    • cargo test --workspace fully passing (344 tests total):
      • shared (186 tests): Swept AABB collision, substepping limits, step-up clearance & reversion, stance ceiling refusal, downhill ground snapping, momentum conservation on air wall contact, deceleration ramps, slide collision deflection & cancellation, coyote time, prediction ring buffer lifecycle & wrapping, exact replay reproducibility on divergence.
      • client (74 tests): Input sampling, latched keypress edges, prediction buffer queueing, stair climb/descent camera smoothing without eye dips.
      • server (42 tests): Input queue idempotency, player spawn raycasting, authority replication.
      • net (27 tests): Stream purpose framing, input/authority serialization codecs.
      • renderer (14 tests): Mesh updates and rendering statistics.
  • Static Analysis & Linting:
    • cargo fmt --all -- --check clean.
    • cargo clippy --all-targets --all-features -- -D warnings clean.
  • Manual / In-Game Verification:
    • Verified movement gaits (sneak, walk, run, sprint, jump, slide) across varied terrain.
    • Confirmed smooth step-up/down stair traversal with camera interpolation.
    • Injected artificial position desyncs via F1 + P to confirm smooth exponential convergence back to server authority.

Additional Context

  • Deterministic Architecture: All physics simulation logic lives in crates/shared/src/movement/ as pure functions of (state, input, profile, world). The exact same simulation runs on both client and server.
  • Split-Coordinate Safety: Position difference arithmetic (EntityPos::delta) computes chunk anchor integer deltas first to avoid float precision loss far from origin.
  • Strict Visual/Physical Separation: Camera smoothing and step offsets only affect the rendered view and are never fed back into the physics collider or state buffer.
  • Future Work (Out of Scope):
    • Remote player entity interpolation and ghost rendering (focus of this PR is local player prediction).
    • Swimming, climbing/mantling, stamina systems, and per-block friction physics (tracked in subsequent feature cards).

No response

Checklist

  • I have branched from dev (or a feature branch off dev) and my PR targets dev.
  • I have kept my changes focused to a single concept.
  • I have added or updated documentation (/// doc comments for Rust) where necessary.
  • I have tested my changes and described any relevant automated or manual testing above.
### What does this PR do? Implements an end-to-end, server-authoritative, client-predicted player movement system over the voxel terrain with reconciliation and camera smoothing. An exhaustive breakdown of every change made in this branch across all crates and subsystems: ### 1. Core Collision & Voxel Query (`crates/shared`) - **Block Extent Conventions (`world::bounds`)**: Centralized half-open block extent arithmetic (`[i, i + 1)`) so `floor` inverts extents consistently across collision, meshing, and culling. - **`VoxelQuery` Trait (`movement::query`)**: Added spatial query abstraction returning `Option<BlockId>` where `None` indicates an unloaded chunk (treated as a solid obstacle rather than air to prevent falling through the void). - **AABB Colliders & Stances (`movement::collider`)**: Defined player bounding boxes across three stances according to ADR 0012 (Standing: 0.75×1.75 m, Crouching: 0.75×1.25 m, Crawling/Sliding: 0.75×0.75 m). - **Swept AABB Collision (`movement::sweep`)**: Substepped, axis-separated collision resolution in fixed order (X, Y, Z) with blocker classification (`Blocker::Solid`, `Blocker::Unloaded`). - **Attempt-and-Revert Step-Up (`movement::sweep`)**: Clear low obstacles up to 1.2 voxels (0.6 m) by attempting elevated forward displacement and reverting to ground-level sweep if blocked. ### 2. Deterministic Locomotion Controller (`crates/shared`) - **Fixed Timestep**: Evaluates physics at a fixed 60 Hz rate (`dt = 1/60s`) without variable delta time. - **Tuned Movement Profile (`movement::profile`)**: Configured locomotion ladder speeds (Sneak: 1.5 m/s, Walk: 4.0 m/s, Run: 6.0 m/s, Sprint: 8.5 m/s, Slide initial: 10.0 m/s), gravity (32 m/s²), jump apex times, and stance heights. - **Dedicated Deceleration Ramp**: Separate 90 u/s² ground deceleration rate so speed is shed quickly upon releasing input or downshifting gaits instead of coasting. - **Air Control & Wall Momentum**: Clamped air control preserving horizontal momentum during airborne wall contact (clearing velocity only while grounded). - **Coyote Time**: Grace window for jumping when running off slopes or ledges. - **Downhill Ground Following (`snap_to_ground`)**: Downward snap (1 voxel) to maintain ground contact when descending stepped slopes. - **Committed Slide Refinements**: Lengthened slide travel downhill, slide cancellation into run upon releasing crouch key, and slide termination when colliding with solid geometry (>10% horizontal speed loss). - **Stance Refusal Rules**: Prohibits standing up if ceiling clearance is insufficient. - **Traversal Events (`movement::state`)**: Emits discrete events for footstep pacing, jumps, landings, fall distance tracking, and slide state transitions. - **Precision Coordinate Math (`world::entity`)**: Added `EntityPos::delta` subtracting integer chunk anchors before `f32` conversion for precision at large distances. ### 3. Prediction & Reconciliation Engine (`crates/shared`) - **Prediction Ring Buffer (`movement::prediction`)**: Fixed 60-tick ring buffer storing unacknowledged `(InputFrame, MovementState)` pairs with wrapping sequence tick comparisons (`tick_is_newer`) and overflow protection. - **Reconciliation Engine (`movement::reconcile`)**: Compares authoritative snapshots against local prediction buffer. Checks motion/stance match, position distance (1 cm squared threshold), and velocity error. - **State Rewind & Replay**: On divergence, replays all buffered unacknowledged ticks forward from the authoritative state. - **Unloaded Stall Flag**: Returns `halted_unloaded` flag in `StepOutcome` to inform client/server if movement stopped due to chunk streaming boundaries. ### 4. Networking & Protocols (`crates/net`, `crates/shared`) - **QUIC Stream Purpose Tagging (`net::runtime`)**: Added one-byte stream layout tags to prevent acceptor races across multi-stream connections. - **Dedicated Input Stream (`net::input`)**: Carries client `InputFrame` payloads with sequence ticks, 2D normalized movement vectors, and held/pressed action bitfields. - **Dedicated Authority Stream (`net::authority`)**: Streams authoritative `PlayerState` snapshots with full movement state and last acknowledged client tick. - **Protocol Version Bump**: Incremented `PROTOCOL_VERSION` to 4 for full movement state serialization. ### 5. Authoritative Server Architecture (`crates/server`) - **Per-Session Player Management (`server::player`)**: Spawns and tracks player entities per active connection. - **Surface Spawn Scan**: Origin column raycasting against world bounds to place spawning players safely on top of terrain. - **Authoritative Tick Execution (`server::main`)**: Steps movement controller at 60 Hz against chunk stores exposed as `VoxelQuery`. - **Idempotent Input Queue (`PendingInput`)**: Ingests input frames by tick, rejecting duplicate, late, or already-simulated frames. ### 6. Client Prediction, Input & Presentation (`crates/client`) - **Fixed-Rate Input Sampling (`client::input`)**: 60 Hz input sampler with latched keypresses and swapped sprint/sneak keybinding fix. - **Redundant Input Packet Transmission**: Sends current tick with a tail of the last 4 unacknowledged frames (`REDUNDANT_FRAMES = 4`) to withstand packet loss. - **Client Prediction System (`client::prediction`)**: Local simulation against client chunk storage with replay reconciliation. - **Camera Mounting & Eye Interpolation (`client::camera`)**: Decoupled mouse-look from movement tick; mounts eye at predicted position with tick interpolation fraction (`alpha`). - **Render-Only Camera Smoothing**: - Exponential decay (~50 ms) for visual position error correction (< 1.0 m) avoiding visual teleports. - Symmetric stair-step climbing and descent smoothing (~100 ms) preventing jarring eye dips across blocky terrain. - **Debug & Telemetry (`client::debug`, `client::stats`)**: Added prediction metrics to overlay (`pred` line) and **F1 + P** keybinding to test desync recovery via artificial 3-block displacement. ### 7. Documentation & Housekeeping - **ADR 0012 (`docs/adr/0012-player-collider-dimensions.md`)**: Formally recorded player collider dimensions, stance boxes, and half-scale units. - **ADR 0002 & Architecture Map Updates (`docs/`)**: Updated documentation cross-references. - **Codebase Cleanliness**: Reorganized file-level constant declarations to the top of files across `client`, `renderer`, `shared`, and test suites. ### Why is this change necessary? Prior to this PR, the client used a free-fly debug camera with no collision, physics, or network synchronization. This PR establishes the core movement foundation: 1. **Zero Input Latency**: Local prediction provides instantaneous feedback for player movement actions. 2. **Server Authority & Anti-Cheat**: Physics and movement authority reside entirely on the server; client input cannot forge positions or bypass collision. 3. **Smooth Voxel Traversal**: Half-scale voxels (0.5 m) inherently create stepped inclines. Automated step-ups, ground snapping, substepping, and visual stair smoothing eliminate snagging, clipping, and camera jitter on stepped terrain. ### Scope of Changes client, server, networking, renderer, shared, workspace ### Testing - **Automated Test Suite**: - `cargo test --workspace` fully passing (344 tests total): - **`shared` (186 tests)**: Swept AABB collision, substepping limits, step-up clearance & reversion, stance ceiling refusal, downhill ground snapping, momentum conservation on air wall contact, deceleration ramps, slide collision deflection & cancellation, coyote time, prediction ring buffer lifecycle & wrapping, exact replay reproducibility on divergence. - **`client` (74 tests)**: Input sampling, latched keypress edges, prediction buffer queueing, stair climb/descent camera smoothing without eye dips. - **`server` (42 tests)**: Input queue idempotency, player spawn raycasting, authority replication. - **`net` (27 tests)**: Stream purpose framing, input/authority serialization codecs. - **`renderer` (14 tests)**: Mesh updates and rendering statistics. - **Static Analysis & Linting**: - `cargo fmt --all -- --check` clean. - `cargo clippy --all-targets --all-features -- -D warnings` clean. - **Manual / In-Game Verification**: - Verified movement gaits (sneak, walk, run, sprint, jump, slide) across varied terrain. - Confirmed smooth step-up/down stair traversal with camera interpolation. - Injected artificial position desyncs via **F1 + P** to confirm smooth exponential convergence back to server authority. ### Additional Context - **Deterministic Architecture**: All physics simulation logic lives in `crates/shared/src/movement/` as pure functions of `(state, input, profile, world)`. The exact same simulation runs on both client and server. - **Split-Coordinate Safety**: Position difference arithmetic (`EntityPos::delta`) computes chunk anchor integer deltas first to avoid float precision loss far from origin. - **Strict Visual/Physical Separation**: Camera smoothing and step offsets only affect the rendered view and are never fed back into the physics collider or state buffer. - **Future Work (Out of Scope)**: - Remote player entity interpolation and ghost rendering (focus of this PR is local player prediction). - Swimming, climbing/mantling, stamina systems, and per-block friction physics (tracked in subsequent feature cards). ### Related Issues _No response_ ### Checklist - [x] I have branched from `dev` (or a feature branch off `dev`) and my PR targets `dev`. - [x] I have kept my changes focused to a single concept. - [x] I have added or updated documentation (`///` doc comments for Rust) where necessary. - [x] I have tested my changes and described any relevant automated or manual testing above.
refactor(workspace): declare file-level constants at the top of their files
Some checks failed
CI / Rust Check, Lint & Test (pull_request) Failing after 18m20s
CI / Lua Lint & Format (pull_request) Successful in 8s
CI / LFS Pointer Guard (pull_request) Successful in 6s
Auto Labeler / label-scope (pull_request) Successful in 3s
CLA Signed CLA not signed by: Serkyo
CLA Check / cla-check (pull_request) Successful in 4s
d2a4e6d06c

📝 CLA Signature Required

@Serkyo — thank you for your contribution! Before this pull request can be reviewed and merged, all commit authors must sign the Contributor License Agreement.

To sign, please leave a comment on this pull request containing exactly:

I have read the CLA and I agree

Signing is a one-time action. Once recorded, all future pull requests from the same account are accepted automatically.

### 📝 CLA Signature Required @Serkyo — thank you for your contribution! Before this pull request can be reviewed and merged, all commit authors must sign the [Contributor License Agreement](https://github.com/Synvael/synvael/blob/dev/CLA.md). To sign, please leave a comment on this pull request containing **exactly**: ``` I have read the CLA and I agree ``` Signing is a one-time action. Once recorded, all future pull requests from the same account are accepted automatically.
chore(renderer): use as_chunks instead of chunks_exact in meshing tests
All checks were successful
CI / Rust Check, Lint & Test (pull_request) Successful in 24m24s
CI / Lua Lint & Format (pull_request) Successful in 8s
CI / LFS Pointer Guard (pull_request) Successful in 6s
CLA Check / cla-check (pull_request) Successful in 4s
CLA Signed All authors have signed the CLA.
bd245fdd18
Author
Owner

I have read the CLA and I agree

I have read the CLA and I agree
Author
Owner

I have read the CLA and I agree

I have read the CLA and I agree
Author
Owner

I have read the CLA and I agree

I have read the CLA and I agree
Merge branch 'dev' into feat/player-movement
All checks were successful
CI / Rust Check, Lint & Test (pull_request) Successful in 23m58s
CI / Lua Lint & Format (pull_request) Successful in 8s
CI / LFS Pointer Guard (pull_request) Successful in 6s
CLA Signed All authors have signed the CLA.
CLA Check / cla-check (pull_request) Successful in 4s
1472d84c31
Merge branch 'dev' into feat/player-movement
All checks were successful
CLA Signed All authors have signed the CLA.
CLA Check / cla-check (pull_request_target) Successful in 4s
CI / Rust Check, Lint & Test (pull_request) Successful in 23m54s
CI / Lua Lint & Format (pull_request) Successful in 8s
CI / LFS Pointer Guard (pull_request) Successful in 6s
242478aef1
Serkyo deleted branch feat/player-movement 2026-08-22 05:56:53 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Synvael/synvael!2
No description provided.