Add physics rollback prediction and the arena example - #289
Draft
bdero wants to merge 17 commits into
Draft
Conversation
Invert the strafe axis, center the HUD via the shared overlay, restyle the join screen as a centered dark modal, and drop the colon from its copy. Add PredictedTransformComponent (owned-entity client prediction with error-smoothing reconciliation) and the SceneReplication localPrediction seam, plus the NetworkTransformComponent idle-gap re-anchor so a resuming remote eases in instead of snapping.
PredictedTransformComponent now drives a fixed client tick, sampling and sending an input command per tick, predicting through the shared step, and reconciling against the authoritative pose the server confirms via the input-command ack (rolling back and replaying unacked inputs). The localPrediction seam takes a PredictedController (sample plus step) instead of a bare step. Supersedes the error-smoothing anticipation.
Player input now flows as tick-stamped input commands the server consumes authoritatively and the client predicts with the same advancePlayer step, replacing the owner-written input field. Adds a prediction toggle and a simulated-latency control so the difference between predicted (instant, reconciled) and interpolated (lags by the round trip) local movement is visible on one machine.
fsr_world_snapshot/fsr_world_restore serialize and restore the persistent Rapier world (bodies, colliders, joints, islands, phases, integration params, gravity) via serde, with the buffer marshalled through the FFI. Exposed as RapierWorld.snapshot/restore behind the PhysicsSimulation seam (supportsSnapshot), the substrate for rollback-predicted physics and lag-compensation rewind. Handles stay valid across a round trip. Native verified end to end; the web backend is stubbed until the wasm module is rebuilt with the exports.
fsr_body_set_pose teleports a body and wakes it, exposed as PhysicsSimulation.setBodyPose (default throws) and implemented by RapierWorld. A rollback correction restores a world snapshot, adopts the authoritative pose, and replays pending inputs; the new test asserts that loop replays deterministically.
PredictedPhysicsComponent predicts an owned body in a dedicated snapshot-capable simulation, retaining a world snapshot per tick; a diverged authoritative pose restores the acked tick's snapshot, adopts the authoritative body state, and replays pending inputs through the world. PhysicsWorldHistory is the server-side ring that rewinds hit queries to the client-rendered tick and restores the present. SceneReplication's localPrediction seam now accepts either controller kind.
Players are dynamic balls in a rapier arena built identically by the room and by each predicting client. The server consumes input commands, steps the world, and publishes pose plus velocities; the local ball is rollback-predicted through PredictedPhysicsComponent, so a mispredicted bump restores the acked snapshot and replays. Prediction stays off on web until the wasm snapshot marshalling lands.
The web backend now round-trips snapshot/restore, copying the shim's buffer out of linear memory and staging restore bytes via fsr_alloc, so rollback prediction works on the web. Also files the pose setter and snapshot changelog entries under Unreleased; 0.3.0 shipped without native changes and its entry stands as released.
The platform gate becomes a runtime capability probe (initialize the backend, try one snapshot), so a web build predicts when the wasm module carries the snapshot exports and degrades to interpolation otherwise. Adds a headless host tool so any platform, including web builds, can join a dart run server.
The end-to-end test rollback-predicts the arena ball over rapier worlds on both sides of a loopback room, on native and (via --platform chrome with a served wasm module) on the web; it skips when the backend lacks the snapshot exports. The SceneHost test skips on web where in-app hosting does not exist.
Clicking Host/Join focuses the button (notably on web), so movement keys never reached the listener until another interaction.
Bodies created after a retained snapshot vanish when a correction restores it, leaving their handles silently dangling. The new onWorldRestored callback lets the controller revalidate anything it manages dynamically, such as remote-player collision proxies.
Remote players mirror into the prediction world as kinematic proxies at their rendered poses, so a bump responds locally against what the player sees instead of penetrating until the server correction arrives; world snapshots retain the proxies, so rollback replays run against their historical poses. The proxy set rebuilds after a restore (older snapshots may predate it) and leavers park instead of despawning so no snapshot can resurrect an unmanaged body. Also tightens the remote interpolation buffer to 75ms to narrow the predicted-vs-interpolated timeline gap.
The remote render delay sizes itself from sample inter-arrival stats, easing between a floor and the configured ceiling, so a clean local link renders barely behind while a jittery one buffers deep. Idleness is judged against the ceiling so spikes are measured, not mistaken for gaps. SceneReplication also passes the input buffer target depth through to the client.
Halves every tick-denominated latency; with the adaptive interpolation delay and a depth-1 input buffer, same-machine action-to-reaction drops from roughly 190ms to under 100ms.
bdero
force-pushed
the
bdero/predicted-physics
branch
from
August 2, 2026 10:07
df75d3c to
adc6986
Compare
|
The latest updates on your projects. Learn more about Argos notifications ↗︎
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #287 and #288; it carries their commits and rebases to just its own once they merge.
PredictedPhysicsComponentrollback-predicts an owned body in a dedicated snapshot-capable world, restoring the acked tick, adopting the authoritative pose and velocity, and replaying pending inputs, withonWorldRestoredtelling the controller to revalidate bodies it manages.PhysicsWorldHistoryrewinds server-side hit queries to the client-rendered tick. Remote players mirror into the prediction world as kinematic proxies at their rendered poses, and the interpolation delay now adapts to measured arrival cadence and jitter. The Multiplayer example becomes a 60Hz physics arena (players are balls that shove each other) with a headlessdart runhost tool, and prediction runs on the web behind a runtime capability probe.