@flighthq/physics3d 0.4.0-edge.1908.751021c

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/dist/broadphase.d.ts +4 -0
  2. package/dist/broadphase.d.ts.map +1 -0
  3. package/dist/broadphase.js +158 -0
  4. package/dist/broadphase.js.map +1 -0
  5. package/dist/colliderCollision.d.ts +5 -0
  6. package/dist/colliderCollision.d.ts.map +1 -0
  7. package/dist/colliderCollision.js +55 -0
  8. package/dist/colliderCollision.js.map +1 -0
  9. package/dist/colliderTransform.d.ts +5 -0
  10. package/dist/colliderTransform.d.ts.map +1 -0
  11. package/dist/colliderTransform.js +424 -0
  12. package/dist/colliderTransform.js.map +1 -0
  13. package/dist/contactIntake.d.ts +5 -0
  14. package/dist/contactIntake.d.ts.map +1 -0
  15. package/dist/contactIntake.js +237 -0
  16. package/dist/contactIntake.js.map +1 -0
  17. package/dist/contacts.d.ts +4 -0
  18. package/dist/contacts.d.ts.map +1 -0
  19. package/dist/contacts.js +64 -0
  20. package/dist/contacts.js.map +1 -0
  21. package/dist/continuous.d.ts +5 -0
  22. package/dist/continuous.d.ts.map +1 -0
  23. package/dist/continuous.js +829 -0
  24. package/dist/continuous.js.map +1 -0
  25. package/dist/contract.d.ts +28 -0
  26. package/dist/contract.d.ts.map +1 -0
  27. package/dist/contract.js +28 -0
  28. package/dist/contract.js.map +1 -0
  29. package/dist/debugGeometry.d.ts +4 -0
  30. package/dist/debugGeometry.d.ts.map +1 -0
  31. package/dist/debugGeometry.js +333 -0
  32. package/dist/debugGeometry.js.map +1 -0
  33. package/dist/enablePhysics3DGuards.d.ts +4 -0
  34. package/dist/enablePhysics3DGuards.d.ts.map +1 -0
  35. package/dist/enablePhysics3DGuards.js +155 -0
  36. package/dist/enablePhysics3DGuards.js.map +1 -0
  37. package/dist/explainPhysics3DCollision.d.ts +3 -0
  38. package/dist/explainPhysics3DCollision.d.ts.map +1 -0
  39. package/dist/explainPhysics3DCollision.js +30 -0
  40. package/dist/explainPhysics3DCollision.js.map +1 -0
  41. package/dist/explainPhysics3DJoints.d.ts +3 -0
  42. package/dist/explainPhysics3DJoints.d.ts.map +1 -0
  43. package/dist/explainPhysics3DJoints.js +32 -0
  44. package/dist/explainPhysics3DJoints.js.map +1 -0
  45. package/dist/explainPhysics3DStep.d.ts +3 -0
  46. package/dist/explainPhysics3DStep.d.ts.map +1 -0
  47. package/dist/explainPhysics3DStep.js +51 -0
  48. package/dist/explainPhysics3DStep.js.map +1 -0
  49. package/dist/index.d.ts +22 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +22 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/integrate.d.ts +6 -0
  54. package/dist/integrate.d.ts.map +1 -0
  55. package/dist/integrate.js +184 -0
  56. package/dist/integrate.js.map +1 -0
  57. package/dist/islands.d.ts +6 -0
  58. package/dist/islands.d.ts.map +1 -0
  59. package/dist/islands.js +333 -0
  60. package/dist/islands.js.map +1 -0
  61. package/dist/jointBreakage.d.ts +5 -0
  62. package/dist/jointBreakage.d.ts.map +1 -0
  63. package/dist/jointBreakage.js +44 -0
  64. package/dist/jointBreakage.js.map +1 -0
  65. package/dist/jointCollisionSuppression.d.ts +4 -0
  66. package/dist/jointCollisionSuppression.d.ts.map +1 -0
  67. package/dist/jointCollisionSuppression.js +40 -0
  68. package/dist/jointCollisionSuppression.js.map +1 -0
  69. package/dist/jointFactories.d.ts +9 -0
  70. package/dist/jointFactories.d.ts.map +1 -0
  71. package/dist/jointFactories.js +159 -0
  72. package/dist/jointFactories.js.map +1 -0
  73. package/dist/jointMath.d.ts +17 -0
  74. package/dist/jointMath.d.ts.map +1 -0
  75. package/dist/jointMath.js +361 -0
  76. package/dist/jointMath.js.map +1 -0
  77. package/dist/jointReaction.d.ts +8 -0
  78. package/dist/jointReaction.d.ts.map +1 -0
  79. package/dist/jointReaction.js +65 -0
  80. package/dist/jointReaction.js.map +1 -0
  81. package/dist/jointRegistry.d.ts +8 -0
  82. package/dist/jointRegistry.d.ts.map +1 -0
  83. package/dist/jointRegistry.js +144 -0
  84. package/dist/jointRegistry.js.map +1 -0
  85. package/dist/jointRows.d.ts +33 -0
  86. package/dist/jointRows.d.ts.map +1 -0
  87. package/dist/jointRows.js +352 -0
  88. package/dist/jointRows.js.map +1 -0
  89. package/dist/joints.d.ts +16 -0
  90. package/dist/joints.d.ts.map +1 -0
  91. package/dist/joints.js +1060 -0
  92. package/dist/joints.js.map +1 -0
  93. package/dist/massProperties.d.ts +13 -0
  94. package/dist/massProperties.d.ts.map +1 -0
  95. package/dist/massProperties.js +462 -0
  96. package/dist/massProperties.js.map +1 -0
  97. package/dist/material.d.ts +3 -0
  98. package/dist/material.d.ts.map +1 -0
  99. package/dist/material.js +13 -0
  100. package/dist/material.js.map +1 -0
  101. package/dist/nodeSync.d.ts +3 -0
  102. package/dist/nodeSync.d.ts.map +1 -0
  103. package/dist/nodeSync.js +16 -0
  104. package/dist/nodeSync.js.map +1 -0
  105. package/dist/ownership.d.ts +8 -0
  106. package/dist/ownership.d.ts.map +1 -0
  107. package/dist/ownership.js +26 -0
  108. package/dist/ownership.js.map +1 -0
  109. package/dist/physics3DBroadphasePublication.d.ts +5 -0
  110. package/dist/physics3DBroadphasePublication.d.ts.map +1 -0
  111. package/dist/physics3DBroadphasePublication.js +49 -0
  112. package/dist/physics3DBroadphasePublication.js.map +1 -0
  113. package/dist/physics3DSpatialIndexingGuards.d.ts +4 -0
  114. package/dist/physics3DSpatialIndexingGuards.d.ts.map +1 -0
  115. package/dist/physics3DSpatialIndexingGuards.js +11 -0
  116. package/dist/physics3DSpatialIndexingGuards.js.map +1 -0
  117. package/dist/registerBuiltInPhysics3DJointSolvers.d.ts +3 -0
  118. package/dist/registerBuiltInPhysics3DJointSolvers.d.ts.map +1 -0
  119. package/dist/registerBuiltInPhysics3DJointSolvers.js +15 -0
  120. package/dist/registerBuiltInPhysics3DJointSolvers.js.map +1 -0
  121. package/dist/solver.d.ts +8 -0
  122. package/dist/solver.d.ts.map +1 -0
  123. package/dist/solver.js +460 -0
  124. package/dist/solver.js.map +1 -0
  125. package/dist/step.d.ts +5 -0
  126. package/dist/step.d.ts.map +1 -0
  127. package/dist/step.js +302 -0
  128. package/dist/step.js.map +1 -0
  129. package/dist/stepValidation.d.ts +13 -0
  130. package/dist/stepValidation.d.ts.map +1 -0
  131. package/dist/stepValidation.js +284 -0
  132. package/dist/stepValidation.js.map +1 -0
  133. package/dist/symmetricTensor.d.ts +11 -0
  134. package/dist/symmetricTensor.d.ts.map +1 -0
  135. package/dist/symmetricTensor.js +150 -0
  136. package/dist/symmetricTensor.js.map +1 -0
  137. package/dist/world.d.ts +27 -0
  138. package/dist/world.d.ts.map +1 -0
  139. package/dist/world.js +762 -0
  140. package/dist/world.js.map +1 -0
  141. package/dist/worldQueries.d.ts +11 -0
  142. package/dist/worldQueries.d.ts.map +1 -0
  143. package/dist/worldQueries.js +409 -0
  144. package/dist/worldQueries.js.map +1 -0
  145. package/package.json +55 -0
  146. package/src/broadphase.test.ts +265 -0
  147. package/src/colliderCollision.test.ts +57 -0
  148. package/src/colliderTransform.test.ts +221 -0
  149. package/src/contactIntake.test.ts +370 -0
  150. package/src/contacts.test.ts +64 -0
  151. package/src/continuous.test.ts +679 -0
  152. package/src/debugGeometry.test.ts +288 -0
  153. package/src/enablePhysics3DGuards.test.ts +206 -0
  154. package/src/explainPhysics3DCollision.test.ts +78 -0
  155. package/src/explainPhysics3DJoints.test.ts +101 -0
  156. package/src/explainPhysics3DStep.test.ts +142 -0
  157. package/src/integrate.test.ts +279 -0
  158. package/src/islands.test.ts +384 -0
  159. package/src/jointBreakage.test.ts +143 -0
  160. package/src/jointCollisionSuppression.test.ts +94 -0
  161. package/src/jointFactories.test.ts +244 -0
  162. package/src/jointMath.test.ts +646 -0
  163. package/src/jointReaction.test.ts +241 -0
  164. package/src/jointRegistry.test.ts +229 -0
  165. package/src/jointRows.test.ts +548 -0
  166. package/src/joints.test.ts +1066 -0
  167. package/src/massProperties.test.ts +611 -0
  168. package/src/material.test.ts +40 -0
  169. package/src/nodeSync.test.ts +50 -0
  170. package/src/ownership.test.ts +61 -0
  171. package/src/physics3DBroadphasePublication.test.ts +63 -0
  172. package/src/physics3DSpatialIndexingGuards.test.ts +43 -0
  173. package/src/registerBuiltInPhysics3DJointSolvers.test.ts +51 -0
  174. package/src/solver.test.ts +567 -0
  175. package/src/step.test.ts +490 -0
  176. package/src/stepValidation.test.ts +346 -0
  177. package/src/stress.test.ts +526 -0
  178. package/src/symmetricTensor.test.ts +166 -0
  179. package/src/world.test.ts +1127 -0
  180. package/src/worldQueries.test.ts +565 -0
package/dist/step.js ADDED
@@ -0,0 +1,302 @@
1
+ import { buildPhysics3DContacts, refreshPhysics3DContacts } from './contactIntake';
2
+ import { hasActivePhysics3DBullet, integratePhysics3DContinuous } from './continuous';
3
+ import { clearRigidBody3DForces, integrateRigidBody3DPose, integrateRigidBody3DVelocity, refreshRigidBody3DWorldInertia, } from './integrate';
4
+ import { buildPhysics3DSolveIslands, updatePhysics3DSleep } from './islands';
5
+ import { evaluatePhysics3DJointBreakage } from './jointBreakage';
6
+ import { steppingPhysics3DWorlds } from './ownership';
7
+ import { preparePhysics3DContactConstraints, solvePhysics3DContactPositions, solvePhysics3DContactVelocities, warmStartPhysics3DContacts, } from './solver';
8
+ import { isPhysics3DBodyStateValid, isPhysics3DColliderStateValid, isPhysics3DContactStateValid, isPhysics3DContactValid, isPhysics3DGravityValid, isPhysics3DJointStateValid, isPhysics3DPositionIterationsValid, isPhysics3DSolverConfigValid, isPhysics3DSubstepsValid, isPhysics3DTimestepValid, isPhysics3DVelocityIterationsValid, } from './stepValidation';
9
+ // Installs the optional diagnostics seam consulted when a step declines its preconditions. Null by
10
+ // default and set only by `enablePhysics3DGuards`, so a build that never enables guards links neither the
11
+ // message text nor `@flighthq/log`.
12
+ export function setPhysics3DStepGuard(guard) {
13
+ physics3DStepGuard = guard;
14
+ }
15
+ // Advances the simulation by `dt` seconds. Everything the step does, it does because the caller asked:
16
+ // no implicit accumulation, no fixed-timestep loop hidden inside, and no allocation once the world's
17
+ // bodies, contacts, and joints exist.
18
+ //
19
+ // It declines SILENTLY on any failed precondition rather than throwing, because a NaN velocity or a zero
20
+ // timestep is a state a caller reaches by writing a field, and a throw from inside the step would take
21
+ // down a frame loop for something the caller can inspect and repair. `explainPhysics3DStep` is how a
22
+ // caller finds out which precondition failed, and it is separately importable so a shipping build that
23
+ // never asks never links it.
24
+ //
25
+ // Recursion IS a throw, because it is API misuse rather than data: reaching this from inside a contact
26
+ // hook would run a whole nested step against the arrays the outer one is midway through.
27
+ export function stepPhysics3D(world, dt) {
28
+ if (steppingPhysics3DWorlds.has(world)) {
29
+ throw new Error('Cannot step a physics world recursively');
30
+ }
31
+ const config = world.config;
32
+ if (!isPhysics3DTimestepValid(dt) ||
33
+ !isPhysics3DSubstepsValid(config) ||
34
+ !isPhysics3DVelocityIterationsValid(config) ||
35
+ !isPhysics3DPositionIterationsValid(config) ||
36
+ !isPhysics3DSolverConfigValid(config) ||
37
+ !isPhysics3DGravityValid(world) ||
38
+ !isPhysics3DBodyStateValid(world) ||
39
+ !isPhysics3DColliderStateValid(world) ||
40
+ !isPhysics3DContactStateValid(world) ||
41
+ !isPhysics3DJointStateValid(world)) {
42
+ // The one place the silent decline is observable from outside. The seam takes the world and the
43
+ // timestep rather than a reason, so the guard asks `explainPhysics3DStep` for ALL of them — a world
44
+ // with two faults reported one at a time would be repaired one frame at a time.
45
+ physics3DStepGuard?.(world, dt);
46
+ return;
47
+ }
48
+ // The flag is set and cleared in exactly one place, whatever the body does or throws. It is what makes
49
+ // every world lifecycle and joint lifecycle helper reject a call from inside a contact hook: the hook's
50
+ // sole mutation surface is the contact fields its contract names.
51
+ steppingPhysics3DWorlds.add(world);
52
+ try {
53
+ stepValidatedPhysics3D(world, dt);
54
+ }
55
+ finally {
56
+ steppingPhysics3DWorlds.delete(world);
57
+ }
58
+ }
59
+ // One sub-interval of a step: integrate velocities, solve the constraints, integrate poses, repair
60
+ // penetration.
61
+ //
62
+ // Exported because the solver ruling requires the step to ship as a composition of named functions rather
63
+ // than a monolith. A caller assembling its own loop wants exactly this piece, and a second solver would
64
+ // replace this while `stepPhysics3D` above it stays as it is.
65
+ //
66
+ // The substep loop is the OUTER loop, which is the whole reason this is a separate function. A solver
67
+ // that integrates once and then iterates cannot be turned into one that substeps without restructuring
68
+ // everything that reads the step, so the shape is reserved from the first release even at `substeps: 1`.
69
+ //
70
+ // The ordering is not arbitrary, and one piece of it is a trap. `refreshRigidBody3DWorldInertia` runs at
71
+ // the TOP, before the velocity integration reads the world tensor, and AGAIN once the poses have moved,
72
+ // before the position pass reads it. Integrating angular velocity against the previous sub-interval's
73
+ // world tensor is wrong in a way that shows only on a rotating asymmetric body — a slow, plausible
74
+ // precession no single-step assertion catches.
75
+ export function stepPhysics3DInterval(world, dt) {
76
+ const sequential = world.config.sequentialImpulse;
77
+ forEachSolveIslandBody(world, refreshRigidBody3DWorldInertia);
78
+ forEachSolveIslandBody(world, (body) => integrateRigidBody3DVelocity(body, world.gravityX, world.gravityY, world.gravityZ, dt));
79
+ preparePhysics3DContactConstraints(world);
80
+ forEachSolveIslandJoint(world, (joint, solver) => solver.prepare(world, joint, dt));
81
+ if (sequential.warmStarting) {
82
+ warmStartPhysics3DContacts(world);
83
+ // Warm starting is a per-KIND capability as well as a per-world preference. A kind that declares no
84
+ // `warmStart` never reapplies its accumulator, so that accumulator has to be cleared even while the
85
+ // world IS warm starting — an impulse that is never reapplied must be cleared, or it is neither warm
86
+ // nor cold, and it grows without ever acting.
87
+ forEachSolveIslandJoint(world, (joint, solver) => {
88
+ if (solver.warmStart !== undefined)
89
+ solver.warmStart(world, joint);
90
+ else
91
+ clearJointAccumulators(joint, solver);
92
+ });
93
+ }
94
+ else {
95
+ // Contacts need no clearing here: `preparePhysics3DContactConstraints` carries an accumulator across
96
+ // only when the flag is set, so the constraint it just built is already cold.
97
+ forEachSolveIslandJoint(world, clearJointAccumulators);
98
+ }
99
+ // Joints and contacts share one iteration count and one interleaved pass. Solving them in separate
100
+ // passes would let each undo the other's correction — a hinge under load creeps if the contacts beneath
101
+ // it get a whole pass to themselves between joint iterations.
102
+ for (let iteration = 0; iteration < sequential.velocityIterations; iteration += 1) {
103
+ forEachSolveIslandJoint(world, (joint, solver) => solver.solve(world, joint, dt));
104
+ solvePhysics3DContactVelocities(world);
105
+ }
106
+ evaluatePhysics3DJointBreakage(world, dt);
107
+ forEachSolveIslandPose(world, dt);
108
+ for (let iteration = 0; iteration < sequential.positionIterations; iteration += 1) {
109
+ solvePhysics3DContactPositions(world);
110
+ }
111
+ }
112
+ function clearJointAccumulators(joint, solver) {
113
+ solver.clearAccumulatedImpulses?.(joint);
114
+ joint.impulse0 = 0;
115
+ joint.impulse1 = 0;
116
+ joint.impulse2 = 0;
117
+ joint.impulse3 = 0;
118
+ joint.impulse4 = 0;
119
+ joint.impulse5 = 0;
120
+ }
121
+ // Visits every body the solve islands admit, in island-major order.
122
+ //
123
+ // The workspace holds only awake, non-static bodies, so this is also the sleeping skip — and the skip is
124
+ // a COST saving rather than a behavioural one, which is worth having in writing: a sleeping body's
125
+ // velocity is zeroed when it falls asleep and nothing can hand it more, because any awake neighbour puts
126
+ // it in an awake island before this point. What the skip buys is that a settled thousand-body pile costs
127
+ // no integration at all, which is the entire reason sleep exists.
128
+ function forEachSolveIslandBody(world, visit) {
129
+ for (let island = 0; island < world.solveIslandRoots.length; island += 1) {
130
+ const start = world.solveIslandBodyStarts[island];
131
+ const end = start + world.solveIslandBodyCounts[island];
132
+ for (let at = start; at < end; at += 1)
133
+ visit(world.bodies[world.solveIslandBodyIndices[at]]);
134
+ }
135
+ }
136
+ // Visits every joint the solve islands admit, paired with its registered solver. The workspace already
137
+ // excluded unregistered kinds and sleeping islands, so the callback never has to ask again.
138
+ function forEachSolveIslandJoint(world, visit) {
139
+ for (let island = 0; island < world.solveIslandRoots.length; island += 1) {
140
+ const start = world.solveIslandJointStarts[island];
141
+ const end = start + world.solveIslandJointCounts[island];
142
+ for (let at = start; at < end; at += 1) {
143
+ const joint = world.joints[world.solveIslandJointIndices[at]];
144
+ const solver = world.jointSolvers.get(joint.kind);
145
+ if (solver !== undefined)
146
+ visit(joint, solver);
147
+ }
148
+ }
149
+ }
150
+ // Moves every awake body by its solved velocity, then refreshes the world inertia the position pass is
151
+ // about to read. Two passes rather than one, because a body's pose must not move between another body's
152
+ // integration and its own: a single fused loop would have the second body's constraint arms measured
153
+ // against a world the first body had already left.
154
+ //
155
+ // Routes through the CONTINUOUS path when the world asks for it and some body is actually flagged. That
156
+ // path integrates in chronological order of impact instead of in one jump, which is the only way a body
157
+ // fast enough to cross a wall within the interval generates a contact at all. It is checked here rather
158
+ // than inside the continuous pass so a world with the config on and no bullets pays one scan of the body
159
+ // list rather than a swept broadphase.
160
+ function forEachSolveIslandPose(world, dt) {
161
+ if (world.config.continuousCollision && hasActivePhysics3DBullet(world)) {
162
+ integratePhysics3DContinuous(world, dt);
163
+ return;
164
+ }
165
+ forEachSolveIslandBody(world, (body) => integrateRigidBody3DPose(body, dt));
166
+ forEachSolveIslandBody(world, refreshRigidBody3DWorldInertia);
167
+ }
168
+ function restoreContactHookFields(contact, friction, restitution, enabled, sensor) {
169
+ contact.friction = friction;
170
+ contact.restitution = restitution;
171
+ contact.enabled = enabled;
172
+ contact.sensor = sensor;
173
+ }
174
+ // Runs a contact hook over every resolvable contact, putting back the fields it may touch if it
175
+ // misbehaves.
176
+ //
177
+ // Sensors are skipped, because they produce no constraint to solve and there is nothing for a hook to
178
+ // adjust. A hook that throws, or that leaves a contact the step cannot use, has its four mutable fields
179
+ // restored before the failure propagates — otherwise a caller catching the error would resume against a
180
+ // world the hook half-edited.
181
+ function runPhysics3DContactHook(world, hook, phase) {
182
+ if (hook === null)
183
+ return;
184
+ for (let contactIndex = 0; contactIndex < world.contacts.length; contactIndex += 1) {
185
+ const contact = world.contacts[contactIndex];
186
+ if (contact.sensor)
187
+ continue;
188
+ const friction = contact.friction;
189
+ const restitution = contact.restitution;
190
+ const enabled = contact.enabled;
191
+ const sensor = contact.sensor;
192
+ try {
193
+ hook(world, contact);
194
+ }
195
+ catch (error) {
196
+ restoreContactHookFields(contact, friction, restitution, enabled, sensor);
197
+ throw error;
198
+ }
199
+ if (!isPhysics3DContactValid(contact)) {
200
+ restoreContactHookFields(contact, friction, restitution, enabled, sensor);
201
+ throw new Error(`Physics3D ${phase} hook produced invalid contact state`);
202
+ }
203
+ }
204
+ }
205
+ // Expresses every cached impulse in the interval it is about to be reapplied over.
206
+ //
207
+ // An accumulated impulse has force-times-time units. Reusing one unchanged across a different interval
208
+ // applies the wrong force before the first iteration can correct it, which presents as a stack or a motor
209
+ // kicking whenever a frame changes cadence. The comparison is against the previous SUB-interval rather
210
+ // than the previous whole step, because a sub-interval's iterations are what built the cache — which is
211
+ // also why changing `substeps` between steps rescales correctly rather than silently by the wrong factor.
212
+ //
213
+ // A non-finite ratio clears the cache rather than seeding infinity from two otherwise-valid timesteps.
214
+ function scalePhysics3DWarmStartCaches(world, dt) {
215
+ const previous = world.previousTimestep;
216
+ if (!(previous > 0) || previous === dt)
217
+ return;
218
+ const divided = dt / previous;
219
+ const timestepRatio = Number.isFinite(divided) ? divided : 0;
220
+ for (let constraintIndex = 0; constraintIndex < world.solver.constraints.length; constraintIndex += 1) {
221
+ const constraint = world.solver.constraints[constraintIndex];
222
+ for (let i = 0; i < constraint.pointCount; i += 1) {
223
+ const point = constraint.points[i];
224
+ point.normalImpulse *= timestepRatio;
225
+ point.tangentImpulse0 *= timestepRatio;
226
+ point.tangentImpulse1 *= timestepRatio;
227
+ }
228
+ }
229
+ for (let jointIndex = 0; jointIndex < world.joints.length; jointIndex += 1) {
230
+ const joint = world.joints[jointIndex];
231
+ joint.impulse0 *= timestepRatio;
232
+ joint.impulse1 *= timestepRatio;
233
+ joint.impulse2 *= timestepRatio;
234
+ joint.impulse3 *= timestepRatio;
235
+ joint.impulse4 *= timestepRatio;
236
+ joint.impulse5 *= timestepRatio;
237
+ world.jointSolvers.get(joint.kind)?.scaleAccumulatedImpulses?.(joint, timestepRatio);
238
+ }
239
+ }
240
+ // The body of one step whose preconditions already hold.
241
+ function stepValidatedPhysics3D(world, dt) {
242
+ const substepDt = dt / world.config.substeps;
243
+ // Break events are cleared once per STEP, not per sub-interval, so a joint that parted during the first
244
+ // substep is still reported after the last one. Clearing inside the substep loop would drop every break
245
+ // but the final sub-interval's, and would do it silently — the joint stays broken either way, so the
246
+ // simulation would look right and only the notification would go missing.
247
+ world.jointEvents.broke.length = 0;
248
+ // Contacts are generated FIRST, from the poses the previous step left behind. The pre-solve hook is
249
+ // one transaction per public step: it runs before any interval commits, so a throw cannot leave half a
250
+ // substepped frame behind. Later interval refreshes retain its four mutable fields.
251
+ buildPhysics3DContacts(world);
252
+ // Pre-solve runs before anything is scaled or prepared, so a hook that disables a contact for this step
253
+ // does so before the constraint that would have resolved it is built.
254
+ runPhysics3DContactHook(world, world.contactHooks.preSolve, 'pre-solve');
255
+ // Scale only after pre-solve succeeds. A callback may throw, and scaling first would leave the cache
256
+ // expressed in the new interval while `previousTimestep` still described the old one; a retry would
257
+ // then scale an already-scaled cache a second time.
258
+ scalePhysics3DWarmStartCaches(world, substepDt);
259
+ // Sleep TIME is advanced once per step; later refreshes pass zero merely to rebuild the constraint
260
+ // graph and wake a sleeper reached by a body during an earlier interval. This preserves the meaning of
261
+ // `timeToSleep` while making a newly connected island live in the interval that discovered it.
262
+ updatePhysics3DSleep(world, dt);
263
+ buildPhysics3DSolveIslands(world);
264
+ for (let substep = 0; substep < world.config.substeps; substep += 1) {
265
+ if (substep > 0) {
266
+ // A substep that only re-runs the solver against the outer step's original contact list is not a
267
+ // smaller timestep: bodies can cross into a collider in interval one and remain invisible through
268
+ // every interval after it. Refreshing here makes N substeps topologically equivalent to N calls at
269
+ // the sub-interval, while aggregating begin/end events across the one public call.
270
+ refreshPhysics3DContacts(world);
271
+ updatePhysics3DSleep(world, 0);
272
+ buildPhysics3DSolveIslands(world);
273
+ }
274
+ stepPhysics3DInterval(world, substepDt);
275
+ }
276
+ for (let bodyIndex = 0; bodyIndex < world.bodies.length; bodyIndex += 1) {
277
+ clearRigidBody3DForces(world.bodies[bodyIndex]);
278
+ }
279
+ // CCD contacts are appended at TOI so they cannot shift the contact indices held by constraints that
280
+ // were prepared earlier in the interval. Those indices have expired now, so restore the canonical
281
+ // identity order before publishing the committed world and invoking post-solve hooks. The active-
282
+ // bullet condition is the same condition that can enter the CCD path; sorting every ordinary settled
283
+ // contact here added an O(n log n) tax to worlds that could not possibly have appended anything.
284
+ if (world.config.continuousCollision && hasActivePhysics3DBullet(world)) {
285
+ world.contacts.sort(comparePhysics3DContactIdentity);
286
+ }
287
+ world.previousTimestep = substepDt;
288
+ // Post-solve observes a committed step. A hook that throws here cannot prevent pose integration, force
289
+ // cleanup, or the timestep agreement above, so the next call never resumes a half-finished step.
290
+ runPhysics3DContactHook(world, world.contactHooks.postSolve, 'post-solve');
291
+ }
292
+ function comparePhysics3DContactIdentity(left, right) {
293
+ if (left.bodyA !== right.bodyA)
294
+ return left.bodyA - right.bodyA;
295
+ if (left.bodyB !== right.bodyB)
296
+ return left.bodyB - right.bodyB;
297
+ if (left.colliderA !== right.colliderA)
298
+ return left.colliderA - right.colliderA;
299
+ return left.colliderB - right.colliderB;
300
+ }
301
+ let physics3DStepGuard = null;
302
+ //# sourceMappingURL=step.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step.js","sourceRoot":"","sources":["../src/step.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Physics3DContact, Physics3DSolverConfig, Physics3DWorld } from '@flighthq/types/contract';
2
+ export declare function isPhysics3DBodyStateValid(world: Readonly<Physics3DWorld>): boolean;
3
+ export declare function isPhysics3DColliderStateValid(world: Readonly<Physics3DWorld>): boolean;
4
+ export declare function isPhysics3DContactStateValid(world: Readonly<Physics3DWorld>): boolean;
5
+ export declare function isPhysics3DContactValid(contact: Readonly<Physics3DContact>): boolean;
6
+ export declare function isPhysics3DGravityValid(world: Readonly<Physics3DWorld>): boolean;
7
+ export declare function isPhysics3DJointStateValid(world: Readonly<Physics3DWorld>): boolean;
8
+ export declare function isPhysics3DPositionIterationsValid(config: Readonly<Physics3DSolverConfig>): boolean;
9
+ export declare function isPhysics3DSolverConfigValid(config: Readonly<Physics3DSolverConfig>): boolean;
10
+ export declare function isPhysics3DSubstepsValid(config: Readonly<Physics3DSolverConfig>): boolean;
11
+ export declare function isPhysics3DTimestepValid(dt: number): boolean;
12
+ export declare function isPhysics3DVelocityIterationsValid(config: Readonly<Physics3DSolverConfig>): boolean;
13
+ //# sourceMappingURL=stepValidation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stepValidation.d.ts","sourceRoot":"","sources":["../src/stepValidation.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAEV,gBAAgB,EAEhB,qBAAqB,EACrB,cAAc,EAEf,MAAM,0BAA0B,CAAC;AAclC,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,GAAG,OAAO,CAclF;AAQD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,GAAG,OAAO,CAStF;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,GAAG,OAAO,CAKrF;AAID,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,OAAO,CA4CpF;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,GAAG,OAAO,CAEhF;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,GAAG,OAAO,CAKnF;AAED,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,QAAQ,CAAC,qBAAqB,CAAC,GAAG,OAAO,CAGnG;AAKD,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,QAAQ,CAAC,qBAAqB,CAAC,GAAG,OAAO,CAwB7F;AAID,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,QAAQ,CAAC,qBAAqB,CAAC,GAAG,OAAO,CAEzF;AAED,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,QAAQ,CAAC,qBAAqB,CAAC,GAAG,OAAO,CAGnG"}
@@ -0,0 +1,284 @@
1
+ import { getCollisionHeightfieldValidationStatus3D, getCollisionShapeValidationStatus3D, getCollisionTriangleMeshValidationStatus3D, } from '@flighthq/collision/contract';
2
+ // The preconditions one explicit step needs to be meaningful, each asked as its own question.
3
+ //
4
+ // Separate predicates rather than one `canStep`, because they are the rows of `Physics3DStepExplanation`
5
+ // and a caller diagnosing a world that will not advance needs to know WHICH one failed. `stepPhysics3D`
6
+ // asks all of them and returns silently on any false; `explainPhysics3DStep` asks the same ones and
7
+ // reports. That is the diagnostics inversion — the step carries no messages, and the explain seam is
8
+ // separately importable so a shipping build that never asks never links it.
9
+ //
10
+ // A world that fails one of these is not an error to throw on: a NaN velocity, a zero timestep, or a
11
+ // negative iteration count is a state a caller can reach by writing a field, and a throw from inside the
12
+ // step would take down a frame loop for something the caller can inspect and repair.
13
+ export function isPhysics3DBodyStateValid(world) {
14
+ if (!Number.isSafeInteger(world.nextBodyIndex) || world.nextBodyIndex < 0)
15
+ return false;
16
+ for (let bodyIndex = 0; bodyIndex < world.bodies.length; bodyIndex += 1) {
17
+ const body = world.bodies[bodyIndex];
18
+ if (!isRigidBody3DStateValid(body) ||
19
+ !Array.isArray(body.colliders) ||
20
+ (body.type !== 'static' && body.colliders.some(isPhysics3DStaticSurfaceCollider)) ||
21
+ world.bodyByIndex.get(body.index) !== body) {
22
+ return false;
23
+ }
24
+ }
25
+ return true;
26
+ }
27
+ function isPhysics3DStaticSurfaceCollider(collider) {
28
+ return collider.local.kind === 'triangle-mesh' || collider.local.kind === 'heightfield';
29
+ }
30
+ // Validates the data that will generate NEW contacts during this step. Keeping this separate from body
31
+ // state is diagnostic: a NaN material is repaired at a collider, not in the body's pose or inertia.
32
+ export function isPhysics3DColliderStateValid(world) {
33
+ for (let bodyIndex = 0; bodyIndex < world.bodies.length; bodyIndex += 1) {
34
+ const body = world.bodies[bodyIndex];
35
+ if (!Array.isArray(body.colliders))
36
+ return false;
37
+ for (let colliderIndex = 0; colliderIndex < body.colliders.length; colliderIndex += 1) {
38
+ if (!isPhysics3DColliderValid(body.colliders[colliderIndex]))
39
+ return false;
40
+ }
41
+ }
42
+ return true;
43
+ }
44
+ export function isPhysics3DContactStateValid(world) {
45
+ for (let contactIndex = 0; contactIndex < world.contacts.length; contactIndex += 1) {
46
+ if (!isPhysics3DContactValid(world.contacts[contactIndex]))
47
+ return false;
48
+ }
49
+ return true;
50
+ }
51
+ // Also the post-hook check: a pre-solve or post-solve callback may write contact fields, and this is what
52
+ // says whether what it wrote is still steppable.
53
+ export function isPhysics3DContactValid(contact) {
54
+ if (!Number.isSafeInteger(contact.bodyA) ||
55
+ !Number.isSafeInteger(contact.bodyB) ||
56
+ !Number.isSafeInteger(contact.colliderA) ||
57
+ contact.colliderA < 0 ||
58
+ !Number.isSafeInteger(contact.colliderB) ||
59
+ contact.colliderB < 0 ||
60
+ !Number.isSafeInteger(contact.pointCount) ||
61
+ contact.pointCount < 0 ||
62
+ contact.pointCount > contact.points.length ||
63
+ !Number.isFinite(contact.normalX) ||
64
+ !Number.isFinite(contact.normalY) ||
65
+ !Number.isFinite(contact.normalZ) ||
66
+ !Number.isFinite(contact.friction) ||
67
+ contact.friction < 0 ||
68
+ !Number.isFinite(contact.restitution) ||
69
+ contact.restitution < 0 ||
70
+ typeof contact.enabled !== 'boolean' ||
71
+ typeof contact.sensor !== 'boolean' ||
72
+ typeof contact.touching !== 'boolean') {
73
+ return false;
74
+ }
75
+ for (let i = 0; i < contact.pointCount; i += 1) {
76
+ const point = contact.points[i];
77
+ if (point === undefined)
78
+ return false;
79
+ if (!Number.isFinite(point.x) ||
80
+ !Number.isFinite(point.y) ||
81
+ !Number.isFinite(point.z) ||
82
+ !Number.isFinite(point.depth) ||
83
+ !Number.isFinite(point.featureId) ||
84
+ !Number.isFinite(point.rAX) ||
85
+ !Number.isFinite(point.rAY) ||
86
+ !Number.isFinite(point.rAZ) ||
87
+ !Number.isFinite(point.rBX) ||
88
+ !Number.isFinite(point.rBY) ||
89
+ !Number.isFinite(point.rBZ)) {
90
+ return false;
91
+ }
92
+ }
93
+ return true;
94
+ }
95
+ export function isPhysics3DGravityValid(world) {
96
+ return Number.isFinite(world.gravityX) && Number.isFinite(world.gravityY) && Number.isFinite(world.gravityZ);
97
+ }
98
+ export function isPhysics3DJointStateValid(world) {
99
+ for (let jointIndex = 0; jointIndex < world.joints.length; jointIndex += 1) {
100
+ if (!isPhysics3DJointValid(world.joints[jointIndex]))
101
+ return false;
102
+ }
103
+ return true;
104
+ }
105
+ export function isPhysics3DPositionIterationsValid(config) {
106
+ const iterations = config.sequentialImpulse.positionIterations;
107
+ return Number.isSafeInteger(iterations) && iterations >= 0;
108
+ }
109
+ // The solver-independent knobs plus the sequential-impulse block. Iteration counts and `substeps` are
110
+ // asked separately, because they are the three a caller is most likely to have tuned by hand and the
111
+ // explanation names each of them.
112
+ export function isPhysics3DSolverConfigValid(config) {
113
+ const sequential = config.sequentialImpulse;
114
+ return (typeof config.allowSleeping === 'boolean' &&
115
+ Number.isFinite(config.sleepLinearThreshold) &&
116
+ config.sleepLinearThreshold >= 0 &&
117
+ Number.isFinite(config.sleepAngularThreshold) &&
118
+ config.sleepAngularThreshold >= 0 &&
119
+ Number.isFinite(config.timeToSleep) &&
120
+ config.timeToSleep >= 0 &&
121
+ typeof config.continuousCollision === 'boolean' &&
122
+ Number.isSafeInteger(config.maxCcdSubsteps) &&
123
+ config.maxCcdSubsteps >= 0 &&
124
+ Number.isSafeInteger(config.maxCcdRotationSubsteps) &&
125
+ config.maxCcdRotationSubsteps >= 0 &&
126
+ Number.isFinite(sequential.penetrationSlop) &&
127
+ sequential.penetrationSlop >= 0 &&
128
+ Number.isFinite(sequential.positionCorrection) &&
129
+ sequential.positionCorrection >= 0 &&
130
+ sequential.positionCorrection <= 1 &&
131
+ Number.isFinite(sequential.restitutionThreshold) &&
132
+ sequential.restitutionThreshold >= 0 &&
133
+ typeof sequential.warmStarting === 'boolean');
134
+ }
135
+ // At least one, because `substeps` divides the timestep and the step runs the loop that many times. Zero
136
+ // would advance nothing while reporting a completed step, which is worse than declining to step at all.
137
+ export function isPhysics3DSubstepsValid(config) {
138
+ return Number.isSafeInteger(config.substeps) && config.substeps >= 1;
139
+ }
140
+ export function isPhysics3DTimestepValid(dt) {
141
+ return Number.isFinite(dt) && dt > 0;
142
+ }
143
+ export function isPhysics3DVelocityIterationsValid(config) {
144
+ const iterations = config.sequentialImpulse.velocityIterations;
145
+ return Number.isSafeInteger(iterations) && iterations >= 0;
146
+ }
147
+ function isPhysics3DJointValid(joint) {
148
+ if (typeof joint.kind !== 'string' ||
149
+ joint.kind.length === 0 ||
150
+ !Number.isSafeInteger(joint.bodyA) ||
151
+ !Number.isSafeInteger(joint.bodyB) ||
152
+ typeof joint.collideConnected !== 'boolean') {
153
+ return false;
154
+ }
155
+ // Every numeric field, whatever the kind added — a limit, a motor speed, a frame component. Walking the
156
+ // object rather than a fixed key list is what makes this cover a user's own joint kind, which is the
157
+ // point of an open registry.
158
+ //
159
+ // Except the fields where INFINITY IS THE VALUE, not a symptom. A `breakForce` of infinity is a joint
160
+ // that never breaks and a `maxLength` of infinity is a rope with no far stop, and both are the natural
161
+ // defaults — so a blanket finiteness walk declares every ordinary joint invalid and the world declines
162
+ // to step at all. That failure is silent by design (an invalid step is skipped, not thrown), so it
163
+ // presents as a motor that does not turn and contacts that never fire, with nothing pointing at the
164
+ // joint. Adding a field whose unset state is "no bound" means adding it here too.
165
+ for (const key in joint) {
166
+ if (UNBOUNDED_JOINT_FIELDS.has(key))
167
+ continue;
168
+ const value = joint[key];
169
+ if (typeof value === 'number' && !Number.isFinite(value))
170
+ return false;
171
+ }
172
+ return true;
173
+ }
174
+ function isRigidBody3DStateValid(body) {
175
+ const orientationLengthSquared = body.orientationX * body.orientationX +
176
+ body.orientationY * body.orientationY +
177
+ body.orientationZ * body.orientationZ +
178
+ body.orientationW * body.orientationW;
179
+ if (!Number.isSafeInteger(body.index) ||
180
+ body.index < 0 ||
181
+ (body.type !== 'dynamic' && body.type !== 'kinematic' && body.type !== 'static') ||
182
+ typeof body.fixedRotation !== 'boolean' ||
183
+ typeof body.bullet !== 'boolean' ||
184
+ typeof body.sleeping !== 'boolean' ||
185
+ typeof body.sleepEnabled !== 'boolean' ||
186
+ !Number.isFinite(body.sleepTimer) ||
187
+ body.sleepTimer < 0 ||
188
+ !Number.isFinite(body.linearDamping) ||
189
+ body.linearDamping < 0 ||
190
+ !Number.isFinite(body.angularDamping) ||
191
+ body.angularDamping < 0 ||
192
+ !Number.isFinite(body.gravityScale) ||
193
+ !Number.isFinite(body.mass) ||
194
+ body.mass < 0 ||
195
+ !Number.isFinite(body.inverseMass) ||
196
+ body.inverseMass < 0 ||
197
+ !Number.isFinite(orientationLengthSquared) ||
198
+ Math.abs(orientationLengthSquared - 1) > PHYSICS3D_QUATERNION_LENGTH_TOLERANCE) {
199
+ return false;
200
+ }
201
+ for (let keyIndex = 0; keyIndex < rigidBody3DFiniteKeys.length; keyIndex += 1) {
202
+ if (!Number.isFinite(body[rigidBody3DFiniteKeys[keyIndex]]))
203
+ return false;
204
+ }
205
+ return true;
206
+ }
207
+ function isPhysics3DColliderValid(collider) {
208
+ const material = collider.material;
209
+ const filter = collider.filter;
210
+ return (getPhysics3DColliderShapeValidationStatus(collider.local) === null &&
211
+ getPhysics3DColliderShapeValidationStatus(collider.world) === null &&
212
+ isPhysics3DColliderWorldShapeCompatible(collider) &&
213
+ Number.isFinite(material.density) &&
214
+ material.density >= 0 &&
215
+ Number.isFinite(material.friction) &&
216
+ material.friction >= 0 &&
217
+ Number.isFinite(material.restitution) &&
218
+ material.restitution >= 0 &&
219
+ Number.isSafeInteger(filter.categoryBits) &&
220
+ Number.isSafeInteger(filter.maskBits) &&
221
+ Number.isSafeInteger(filter.groupIndex) &&
222
+ typeof collider.sensor === 'boolean');
223
+ }
224
+ function getPhysics3DColliderShapeValidationStatus(shape) {
225
+ if (shape.kind === 'triangle-mesh')
226
+ return getCollisionTriangleMeshValidationStatus3D(shape);
227
+ if (shape.kind === 'heightfield')
228
+ return getCollisionHeightfieldValidationStatus3D(shape);
229
+ return getCollisionShapeValidationStatus3D(shape);
230
+ }
231
+ function isPhysics3DColliderWorldShapeCompatible(collider) {
232
+ return collider.world.kind === (collider.local.kind === 'aabb' ? 'box' : collider.local.kind);
233
+ }
234
+ // Every field that has to be a real number for the step to mean anything: the pose, the velocities, the
235
+ // accumulators, the centre of mass, and all three inertia tensors. The world tensor is derived and is
236
+ // included anyway — it is what every constraint row multiplies by, so a NaN there reaches both bodies of
237
+ // every contact and joint within one substep.
238
+ const rigidBody3DFiniteKeys = [
239
+ 'x',
240
+ 'y',
241
+ 'z',
242
+ 'orientationX',
243
+ 'orientationY',
244
+ 'orientationZ',
245
+ 'orientationW',
246
+ 'velocityX',
247
+ 'velocityY',
248
+ 'velocityZ',
249
+ 'angularVelocityX',
250
+ 'angularVelocityY',
251
+ 'angularVelocityZ',
252
+ 'forceX',
253
+ 'forceY',
254
+ 'forceZ',
255
+ 'torqueX',
256
+ 'torqueY',
257
+ 'torqueZ',
258
+ 'centerX',
259
+ 'centerY',
260
+ 'centerZ',
261
+ 'inertiaXX',
262
+ 'inertiaYY',
263
+ 'inertiaZZ',
264
+ 'inertiaXY',
265
+ 'inertiaXZ',
266
+ 'inertiaYZ',
267
+ 'inverseInertiaXX',
268
+ 'inverseInertiaYY',
269
+ 'inverseInertiaZZ',
270
+ 'inverseInertiaXY',
271
+ 'inverseInertiaXZ',
272
+ 'inverseInertiaYZ',
273
+ 'inverseInertiaWorldXX',
274
+ 'inverseInertiaWorldYY',
275
+ 'inverseInertiaWorldZZ',
276
+ 'inverseInertiaWorldXY',
277
+ 'inverseInertiaWorldXZ',
278
+ 'inverseInertiaWorldYZ',
279
+ ];
280
+ // Joint fields whose infinite value is meaningful rather than corrupt: a threshold that is never reached
281
+ // and a bound that never stops anything.
282
+ const UNBOUNDED_JOINT_FIELDS = new Set(['breakForce', 'breakTorque', 'maxLength']);
283
+ const PHYSICS3D_QUATERNION_LENGTH_TOLERANCE = 1e-6;
284
+ //# sourceMappingURL=stepValidation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stepValidation.js","sourceRoot":"","sources":["../src/stepValidation.ts"],"names":[],"mappings":"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"}