[Feature] Drive external physics backends via an EngineExtension coordinator - #1129
Merged
untoldengine merged 1 commit intoAug 5, 2026
Conversation
miogds
force-pushed
the
feature/physics_coordinator-upstream
branch
from
August 4, 2026 09:10
0c942be to
3fec784
Compare
…dinator PR B of the physics plugin readiness plan (discussion untoldengine#1116), built on the EngineExtension infrastructure from untoldengine#1127 instead of a custom runFrame seam: - PhysicsCoordinator (EngineExtension) steps the installed backend once per fixed substep: body-set diffing against the RigidBodyComponent + ColliderComponent query, batch kinematic writes, step, batch transform read-back into LocalTransformComponent, event drain into an inert sink (subscriptions arrive in the events PR). - PhysicsBackendRegistry schedules/unschedules the coordinator in EngineExtensionRegistry on install/uninstall and locks for runtime on the first simulated substep. - Gravity for the built-in integrator now reads from the global PhysicsWorldConfiguration (default unchanged at (0, -9.8, 0)), so legacy and backend-owned bodies share one gravity. With no backend installed nothing is scheduled and behavior is unchanged; the built-in integrator keeps running legacy entities either way.
miogds
force-pushed
the
feature/physics_coordinator-upstream
branch
from
August 4, 2026 09:37
3fec784 to
b1f3039
Compare
untoldengine
approved these changes
Aug 5, 2026
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
PR B of the narrowed phase-1 plan from discussion #1116 (follows #1123), reworked per your review guidance to sit entirely on the #1127
EngineExtensioninfrastructure — norunFrameseam, no engine-core changes. Rebased on currentdevelop(post the repo-wide format commit);make lintpasses clean on the branch. With no backend installed, nothing is even scheduled: the coordinator is only registered while a backend plugin is installed, so runtime behavior is unchanged by construction. The built-in integrator is untouched and keeps running legacyPhysicsComponents/KineticComponententities in all cases (the coexistence rule from the plan).Sources/UntoldEngine/Physics/PhysicsCoordinator.swift—PhysicsCoordinatorconforming toEngineExtension(id: com.untoldengine.physics.coordinator). ItsfixedUpdateruns once per fixed substep right afterupdatePhysicsSystem, and per substep: (1) diffs theRigidBodyComponent+ColliderComponent+LocalTransformComponentquery result against the backend's known-body set →didAddBody/didRemoveBody(entity destruction needs no extra hook — component cleanup drops the entity out of the query and the diff catches it); (2) batch-writes kinematic targets; (3)backend.step; (4) batch-reads active transforms back intoLocalTransformComponentfor dynamic bodies, markingtransformDirty/anyTransformDirtyexactly like the built-in integrator; (5) drains events into an inert sink (delivery/USC wiring is PR C).PhysicsBackendRegistrynow registers the coordinator withEngineExtensionRegistry.shared.register(_:)on successful install (also pushing the currentPhysicsWorldConfigurationto the backend) and unregisters it on uninstall — both outside the registry lock. ThelockForRuntime()seam from [Feature] Add physics backend plugin interface #1123 is wired with zero core edits: the coordinator locks the registry on the first substep it simulates, freezing the backend choice for the run.PhysicsCoordinator.setWorldConfiguration(_:)applies to the active backend and to the built-in integrator, whose hardcoded(0, -9.8, 0)inupdatePhysicsSystemnow reads the same configuration (default identical, hoisted out of the per-entity loop).Engine touch outside
Physics/: one hoisted gravity read inSystems/PhysicsSystem.swift(3 lines). Follow-ups per the plan: PR C (event sink subscriptions + USCOnCollision), PR D (raycast facade).Test plan
swift test --filter PhysicsCoordinatorTests— 15/15 passPhysicsBackendRegistryTests,ComponentRegistryTest,ECSTests,EngineExtensionLifecycleTest,CustomSystemTest— all passUntoldEngineTestsmodule: 1060 tests, no new failures (the one failure,ExternalRenderExtensionPackageTests, fails identically on cleandevelopon this machine)