Physics: Add manual space stepping to PhysicsServer2D/3D - #7
Open
dsarno wants to merge 3 commits into
Open
Conversation
Review fixes on top of the manual space-stepping API: - Fix `flushing_queries` being raised before argument validation. An invalid RID returned early with the flag still set, leaving the server permanently in the "flushing" state and silently disabling every guard that reads `is_flushing_queries()` (such as `Area2D::set_monitorable`). The flag is now saved and restored around the call rather than forced to `false`, so a nested flush from inside a physics callback cannot clear the outer one. - Bracket the Jolt backend's `space_step()` with `job_system->pre_step()` and `post_step()`, matching `step()`. Without this, repeated manual steps exhaust Jolt's job allocator. - Reject active spaces in the Jolt backend, matching the GodotPhysics backends. An active space is already advanced once per physics frame, so stepping it manually double-advanced the simulation. - Correct the documentation, which described stepping an active space from `_physics_process()` as a supported workflow while every backend rejects it. - Qualify `ProcessInfo` with the enum namespace in the backend definitions, and restore the trailing semicolons on two `GDVIRTUAL_BIND` lines.
Adds regression coverage for the manual stepping API against the real GodotPhysics backends. The test harness installs the dummy servers, so these cases construct `GodotPhysicsServer2D`/`3D` directly instead of going through the server managers. Covered: a manually stepped inactive space advances; an unstepped space does not; stepping one space leaves another untouched; an active space rejects a manual step; and flushing queries with an invalid space leaves the server's flushing flag clear. The last case fails without the accompanying validation-ordering fix.
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.
Summary
Adds three methods to
PhysicsServer2DandPhysicsServer3Dfor driving a physics space by hand instead of letting the engine advance it once per frame:space_step(space, delta)— advance one spacespace_flush_queries(space)— run that space's contact and area monitoring callbacksspace_get_last_process_info(space, info)— per-space counters, since a manual step does not update the server-global onesThe motivating use cases are rollback-style networking (fast-forwarding a simulation after a correction) and prediction (previewing where a ball will end up before committing to a shot). The API is forward-only: snapshotting and restoring body state remains the caller's job.
The methods are plumbed through the abstract server, the dummy server, the GDExtension binding, the threaded wrapper, and all three backends (
godot_physics_2d,godot_physics_3d,jolt_physics), and are markedexperimentalin the class reference.Provenance
The first commit is third-party work, rebased onto current
masterand preserved with its original authorship. It did not apply cleanly — 14 files conflicted, because the physics enums were since moved out of the server classes into thePhysicsServer2DEnums/PhysicsServer3DEnumsnamespaces. Conflicts were resolved onto the current enum API.The remaining two commits are mine: defects found while reviewing, and the tests that cover them.
This branch was produced by an AI agent. Everything below was verified by building and running it, but it warrants a human read before it goes anywhere.
Defects found and fixed
1. Flushing flag leaked on early return (all three backends).
flushing_queries = truewas set before the arguments were validated, so an invalid RID returned early with the flag still raised. The server then stayed permanently in the "flushing" state, silently disabling every guard that readsis_flushing_queries()—Area2D::set_monitorableamong them. The flag is now raised only after validation, and saved/restored rather than forced tofalse, so a nested flush from inside a physics callback cannot clear the outer one. This is the defect the last test case covers.2. Jolt exhausted its job allocator.
JoltPhysicsServer3D::step()brackets each space withjob_system->pre_step()/post_step(), but the newspace_step()did not. Repeated manual steps therefore ran the job system out of slots. Now bracketed identically.3. Backends disagreed about active spaces. The GodotPhysics backends rejected a manual step on an active space; Jolt silently allowed it, double-advancing the simulation, since the engine already steps active spaces every physics frame. Jolt now rejects it too.
4. The documentation contradicted every backend. It described stepping an active space from
_physics_process()as the supported workflow, which all three backends reject. Rewritten to state the actual contract: deactivate the space first.5. Compile and style breakage from the rebase.
ProcessInfoneeded namespace qualification in the backend definitions and switch cases under the current enum API, and twoGDVIRTUAL_BINDlines were missing trailing semicolons (196 of 198 in those files had them).Testing
New file
tests/servers/test_physics_server_manual_step.cpp, 8 cases / 29 assertions, all passing:The test harness installs the dummy physics servers, so the backends are unreachable through
PhysicsServer3DManager. The cases constructGodotPhysicsServer2D/3Ddirectly instead. Coverage: a manually stepped inactive space advances; an unstepped space does not; stepping one space leaves another untouched; an active space rejects a manual step; and flushing with an invalid space leaves the flag clear.The last case was verified to actually catch defect 1 — with the fix reverted it fails:
Also verified locally:
clang-formatclean on all touched files, and--doctoolregenerates the class reference with zero diff, so the documentation matches the bindings.Open questions for review
These are real and deliberately not resolved here, because each one is a design decision rather than a defect:
space_stepis queued asynchronously, so underrun_on_separate_threadthe call returns before the step happens and there is no exposed sync point.space_get_last_process_infobypasses the queue entirely. Making this coherent probably needs a per-space sync primitive.flushing_queriesis server-wide. Save/restore makes it safe, but the flag arguably belongs on the space so that flushing one space doesn't affect guards on another.virtual required, which breaks out-of-tree physics servers. A non-required binding or a compat shim may be wanted.space_get_last_process_inforeturns 0. Left as-is; it should either be implemented or explicitly documented as unsupported on that backend.Generated by Claude Code