@series-inc/rundot-syncplay 5.28.0-beta.3 → 5.28.0-beta.4
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.
- package/core/physics.d.ts +1 -0
- package/core/src/physics/index.mjs +1 -0
- package/dist/browser.d.ts +3 -3
- package/dist/browser.js +1 -1
- package/dist/creator.d.ts +3 -3
- package/dist/creator.js +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/physics3d-joints.d.ts +4 -0
- package/dist/physics3d-joints.js +73 -11
- package/dist/physics3d-shared.js +26 -7
- package/dist/physics3d-solver.d.ts +19 -0
- package/dist/physics3d-solver.js +302 -0
- package/dist/physics3d-voxel.d.ts +13 -0
- package/dist/physics3d-voxel.js +124 -0
- package/dist/physics3d.d.ts +5 -0
- package/dist/physics3d.js +49 -2
- package/package.json +2 -2
package/core/physics.d.ts
CHANGED
|
@@ -276,6 +276,7 @@ export interface KinetixPhysicsStepResult {
|
|
|
276
276
|
readonly world: KinetixPhysicsWorld;
|
|
277
277
|
readonly contacts: readonly KinetixPhysicsContactEvent[];
|
|
278
278
|
readonly brokenJointIds: readonly string[];
|
|
279
|
+
readonly brokenJoints: readonly string[];
|
|
279
280
|
readonly scheduledQueryResults: readonly { readonly id: string; readonly hits: readonly KinetixPhysicsHit[] }[];
|
|
280
281
|
readonly prePhysicsScheduledQueryResults: readonly { readonly id: string; readonly hits: readonly KinetixPhysicsHit[] }[];
|
|
281
282
|
readonly postPhysicsScheduledQueryResults: readonly { readonly id: string; readonly hits: readonly KinetixPhysicsHit[] }[];
|
|
@@ -2953,6 +2953,7 @@ export function stepPhysicsWorld(world, options) {
|
|
|
2953
2953
|
world: nextWorld,
|
|
2954
2954
|
contacts: visibleEvents,
|
|
2955
2955
|
brokenJointIds,
|
|
2956
|
+
brokenJoints: brokenJointIds,
|
|
2956
2957
|
scheduledQueryResults,
|
|
2957
2958
|
prePhysicsScheduledQueryResults,
|
|
2958
2959
|
postPhysicsScheduledQueryResults,
|
package/dist/browser.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export { createSyncplayRunner } from './runner.js';
|
|
|
25
25
|
export { fbm2D, hash2, hashUint32, valueNoise1D, valueNoise2D } from './noise.js';
|
|
26
26
|
export { circleCastDeterministicPhysics2D, createDeterministicPhysicsWorld2D, nearestDeterministicPhysicsHit2D, queryDeterministicPhysicsAabb2D, queryDeterministicPhysicsShapeOverlap2D, raycastAllDeterministicPhysics2D, raycastDeterministicPhysics2D, stepDeterministicPhysicsWorld2D } from './physics2d.js';
|
|
27
27
|
export { applyDeterministicForces3D, applyDeterministicImpulse3D, applyDeterministicImpulses3D, applyDeterministicWorldEdit3D, contactDetailsDeterministicPhysics3D, createBoxShapeFromExtents, createBoxShapeFromMinMax, createCapsuleShapeFromBase, createDeterministicPhysicsWorld3D, createTrustedDeterministicPhysicsWorld3D, deriveInverseInertia, deterministicPhysicsBodyById3D, deterministicPhysicsCallback3D, overlapDeterministicPhysics3D, raycastDeterministicPhysics3D, raycastDeterministicPhysics3DDetailed, runDeterministicPhysics3DStress, setDeterministicBodyVelocity3D, setDeterministicKinematicPoses3D, setDeterministicKinematicTransforms3D, shapeCastDeterministicPhysics3D, shapeCastDeterministicPhysics3DDetailed, stepDeterministicPhysicsWorld3D } from './physics3d.js';
|
|
28
|
-
export { carveDeterministicVoxelChunk3D, cookDeterministicVoxelChunkCollider3D, cookDeterministicVoxelSubregion3D, recookDeterministicVoxelSubregion3D, raycastDeterministicVoxelChunk3D, splitDeterministicVoxelChunk3D } from './physics3d-voxel.js';
|
|
28
|
+
export { carveDeterministicVoxelChunk3D, cookDeterministicVoxelChunkCollider3D, cookDeterministicVoxelSubregion3D, recookDeterministicVoxelSubregion3D, raycastDeterministicVoxelChunk3D, splitDeterministicVoxelChunk3D, splitDeterministicVoxelCompoundCollider3D } from './physics3d-voxel.js';
|
|
29
29
|
export { generatePhysicsWorldDebugMesh } from './debug-wireframe.js';
|
|
30
30
|
export { cylinderHullVertices } from './physics3d-hull.js';
|
|
31
31
|
export { createDeterministicCosmeticPhysicsWorld3D, setDeterministicCosmeticPhysicsAuthoritativeBodyProxies3D, stepDeterministicCosmeticPhysicsWorld3D } from './cosmetic-physics3d.js';
|
|
@@ -66,8 +66,8 @@ export type { CookedDeterministicNavmesh, DeterministicNavmeshAgent, Determinist
|
|
|
66
66
|
export type { ConfirmedSyncplayPresentationFrame, KinetixRuntimeFactory, NetworkedClientTransport, NetworkedSyncplayClient, NetworkedSyncplayClientInputDelayOptions, NetworkedSyncplayClientNetStats, NetworkedSyncplayClientOptions, NetworkedSyncplayClientPacingOptions, NetworkedSyncplayPreparationOptions, NetworkedSyncplaySessionDescriptor, NetworkedSyncplaySlotPresence, PreparedNetworkedSyncplayTransport, SyncplayPredictionMode, SyncplayRemoteInputPrediction } from './networked-client.js';
|
|
67
67
|
export type { SyncplayRunner, SyncplayRunnerConfig, SyncplayRunnerConnectionEvent, SyncplayRunnerOccupancy, SyncplayRunnerOfflineOptions, SyncplayRunnerPresentation, SyncplayRunnerSnapshot, SyncplayRunnerStatus, SyncplayRunnerTransport } from './runner.js';
|
|
68
68
|
export type { DeterministicBodyKind, DeterministicContactEvent2D, DeterministicContactEventType, DeterministicPhysicsAabbQuery2D, DeterministicPhysicsActivePair2D, DeterministicPhysicsBody2D, DeterministicPhysicsCircleCastQuery2D, DeterministicPhysicsConstraint2D, DeterministicPhysicsHit2D, DeterministicPhysicsQueryOptions2D, DeterministicPhysicsRaycastQuery2D, DeterministicPhysicsShape2D, DeterministicPhysicsShapeOverlapQuery2D, DeterministicPhysicsStepOptions2D, DeterministicPhysicsStepResult2D, DeterministicPhysicsWorld2D } from './physics2d.js';
|
|
69
|
-
export type { DeterministicContactCacheEntry3D, DeterministicJointCacheEntry3D, DeterministicKinematicPose3D, DeterministicKinematicTransformBuffer3D, DeterministicPhysicsActivePair3D, DeterministicPhysicsAxisLock3D, DeterministicPhysicsBody3D, DeterministicPhysicsCallbackMask3D, DeterministicPhysicsCompoundChild3D, DeterministicPhysicsCompoundChildShape3D, DeterministicPhysicsConstraint3D, DeterministicPhysicsContactDetail3D, DeterministicPhysicsContactEvent3D, DeterministicPhysicsDetailedHit3D, DeterministicPhysicsForceApplication3D, DeterministicPhysicsHit3D, DeterministicPhysicsHullShape3D, DeterministicPhysicsImpulseApplication3D, DeterministicPhysicsOverlapQuery3D, DeterministicPhysicsPrimitiveShape3D, DeterministicPhysicsQuaternion3D, DeterministicPhysicsQueryOptions3D, DeterministicPhysicsRaycastQuery3D, DeterministicPhysicsScheduledQuery3D, DeterministicPhysicsShape3D, DeterministicPhysicsShapeCastQuery3D, DeterministicPhysicsStepOptions3D, DeterministicPhysicsStepResult3D, DeterministicPhysicsVec3, DeterministicPhysicsWorld3D, DeterministicPhysicsWorldEdit3D } from './physics3d.js';
|
|
70
|
-
export type { DeterministicVoxelChunk3D, DeterministicVoxelCompoundShape3D, DeterministicVoxelRayHit3D, SplitDeterministicVoxelChunkOptions3D, VoxelAnchorFace, VoxelBoxCarveRegion3D, VoxelCapsuleCarveRegion3D, VoxelCarveRegion3D, VoxelOccupancy3D, VoxelSphereCarveRegion3D, VoxelSubChunk3D } from './physics3d-voxel.js';
|
|
69
|
+
export type { DeterministicContactCacheEntry3D, DeterministicFluidVolume3D, DeterministicJointCacheEntry3D, DeterministicKinematicPose3D, DeterministicKinematicTransformBuffer3D, DeterministicPhysicsAabb3D, DeterministicPhysicsActivePair3D, DeterministicPhysicsAxisLock3D, DeterministicPhysicsBody3D, DeterministicPhysicsCallbackMask3D, DeterministicPhysicsCompoundChild3D, DeterministicPhysicsCompoundChildShape3D, DeterministicPhysicsConstraint3D, DeterministicPhysicsContactDetail3D, DeterministicPhysicsContactEvent3D, DeterministicPhysicsDetailedHit3D, DeterministicPhysicsForceApplication3D, DeterministicPhysicsHit3D, DeterministicPhysicsHullShape3D, DeterministicPhysicsImpulseApplication3D, DeterministicPhysicsOverlapQuery3D, DeterministicPhysicsPrimitiveShape3D, DeterministicPhysicsQuaternion3D, DeterministicPhysicsQueryOptions3D, DeterministicPhysicsRaycastQuery3D, DeterministicPhysicsScheduledQuery3D, DeterministicPhysicsShape3D, DeterministicPhysicsShapeCastQuery3D, DeterministicPhysicsStepOptions3D, DeterministicPhysicsStepResult3D, DeterministicPhysicsVec3, DeterministicPhysicsWorld3D, DeterministicPhysicsWorldEdit3D } from './physics3d.js';
|
|
70
|
+
export type { DeterministicVoxelChunk3D, DeterministicVoxelCompoundShape3D, DeterministicVoxelCompoundSplitResult3D, DeterministicVoxelRayHit3D, SplitDeterministicVoxelChunkOptions3D, VoxelAnchorFace, VoxelBoxCarveRegion3D, VoxelCapsuleCarveRegion3D, VoxelCarveRegion3D, VoxelOccupancy3D, VoxelSphereCarveRegion3D, VoxelSubChunk3D } from './physics3d-voxel.js';
|
|
71
71
|
export type { PhysicsWorldDebugMesh, PhysicsWorldDebugMeshOptions } from './debug-wireframe.js';
|
|
72
72
|
export type { DeterministicAuthoritativeBodyProxy3D, DeterministicCosmeticPhysicsBody3D, DeterministicCosmeticPhysicsStepOptions3D, DeterministicCosmeticPhysicsStepResult3D, DeterministicCosmeticPhysicsWorld3D } from './cosmetic-physics3d.js';
|
|
73
73
|
export type { DeterministicPhysicsJoint3D } from './physics3d-joints.js';
|
package/dist/browser.js
CHANGED
|
@@ -26,7 +26,7 @@ export { createSyncplayRunner } from './runner.js';
|
|
|
26
26
|
export { fbm2D, hash2, hashUint32, valueNoise1D, valueNoise2D } from './noise.js';
|
|
27
27
|
export { circleCastDeterministicPhysics2D, createDeterministicPhysicsWorld2D, nearestDeterministicPhysicsHit2D, queryDeterministicPhysicsAabb2D, queryDeterministicPhysicsShapeOverlap2D, raycastAllDeterministicPhysics2D, raycastDeterministicPhysics2D, stepDeterministicPhysicsWorld2D } from './physics2d.js';
|
|
28
28
|
export { applyDeterministicForces3D, applyDeterministicImpulse3D, applyDeterministicImpulses3D, applyDeterministicWorldEdit3D, contactDetailsDeterministicPhysics3D, createBoxShapeFromExtents, createBoxShapeFromMinMax, createCapsuleShapeFromBase, createDeterministicPhysicsWorld3D, createTrustedDeterministicPhysicsWorld3D, deriveInverseInertia, deterministicPhysicsBodyById3D, deterministicPhysicsCallback3D, overlapDeterministicPhysics3D, raycastDeterministicPhysics3D, raycastDeterministicPhysics3DDetailed, runDeterministicPhysics3DStress, setDeterministicBodyVelocity3D, setDeterministicKinematicPoses3D, setDeterministicKinematicTransforms3D, shapeCastDeterministicPhysics3D, shapeCastDeterministicPhysics3DDetailed, stepDeterministicPhysicsWorld3D } from './physics3d.js';
|
|
29
|
-
export { carveDeterministicVoxelChunk3D, cookDeterministicVoxelChunkCollider3D, cookDeterministicVoxelSubregion3D, recookDeterministicVoxelSubregion3D, raycastDeterministicVoxelChunk3D, splitDeterministicVoxelChunk3D } from './physics3d-voxel.js';
|
|
29
|
+
export { carveDeterministicVoxelChunk3D, cookDeterministicVoxelChunkCollider3D, cookDeterministicVoxelSubregion3D, recookDeterministicVoxelSubregion3D, raycastDeterministicVoxelChunk3D, splitDeterministicVoxelChunk3D, splitDeterministicVoxelCompoundCollider3D } from './physics3d-voxel.js';
|
|
30
30
|
export { generatePhysicsWorldDebugMesh } from './debug-wireframe.js';
|
|
31
31
|
export { cylinderHullVertices } from './physics3d-hull.js';
|
|
32
32
|
export { createDeterministicCosmeticPhysicsWorld3D, setDeterministicCosmeticPhysicsAuthoritativeBodyProxies3D, stepDeterministicCosmeticPhysicsWorld3D } from './cosmetic-physics3d.js';
|
package/dist/creator.d.ts
CHANGED
|
@@ -13,13 +13,13 @@ export type { ReplayRuntimeFactory, ReplayVerificationConfig, ReplayVerification
|
|
|
13
13
|
export type { SyncplaySession, SyncplaySessionPolicy } from './sdk-session.js';
|
|
14
14
|
export type { InstantReplayInputFrame, InstantReplayResult, InstantReplayRunner, InstantReplayRunnerOptions, InstantReplayRunOptions, RunInstantReplayOptions, } from './instant-replay.js';
|
|
15
15
|
export { applyDeterministicForces3D, applyDeterministicImpulse3D, applyDeterministicImpulses3D, applyDeterministicWorldEdit3D, contactDetailsDeterministicPhysics3D, createBoxShapeFromExtents, createBoxShapeFromMinMax, createCapsuleShapeFromBase, createDeterministicPhysicsWorld3D, deriveInverseInertia, deterministicPhysicsBodyById3D, deterministicPhysicsCallback3D, overlapDeterministicPhysics3D, raycastDeterministicPhysics3D, raycastDeterministicPhysics3DDetailed, runDeterministicPhysics3DStress, setDeterministicBodyVelocity3D, setDeterministicKinematicPoses3D, setDeterministicKinematicTransforms3D, shapeCastDeterministicPhysics3D, shapeCastDeterministicPhysics3DDetailed, stepDeterministicPhysicsWorld3D, } from './physics3d.js';
|
|
16
|
-
export { carveDeterministicVoxelChunk3D, cookDeterministicVoxelChunkCollider3D, cookDeterministicVoxelSubregion3D, recookDeterministicVoxelSubregion3D, raycastDeterministicVoxelChunk3D, splitDeterministicVoxelChunk3D, } from './physics3d-voxel.js';
|
|
16
|
+
export { carveDeterministicVoxelChunk3D, cookDeterministicVoxelChunkCollider3D, cookDeterministicVoxelSubregion3D, recookDeterministicVoxelSubregion3D, raycastDeterministicVoxelChunk3D, splitDeterministicVoxelChunk3D, splitDeterministicVoxelCompoundCollider3D, } from './physics3d-voxel.js';
|
|
17
17
|
export { generatePhysicsWorldDebugMesh } from './debug-wireframe.js';
|
|
18
18
|
export { cylinderHullVertices } from './physics3d-hull.js';
|
|
19
19
|
export { stepDeterministicVehicle3D } from './physics3d-vehicle.js';
|
|
20
20
|
export { createDeterministicBinarySerializer, deterministicDslMaxPlayers, parseDeterministicSchemaDsl, stableDeterministicDslSchemaJson, } from './schema-dsl-binary.js';
|
|
21
|
-
export type { DeterministicContactCacheEntry3D, DeterministicJointCacheEntry3D, DeterministicKinematicPose3D, DeterministicKinematicTransformBuffer3D, DeterministicPhysicsActivePair3D, DeterministicPhysicsAxisLock3D, DeterministicPhysicsBody3D, DeterministicPhysicsCallbackMask3D, DeterministicPhysicsCompoundChild3D, DeterministicPhysicsCompoundChildShape3D, DeterministicPhysicsConstraint3D, DeterministicPhysicsContactDetail3D, DeterministicPhysicsContactEvent3D, DeterministicPhysicsDetailedHit3D, DeterministicPhysicsForceApplication3D, DeterministicPhysicsHit3D, DeterministicPhysicsHullShape3D, DeterministicPhysicsImpulseApplication3D, DeterministicPhysicsOverlapQuery3D, DeterministicPhysicsPrimitiveShape3D, DeterministicPhysicsQuaternion3D, DeterministicPhysicsQueryOptions3D, DeterministicPhysicsRaycastQuery3D, DeterministicPhysicsScheduledQuery3D, DeterministicPhysicsShape3D, DeterministicPhysicsShapeCastQuery3D, DeterministicPhysicsStepOptions3D, DeterministicPhysicsStepResult3D, DeterministicPhysicsVec3, DeterministicPhysicsWorld3D, DeterministicPhysicsWorldEdit3D, } from './physics3d.js';
|
|
22
|
-
export type { DeterministicVoxelChunk3D, DeterministicVoxelCompoundShape3D, DeterministicVoxelRayHit3D, SplitDeterministicVoxelChunkOptions3D, VoxelAnchorFace, VoxelBoxCarveRegion3D, VoxelCapsuleCarveRegion3D, VoxelCarveRegion3D, VoxelOccupancy3D, VoxelSphereCarveRegion3D, VoxelSubChunk3D, } from './physics3d-voxel.js';
|
|
21
|
+
export type { DeterministicContactCacheEntry3D, DeterministicFluidVolume3D, DeterministicJointCacheEntry3D, DeterministicKinematicPose3D, DeterministicKinematicTransformBuffer3D, DeterministicPhysicsAabb3D, DeterministicPhysicsActivePair3D, DeterministicPhysicsAxisLock3D, DeterministicPhysicsBody3D, DeterministicPhysicsCallbackMask3D, DeterministicPhysicsCompoundChild3D, DeterministicPhysicsCompoundChildShape3D, DeterministicPhysicsConstraint3D, DeterministicPhysicsContactDetail3D, DeterministicPhysicsContactEvent3D, DeterministicPhysicsDetailedHit3D, DeterministicPhysicsForceApplication3D, DeterministicPhysicsHit3D, DeterministicPhysicsHullShape3D, DeterministicPhysicsImpulseApplication3D, DeterministicPhysicsOverlapQuery3D, DeterministicPhysicsPrimitiveShape3D, DeterministicPhysicsQuaternion3D, DeterministicPhysicsQueryOptions3D, DeterministicPhysicsRaycastQuery3D, DeterministicPhysicsScheduledQuery3D, DeterministicPhysicsShape3D, DeterministicPhysicsShapeCastQuery3D, DeterministicPhysicsStepOptions3D, DeterministicPhysicsStepResult3D, DeterministicPhysicsVec3, DeterministicPhysicsWorld3D, DeterministicPhysicsWorldEdit3D, } from './physics3d.js';
|
|
22
|
+
export type { DeterministicVoxelChunk3D, DeterministicVoxelCompoundShape3D, DeterministicVoxelCompoundSplitResult3D, DeterministicVoxelRayHit3D, SplitDeterministicVoxelChunkOptions3D, VoxelAnchorFace, VoxelBoxCarveRegion3D, VoxelCapsuleCarveRegion3D, VoxelCarveRegion3D, VoxelOccupancy3D, VoxelSphereCarveRegion3D, VoxelSubChunk3D, } from './physics3d-voxel.js';
|
|
23
23
|
export type { PhysicsWorldDebugMesh, PhysicsWorldDebugMeshOptions } from './debug-wireframe.js';
|
|
24
24
|
export type { DeterministicPhysicsJoint3D } from './physics3d-joints.js';
|
|
25
25
|
export type { DeterministicVehicle3D, DeterministicVehicleImpulse3D, DeterministicVehicleInput3D, DeterministicVehicleStepOptions3D, DeterministicVehicleStepResult3D, DeterministicVehicleWheel3D, DeterministicVehicleWheelTelemetry3D, } from './physics3d-vehicle.js';
|
package/dist/creator.js
CHANGED
|
@@ -10,7 +10,7 @@ export { runSyncplaySynctest } from './synctest.js';
|
|
|
10
10
|
// cooking. Cosmetic physics, KCC (movement3d), and the destruction-cert runner
|
|
11
11
|
// stay off it — the first two are not requested, the third reads wall clock.
|
|
12
12
|
export { applyDeterministicForces3D, applyDeterministicImpulse3D, applyDeterministicImpulses3D, applyDeterministicWorldEdit3D, contactDetailsDeterministicPhysics3D, createBoxShapeFromExtents, createBoxShapeFromMinMax, createCapsuleShapeFromBase, createDeterministicPhysicsWorld3D, deriveInverseInertia, deterministicPhysicsBodyById3D, deterministicPhysicsCallback3D, overlapDeterministicPhysics3D, raycastDeterministicPhysics3D, raycastDeterministicPhysics3DDetailed, runDeterministicPhysics3DStress, setDeterministicBodyVelocity3D, setDeterministicKinematicPoses3D, setDeterministicKinematicTransforms3D, shapeCastDeterministicPhysics3D, shapeCastDeterministicPhysics3DDetailed, stepDeterministicPhysicsWorld3D, } from './physics3d.js';
|
|
13
|
-
export { carveDeterministicVoxelChunk3D, cookDeterministicVoxelChunkCollider3D, cookDeterministicVoxelSubregion3D, recookDeterministicVoxelSubregion3D, raycastDeterministicVoxelChunk3D, splitDeterministicVoxelChunk3D, } from './physics3d-voxel.js';
|
|
13
|
+
export { carveDeterministicVoxelChunk3D, cookDeterministicVoxelChunkCollider3D, cookDeterministicVoxelSubregion3D, recookDeterministicVoxelSubregion3D, raycastDeterministicVoxelChunk3D, splitDeterministicVoxelChunk3D, splitDeterministicVoxelCompoundCollider3D, } from './physics3d-voxel.js';
|
|
14
14
|
export { generatePhysicsWorldDebugMesh } from './debug-wireframe.js';
|
|
15
15
|
export { cylinderHullVertices } from './physics3d-hull.js';
|
|
16
16
|
export { stepDeterministicVehicle3D } from './physics3d-vehicle.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export { createSyncplayRunner } from './runner.js';
|
|
|
28
28
|
export { fbm2D, hash2, hashUint32, valueNoise1D, valueNoise2D } from './noise.js';
|
|
29
29
|
export { circleCastDeterministicPhysics2D, createDeterministicPhysicsWorld2D, nearestDeterministicPhysicsHit2D, queryDeterministicPhysicsAabb2D, queryDeterministicPhysicsShapeOverlap2D, raycastAllDeterministicPhysics2D, raycastDeterministicPhysics2D, stepDeterministicPhysicsWorld2D } from './physics2d.js';
|
|
30
30
|
export { applyDeterministicForces3D, applyDeterministicImpulse3D, applyDeterministicImpulses3D, applyDeterministicWorldEdit3D, contactDetailsDeterministicPhysics3D, createBoxShapeFromExtents, createBoxShapeFromMinMax, createCapsuleShapeFromBase, createDeterministicPhysicsWorld3D, createTrustedDeterministicPhysicsWorld3D, deriveInverseInertia, deterministicPhysicsBodyById3D, deterministicPhysicsCallback3D, overlapDeterministicPhysics3D, raycastDeterministicPhysics3D, raycastDeterministicPhysics3DDetailed, runDeterministicPhysics3DStress, setDeterministicBodyVelocity3D, setDeterministicKinematicPoses3D, setDeterministicKinematicTransforms3D, shapeCastDeterministicPhysics3D, shapeCastDeterministicPhysics3DDetailed, stepDeterministicPhysicsWorld3D } from './physics3d.js';
|
|
31
|
-
export { carveDeterministicVoxelChunk3D, cookDeterministicVoxelChunkCollider3D, cookDeterministicVoxelSubregion3D, recookDeterministicVoxelSubregion3D, raycastDeterministicVoxelChunk3D, splitDeterministicVoxelChunk3D } from './physics3d-voxel.js';
|
|
31
|
+
export { carveDeterministicVoxelChunk3D, cookDeterministicVoxelChunkCollider3D, cookDeterministicVoxelSubregion3D, recookDeterministicVoxelSubregion3D, raycastDeterministicVoxelChunk3D, splitDeterministicVoxelChunk3D, splitDeterministicVoxelCompoundCollider3D } from './physics3d-voxel.js';
|
|
32
32
|
export { generatePhysicsWorldDebugMesh } from './debug-wireframe.js';
|
|
33
33
|
export { cylinderHullVertices } from './physics3d-hull.js';
|
|
34
34
|
export { runDeterministicPhysics3DDestructionCert } from './physics3d-destruction-cert.js';
|
|
@@ -78,8 +78,8 @@ export type { CookedDeterministicNavmesh, DeterministicNavmeshAgent, Determinist
|
|
|
78
78
|
export type { ConfirmedSyncplayPresentationFrame, KinetixRuntimeFactory, NetworkedClientTransport, NetworkedSyncplayClient, NetworkedSyncplayClientInputDelayOptions, NetworkedSyncplayClientNetStats, NetworkedSyncplayClientOptions, NetworkedSyncplayClientPacingOptions, NetworkedSyncplayPreparationOptions, NetworkedSyncplaySessionDescriptor, PreparedNetworkedSyncplayTransport, SyncplayPredictionMode, SyncplayRemoteInputPrediction } from './networked-client.js';
|
|
79
79
|
export type { SyncplayRunner, SyncplayRunnerConfig, SyncplayRunnerConnectionEvent, SyncplayRunnerOccupancy, SyncplayRunnerOfflineOptions, SyncplayRunnerPresentation, SyncplayRunnerSnapshot, SyncplayRunnerStatus, SyncplayRunnerTransport } from './runner.js';
|
|
80
80
|
export type { DeterministicBodyKind, DeterministicContactEvent2D, DeterministicContactEventType, DeterministicPhysicsAabbQuery2D, DeterministicPhysicsBody2D, DeterministicPhysicsCircleCastQuery2D, DeterministicPhysicsConstraint2D, DeterministicPhysicsHit2D, DeterministicPhysicsQueryOptions2D, DeterministicPhysicsRaycastQuery2D, DeterministicPhysicsShape2D, DeterministicPhysicsShapeOverlapQuery2D, DeterministicPhysicsStepOptions2D, DeterministicPhysicsStepResult2D, DeterministicPhysicsWorld2D } from './physics2d.js';
|
|
81
|
-
export type { DeterministicContactCacheEntry3D, DeterministicJointCacheEntry3D, DeterministicKinematicPose3D, DeterministicKinematicTransformBuffer3D, DeterministicPhysicsActivePair3D, DeterministicPhysicsAxisLock3D, DeterministicPhysicsBody3D, DeterministicPhysicsCallbackMask3D, DeterministicPhysicsCompoundChild3D, DeterministicPhysicsCompoundChildShape3D, DeterministicPhysicsConstraint3D, DeterministicPhysicsContactDetail3D, DeterministicPhysicsContactEvent3D, DeterministicPhysicsDetailedHit3D, DeterministicPhysicsForceApplication3D, DeterministicPhysicsHit3D, DeterministicPhysicsHullShape3D, DeterministicPhysicsImpulseApplication3D, DeterministicPhysicsOverlapQuery3D, DeterministicPhysicsPrimitiveShape3D, DeterministicPhysicsQuaternion3D, DeterministicPhysicsQueryOptions3D, DeterministicPhysicsRaycastQuery3D, DeterministicPhysicsScheduledQuery3D, DeterministicPhysicsShape3D, DeterministicPhysicsShapeCastQuery3D, DeterministicPhysicsStepOptions3D, DeterministicPhysicsStepResult3D, DeterministicPhysicsVec3, DeterministicPhysicsWorld3D, DeterministicPhysicsWorldEdit3D } from './physics3d.js';
|
|
82
|
-
export type { DeterministicVoxelChunk3D, DeterministicVoxelCompoundShape3D, DeterministicVoxelRayHit3D, SplitDeterministicVoxelChunkOptions3D, VoxelAnchorFace, VoxelBoxCarveRegion3D, VoxelCapsuleCarveRegion3D, VoxelCarveRegion3D, VoxelOccupancy3D, VoxelSphereCarveRegion3D, VoxelSubChunk3D } from './physics3d-voxel.js';
|
|
81
|
+
export type { DeterministicContactCacheEntry3D, DeterministicFluidVolume3D, DeterministicJointCacheEntry3D, DeterministicKinematicPose3D, DeterministicKinematicTransformBuffer3D, DeterministicPhysicsAabb3D, DeterministicPhysicsActivePair3D, DeterministicPhysicsAxisLock3D, DeterministicPhysicsBody3D, DeterministicPhysicsCallbackMask3D, DeterministicPhysicsCompoundChild3D, DeterministicPhysicsCompoundChildShape3D, DeterministicPhysicsConstraint3D, DeterministicPhysicsContactDetail3D, DeterministicPhysicsContactEvent3D, DeterministicPhysicsDetailedHit3D, DeterministicPhysicsForceApplication3D, DeterministicPhysicsHit3D, DeterministicPhysicsHullShape3D, DeterministicPhysicsImpulseApplication3D, DeterministicPhysicsOverlapQuery3D, DeterministicPhysicsPrimitiveShape3D, DeterministicPhysicsQuaternion3D, DeterministicPhysicsQueryOptions3D, DeterministicPhysicsRaycastQuery3D, DeterministicPhysicsScheduledQuery3D, DeterministicPhysicsShape3D, DeterministicPhysicsShapeCastQuery3D, DeterministicPhysicsStepOptions3D, DeterministicPhysicsStepResult3D, DeterministicPhysicsVec3, DeterministicPhysicsWorld3D, DeterministicPhysicsWorldEdit3D } from './physics3d.js';
|
|
82
|
+
export type { DeterministicVoxelChunk3D, DeterministicVoxelCompoundShape3D, DeterministicVoxelCompoundSplitResult3D, DeterministicVoxelRayHit3D, SplitDeterministicVoxelChunkOptions3D, VoxelAnchorFace, VoxelBoxCarveRegion3D, VoxelCapsuleCarveRegion3D, VoxelCarveRegion3D, VoxelOccupancy3D, VoxelSphereCarveRegion3D, VoxelSubChunk3D } from './physics3d-voxel.js';
|
|
83
83
|
export type { PhysicsWorldDebugMesh, PhysicsWorldDebugMeshOptions } from './debug-wireframe.js';
|
|
84
84
|
export type { DeterministicDestructionCertOptions, DeterministicDestructionCertResult } from './physics3d-destruction-cert.js';
|
|
85
85
|
export type { DeterministicAuthoritativeBodyProxy3D, DeterministicCosmeticPhysicsBody3D, DeterministicCosmeticPhysicsStepOptions3D, DeterministicCosmeticPhysicsStepResult3D, DeterministicCosmeticPhysicsWorld3D } from './cosmetic-physics3d.js';
|
package/dist/index.js
CHANGED
|
@@ -29,7 +29,7 @@ export { createSyncplayRunner } from './runner.js';
|
|
|
29
29
|
export { fbm2D, hash2, hashUint32, valueNoise1D, valueNoise2D } from './noise.js';
|
|
30
30
|
export { circleCastDeterministicPhysics2D, createDeterministicPhysicsWorld2D, nearestDeterministicPhysicsHit2D, queryDeterministicPhysicsAabb2D, queryDeterministicPhysicsShapeOverlap2D, raycastAllDeterministicPhysics2D, raycastDeterministicPhysics2D, stepDeterministicPhysicsWorld2D } from './physics2d.js';
|
|
31
31
|
export { applyDeterministicForces3D, applyDeterministicImpulse3D, applyDeterministicImpulses3D, applyDeterministicWorldEdit3D, contactDetailsDeterministicPhysics3D, createBoxShapeFromExtents, createBoxShapeFromMinMax, createCapsuleShapeFromBase, createDeterministicPhysicsWorld3D, createTrustedDeterministicPhysicsWorld3D, deriveInverseInertia, deterministicPhysicsBodyById3D, deterministicPhysicsCallback3D, overlapDeterministicPhysics3D, raycastDeterministicPhysics3D, raycastDeterministicPhysics3DDetailed, runDeterministicPhysics3DStress, setDeterministicBodyVelocity3D, setDeterministicKinematicPoses3D, setDeterministicKinematicTransforms3D, shapeCastDeterministicPhysics3D, shapeCastDeterministicPhysics3DDetailed, stepDeterministicPhysicsWorld3D } from './physics3d.js';
|
|
32
|
-
export { carveDeterministicVoxelChunk3D, cookDeterministicVoxelChunkCollider3D, cookDeterministicVoxelSubregion3D, recookDeterministicVoxelSubregion3D, raycastDeterministicVoxelChunk3D, splitDeterministicVoxelChunk3D } from './physics3d-voxel.js';
|
|
32
|
+
export { carveDeterministicVoxelChunk3D, cookDeterministicVoxelChunkCollider3D, cookDeterministicVoxelSubregion3D, recookDeterministicVoxelSubregion3D, raycastDeterministicVoxelChunk3D, splitDeterministicVoxelChunk3D, splitDeterministicVoxelCompoundCollider3D } from './physics3d-voxel.js';
|
|
33
33
|
export { generatePhysicsWorldDebugMesh } from './debug-wireframe.js';
|
|
34
34
|
export { cylinderHullVertices } from './physics3d-hull.js';
|
|
35
35
|
export { runDeterministicPhysics3DDestructionCert } from './physics3d-destruction-cert.js';
|
|
@@ -101,9 +101,13 @@ export type DeterministicPhysicsJoint3D = {
|
|
|
101
101
|
readonly targetZ: number;
|
|
102
102
|
readonly maxForce: number;
|
|
103
103
|
readonly damping?: number;
|
|
104
|
+
readonly linearHertz?: number;
|
|
105
|
+
readonly linearDampingRatio?: number;
|
|
104
106
|
readonly targetRotation?: Quat3D;
|
|
105
107
|
readonly maxTorque?: number;
|
|
106
108
|
readonly angularDamping?: number;
|
|
109
|
+
readonly angularHertz?: number;
|
|
110
|
+
readonly angularDampingRatio?: number;
|
|
107
111
|
readonly breakDistance?: number;
|
|
108
112
|
readonly breakImpulse?: number;
|
|
109
113
|
};
|
package/dist/physics3d-joints.js
CHANGED
|
@@ -626,6 +626,29 @@ function springJoint(joint, aIndex, bIndex, warm) {
|
|
|
626
626
|
},
|
|
627
627
|
};
|
|
628
628
|
}
|
|
629
|
+
/**
|
|
630
|
+
* Box3D / Box2D v3 b3MakeSoft coefficient scheme:
|
|
631
|
+
* Translates (frequencyHz, dampingRatio, dt) into mass-independent constraint softness coefficients:
|
|
632
|
+
* biasRate = omega / a1, massScale = a2 / (1 + a2), impulseScale = 1 / (1 + a2).
|
|
633
|
+
* Unconditionally stable: biasRate * dt = (dt * omega) / (2 * damping + dt * omega) <= 1.0 always.
|
|
634
|
+
*/
|
|
635
|
+
function makeSoft(hertz, dampingRatio, dt) {
|
|
636
|
+
if (hertz <= 0) {
|
|
637
|
+
return { biasRate: 0, massScale: 0, impulseScale: 0 };
|
|
638
|
+
}
|
|
639
|
+
const omega = TWO_PI * hertz;
|
|
640
|
+
const a1 = 2 * Math.max(0, dampingRatio) + dt * omega;
|
|
641
|
+
if (a1 <= 1e-18) {
|
|
642
|
+
return { biasRate: 0, massScale: 0, impulseScale: 0 };
|
|
643
|
+
}
|
|
644
|
+
const a2 = dt * omega * a1;
|
|
645
|
+
const a3 = 1 / (1 + a2);
|
|
646
|
+
return {
|
|
647
|
+
biasRate: omega / a1,
|
|
648
|
+
massScale: a2 * a3,
|
|
649
|
+
impulseScale: a3,
|
|
650
|
+
};
|
|
651
|
+
}
|
|
629
652
|
function grabJoint(joint, bodyIndex, warm) {
|
|
630
653
|
const state = {
|
|
631
654
|
impulse: warm ? { x: warm.impulseX, y: warm.impulseY, z: warm.impulseZ } : { x: 0, y: 0, z: 0 },
|
|
@@ -636,13 +659,20 @@ function grabJoint(joint, bodyIndex, warm) {
|
|
|
636
659
|
};
|
|
637
660
|
let r = { x: 0, y: 0, z: 0 };
|
|
638
661
|
let kInv = [0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
639
|
-
let desiredVel = { x: 0, y: 0, z: 0 };
|
|
640
662
|
const target = { x: joint.targetX, y: joint.targetY, z: joint.targetZ };
|
|
641
663
|
const maxImpulse = joint.maxForce * 1;
|
|
642
664
|
const targetRotation = joint.targetRotation !== undefined ? normalizeQuat(joint.targetRotation) : undefined;
|
|
643
665
|
const maxTorque = joint.maxTorque ?? 0;
|
|
644
|
-
const
|
|
645
|
-
|
|
666
|
+
const linearHertz = joint.linearHertz ?? 5.0;
|
|
667
|
+
const linearDampingRatio = joint.linearDampingRatio ?? joint.damping ?? 1.0;
|
|
668
|
+
const angularHertz = joint.angularHertz ?? 5.0;
|
|
669
|
+
const angularDampingRatio = joint.angularDampingRatio ?? joint.angularDamping ?? joint.damping ?? 1.0;
|
|
670
|
+
let linBiasRate = 0;
|
|
671
|
+
let linMassScale = 1;
|
|
672
|
+
let linImpulseScale = 0;
|
|
673
|
+
let angBiasVel = { x: 0, y: 0, z: 0 };
|
|
674
|
+
let angMassScale = 1;
|
|
675
|
+
let angImpulseScale = 0;
|
|
646
676
|
let angMassMat;
|
|
647
677
|
let angMassDiag;
|
|
648
678
|
let broken = false;
|
|
@@ -671,10 +701,17 @@ function grabJoint(joint, bodyIndex, warm) {
|
|
|
671
701
|
const skewR = skewMat3(r);
|
|
672
702
|
const ang = mat3Multiply(mat3Multiply(skewR, ctx.invInertia[bodyIndex]), skewR);
|
|
673
703
|
kInv = invertMat3(mat3Sub(linear, ang));
|
|
674
|
-
const
|
|
675
|
-
|
|
704
|
+
const linSoft = (joint.linearHertz !== undefined || joint.linearDampingRatio !== undefined)
|
|
705
|
+
? makeSoft(linearHertz, linearDampingRatio, ctx.dt)
|
|
706
|
+
: undefined;
|
|
707
|
+
linBiasRate = linSoft ? linSoft.biasRate : (joint.damping ?? 1) / ctx.dt;
|
|
708
|
+
linMassScale = linSoft ? linSoft.massScale : 1.0;
|
|
709
|
+
linImpulseScale = linSoft ? linSoft.impulseScale : 0;
|
|
676
710
|
ctx.applyToBody(bodyIndex, r, state.impulse);
|
|
677
711
|
if (targetRotation !== undefined) {
|
|
712
|
+
const angSoft = makeSoft(angularHertz, angularDampingRatio, ctx.dt);
|
|
713
|
+
angMassScale = angSoft.massScale;
|
|
714
|
+
angImpulseScale = angSoft.impulseScale;
|
|
678
715
|
const errorRotation = quatMultiply(quatConjugate(targetRotation), body.q);
|
|
679
716
|
const sign = errorRotation.w < 0 ? -1 : 1;
|
|
680
717
|
const error = {
|
|
@@ -682,7 +719,8 @@ function grabJoint(joint, bodyIndex, warm) {
|
|
|
682
719
|
y: 2 * sign * errorRotation.y,
|
|
683
720
|
z: 2 * sign * errorRotation.z,
|
|
684
721
|
};
|
|
685
|
-
|
|
722
|
+
// Box3D soft constraint bias rate: biasRate * dt <= 1.0 always, preventing single-step overshoot
|
|
723
|
+
angBiasVel = clampMagnitude(scaleVec3(error, -angSoft.biasRate), 10.0);
|
|
686
724
|
const invI = ctx.invInertia[bodyIndex];
|
|
687
725
|
const fullInv = invertMat3(invI);
|
|
688
726
|
const isSingular = fullInv[0] === 0 && fullInv[4] === 0 && fullInv[8] === 0;
|
|
@@ -705,22 +743,34 @@ function grabJoint(joint, bodyIndex, warm) {
|
|
|
705
743
|
return;
|
|
706
744
|
}
|
|
707
745
|
const body = ctx.bodies[bodyIndex];
|
|
746
|
+
const worldAnchor = addVec3(body.c, r);
|
|
747
|
+
const posError = subVec3(target, worldAnchor);
|
|
748
|
+
const desiredVel = scaleVec3(posError, linBiasRate);
|
|
708
749
|
const currentVel = addVec3(body.v, crossVec3(body.w, r));
|
|
709
|
-
const
|
|
750
|
+
const deltaV = subVec3(desiredVel, currentVel);
|
|
751
|
+
const rawImpulse = mulMat3Vec(kInv, deltaV);
|
|
752
|
+
const dImpulse = subVec3(scaleVec3(rawImpulse, linMassScale), scaleVec3(state.impulse, linImpulseScale));
|
|
710
753
|
const target2 = addVec3(state.impulse, dImpulse);
|
|
711
754
|
const clamped = clampMagnitude(target2, maxImpulse * ctx.dt);
|
|
712
755
|
const applied = subVec3(clamped, state.impulse);
|
|
713
756
|
state.impulse = clamped;
|
|
714
757
|
ctx.applyToBody(bodyIndex, r, applied);
|
|
715
758
|
if (targetRotation !== undefined && maxTorque > 0) {
|
|
716
|
-
const deltaW = subVec3(
|
|
717
|
-
const
|
|
759
|
+
const deltaW = subVec3(angBiasVel, body.w);
|
|
760
|
+
const rawTorque = angMassMat !== undefined
|
|
718
761
|
? mulMat3Vec(angMassMat, deltaW)
|
|
719
762
|
: { x: deltaW.x * angMassDiag.x, y: deltaW.y * angMassDiag.y, z: deltaW.z * angMassDiag.z };
|
|
763
|
+
const dTorque = subVec3(scaleVec3(rawTorque, angMassScale), scaleVec3(torqueImpulse, angImpulseScale));
|
|
720
764
|
const targetTorque = addVec3(torqueImpulse, dTorque);
|
|
721
765
|
const clampedTorque = clampMagnitude(targetTorque, maxTorque * ctx.dt);
|
|
722
|
-
|
|
723
|
-
|
|
766
|
+
let appliedTorque = subVec3(clampedTorque, torqueImpulse);
|
|
767
|
+
// Safeguard angular acceleration: clamp appliedTorque so Delta omega <= 0.5 rad/substep
|
|
768
|
+
const dw = mulMat3Vec(ctx.invInertia[bodyIndex], appliedTorque);
|
|
769
|
+
const dwLen = solverSqrt(dotVec3(dw, dw));
|
|
770
|
+
if (dwLen > 0.5) {
|
|
771
|
+
appliedTorque = scaleVec3(appliedTorque, 0.5 / dwLen);
|
|
772
|
+
}
|
|
773
|
+
torqueImpulse = addVec3(torqueImpulse, appliedTorque);
|
|
724
774
|
ctx.applyAngularToBody(bodyIndex, appliedTorque);
|
|
725
775
|
}
|
|
726
776
|
},
|
|
@@ -766,6 +816,12 @@ function validateJoint(joint) {
|
|
|
766
816
|
if (joint.damping !== undefined && (!Number.isFinite(joint.damping) || joint.damping < 0)) {
|
|
767
817
|
throw new Error(`physics3d joint ${joint.id}: damping must be non-negative`);
|
|
768
818
|
}
|
|
819
|
+
if (joint.linearHertz !== undefined && (!Number.isFinite(joint.linearHertz) || joint.linearHertz <= 0)) {
|
|
820
|
+
throw new Error(`physics3d joint ${joint.id}: linearHertz must be positive`);
|
|
821
|
+
}
|
|
822
|
+
if (joint.linearDampingRatio !== undefined && (!Number.isFinite(joint.linearDampingRatio) || joint.linearDampingRatio < 0)) {
|
|
823
|
+
throw new Error(`physics3d joint ${joint.id}: linearDampingRatio must be non-negative`);
|
|
824
|
+
}
|
|
769
825
|
if (joint.targetRotation !== undefined) {
|
|
770
826
|
const target = joint.targetRotation;
|
|
771
827
|
if (!Number.isFinite(target.x) || !Number.isFinite(target.y) || !Number.isFinite(target.z) || !Number.isFinite(target.w)
|
|
@@ -784,6 +840,12 @@ function validateJoint(joint) {
|
|
|
784
840
|
if (joint.angularDamping !== undefined && (!Number.isFinite(joint.angularDamping) || joint.angularDamping < 0)) {
|
|
785
841
|
throw new Error(`physics3d joint ${joint.id}: angularDamping must be non-negative`);
|
|
786
842
|
}
|
|
843
|
+
if (joint.angularHertz !== undefined && (!Number.isFinite(joint.angularHertz) || joint.angularHertz <= 0)) {
|
|
844
|
+
throw new Error(`physics3d joint ${joint.id}: angularHertz must be positive`);
|
|
845
|
+
}
|
|
846
|
+
if (joint.angularDampingRatio !== undefined && (!Number.isFinite(joint.angularDampingRatio) || joint.angularDampingRatio < 0)) {
|
|
847
|
+
throw new Error(`physics3d joint ${joint.id}: angularDampingRatio must be non-negative`);
|
|
848
|
+
}
|
|
787
849
|
if (joint.breakDistance !== undefined && (!Number.isFinite(joint.breakDistance) || joint.breakDistance <= 0)) {
|
|
788
850
|
throw new Error(`physics3d joint ${joint.id}: breakDistance must be positive`);
|
|
789
851
|
}
|
package/dist/physics3d-shared.js
CHANGED
|
@@ -141,6 +141,9 @@ export function worldInvInertia(rot, invI) {
|
|
|
141
141
|
* identity so no NaN reaches state.
|
|
142
142
|
*/
|
|
143
143
|
export function integrateQuat(q, w, dt) {
|
|
144
|
+
if (!Number.isFinite(dt) || dt <= 0 || !Number.isFinite(w.x) || !Number.isFinite(w.y) || !Number.isFinite(w.z)) {
|
|
145
|
+
return normalizeQuat(q);
|
|
146
|
+
}
|
|
144
147
|
const hx = w.x * 0.5 * dt;
|
|
145
148
|
const hy = w.y * 0.5 * dt;
|
|
146
149
|
const hz = w.z * 0.5 * dt;
|
|
@@ -148,18 +151,34 @@ export function integrateQuat(q, w, dt) {
|
|
|
148
151
|
const ny = q.y + (hy * q.w + hz * q.x - hx * q.z);
|
|
149
152
|
const nz = q.z + (hz * q.w + hx * q.y - hy * q.x);
|
|
150
153
|
const nw = q.w + (-hx * q.x - hy * q.y - hz * q.z);
|
|
151
|
-
const
|
|
152
|
-
if (
|
|
153
|
-
return
|
|
154
|
+
const maxComp = Math.max(Math.abs(nx), Math.abs(ny), Math.abs(nz), Math.abs(nw));
|
|
155
|
+
if (!Number.isFinite(maxComp) || maxComp === 0) {
|
|
156
|
+
return normalizeQuat(q);
|
|
157
|
+
}
|
|
158
|
+
const sx = nx / maxComp;
|
|
159
|
+
const sy = ny / maxComp;
|
|
160
|
+
const sz = nz / maxComp;
|
|
161
|
+
const sw = nw / maxComp;
|
|
162
|
+
const length = solverSqrt(sx * sx + sy * sy + sz * sz + sw * sw);
|
|
163
|
+
if (!Number.isFinite(length) || length === 0) {
|
|
164
|
+
return normalizeQuat(q);
|
|
154
165
|
}
|
|
155
|
-
return { x:
|
|
166
|
+
return { x: sx / length, y: sy / length, z: sz / length, w: sw / length };
|
|
156
167
|
}
|
|
157
168
|
export function normalizeQuat(q) {
|
|
158
|
-
const
|
|
159
|
-
if (
|
|
169
|
+
const maxComp = Math.max(Math.abs(q.x), Math.abs(q.y), Math.abs(q.z), Math.abs(q.w));
|
|
170
|
+
if (!Number.isFinite(maxComp) || maxComp === 0) {
|
|
171
|
+
return { x: 0, y: 0, z: 0, w: 1 };
|
|
172
|
+
}
|
|
173
|
+
const sx = q.x / maxComp;
|
|
174
|
+
const sy = q.y / maxComp;
|
|
175
|
+
const sz = q.z / maxComp;
|
|
176
|
+
const sw = q.w / maxComp;
|
|
177
|
+
const length = solverSqrt(sx * sx + sy * sy + sz * sz + sw * sw);
|
|
178
|
+
if (!Number.isFinite(length) || length === 0) {
|
|
160
179
|
return { x: 0, y: 0, z: 0, w: 1 };
|
|
161
180
|
}
|
|
162
|
-
return { x:
|
|
181
|
+
return { x: sx / length, y: sy / length, z: sz / length, w: sw / length };
|
|
163
182
|
}
|
|
164
183
|
export function quatConjugate(q) {
|
|
165
184
|
return { x: -q.x, y: -q.y, z: -q.z, w: q.w };
|
|
@@ -249,6 +249,24 @@ export interface SolverWarmPoint {
|
|
|
249
249
|
readonly tangentImpulse1: number;
|
|
250
250
|
readonly tangentImpulse2: number;
|
|
251
251
|
}
|
|
252
|
+
export interface DeterministicPhysicsAabb3D {
|
|
253
|
+
readonly minX: number;
|
|
254
|
+
readonly minY: number;
|
|
255
|
+
readonly minZ: number;
|
|
256
|
+
readonly maxX: number;
|
|
257
|
+
readonly maxY: number;
|
|
258
|
+
readonly maxZ: number;
|
|
259
|
+
}
|
|
260
|
+
export interface DeterministicFluidVolume3D {
|
|
261
|
+
readonly id: string;
|
|
262
|
+
readonly bounds: DeterministicPhysicsAabb3D;
|
|
263
|
+
readonly density?: number;
|
|
264
|
+
readonly linearDrag?: number;
|
|
265
|
+
readonly angularDrag?: number;
|
|
266
|
+
readonly flowVelocity?: Point3D;
|
|
267
|
+
readonly layer?: number;
|
|
268
|
+
readonly mask?: number;
|
|
269
|
+
}
|
|
252
270
|
export interface SolverStepOptions {
|
|
253
271
|
readonly dt: number;
|
|
254
272
|
readonly gravityY: number;
|
|
@@ -262,6 +280,7 @@ export interface SolverStepOptions {
|
|
|
262
280
|
readonly joints?: readonly SolverJointSolve[];
|
|
263
281
|
/** Packed index pairs (min * WARM_KEY_BASE + max) whose contacts are suppressed (jointed pairs). */
|
|
264
282
|
readonly noCollidePairs?: ReadonlySet<number>;
|
|
283
|
+
readonly fluids?: readonly DeterministicFluidVolume3D[];
|
|
265
284
|
}
|
|
266
285
|
export declare function combinedContactFriction(frictionA10: number, frictionB10: number): number;
|
|
267
286
|
export interface SolverContactImpulse {
|
package/dist/physics3d-solver.js
CHANGED
|
@@ -1435,6 +1435,286 @@ function takeConstraint() {
|
|
|
1435
1435
|
constraintPool.high += 1;
|
|
1436
1436
|
return slot;
|
|
1437
1437
|
}
|
|
1438
|
+
function computeSubmergence(b, bounds) {
|
|
1439
|
+
let points = [];
|
|
1440
|
+
let volume = 0;
|
|
1441
|
+
let yMin = b.p.y;
|
|
1442
|
+
let yMax = b.p.y;
|
|
1443
|
+
let xMin = b.p.x;
|
|
1444
|
+
let xMax = b.p.x;
|
|
1445
|
+
let zMin = b.p.z;
|
|
1446
|
+
let zMax = b.p.z;
|
|
1447
|
+
const shape = b.shape;
|
|
1448
|
+
if (shape.kind === 'box') {
|
|
1449
|
+
const h = shape.half;
|
|
1450
|
+
volume = 8 * h.x * h.y * h.z;
|
|
1451
|
+
const corners = [
|
|
1452
|
+
{ x: -h.x, y: -h.y, z: -h.z },
|
|
1453
|
+
{ x: h.x, y: -h.y, z: -h.z },
|
|
1454
|
+
{ x: -h.x, y: h.y, z: -h.z },
|
|
1455
|
+
{ x: h.x, y: h.y, z: -h.z },
|
|
1456
|
+
{ x: -h.x, y: -h.y, z: h.z },
|
|
1457
|
+
{ x: h.x, y: -h.y, z: h.z },
|
|
1458
|
+
{ x: -h.x, y: h.y, z: h.z },
|
|
1459
|
+
{ x: h.x, y: h.y, z: h.z },
|
|
1460
|
+
];
|
|
1461
|
+
points = corners.map((c) => addVec3(b.p, rotatePointByQuat(b.q, c)));
|
|
1462
|
+
xMin = points[0].x;
|
|
1463
|
+
xMax = points[0].x;
|
|
1464
|
+
yMin = points[0].y;
|
|
1465
|
+
yMax = points[0].y;
|
|
1466
|
+
zMin = points[0].z;
|
|
1467
|
+
zMax = points[0].z;
|
|
1468
|
+
for (let i = 1; i < points.length; i += 1) {
|
|
1469
|
+
const p = points[i];
|
|
1470
|
+
if (p.x < xMin)
|
|
1471
|
+
xMin = p.x;
|
|
1472
|
+
if (p.x > xMax)
|
|
1473
|
+
xMax = p.x;
|
|
1474
|
+
if (p.y < yMin)
|
|
1475
|
+
yMin = p.y;
|
|
1476
|
+
if (p.y > yMax)
|
|
1477
|
+
yMax = p.y;
|
|
1478
|
+
if (p.z < zMin)
|
|
1479
|
+
zMin = p.z;
|
|
1480
|
+
if (p.z > zMax)
|
|
1481
|
+
zMax = p.z;
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
else if (shape.kind === 'sphere') {
|
|
1485
|
+
const r = shape.radius;
|
|
1486
|
+
volume = (4 / 3) * Math.PI * r * r * r;
|
|
1487
|
+
xMin = b.p.x - r;
|
|
1488
|
+
xMax = b.p.x + r;
|
|
1489
|
+
yMin = b.p.y - r;
|
|
1490
|
+
yMax = b.p.y + r;
|
|
1491
|
+
zMin = b.p.z - r;
|
|
1492
|
+
zMax = b.p.z + r;
|
|
1493
|
+
points = [b.p];
|
|
1494
|
+
}
|
|
1495
|
+
else if (shape.kind === 'capsule') {
|
|
1496
|
+
const r = shape.radius;
|
|
1497
|
+
const hh = shape.halfHeight;
|
|
1498
|
+
volume = (4 / 3) * Math.PI * r * r * r + 2 * Math.PI * r * r * hh;
|
|
1499
|
+
const pTop = addVec3(b.p, rotatePointByQuat(b.q, { x: 0, y: hh, z: 0 }));
|
|
1500
|
+
const pBot = addVec3(b.p, rotatePointByQuat(b.q, { x: 0, y: -hh, z: 0 }));
|
|
1501
|
+
xMin = Math.min(pTop.x, pBot.x) - r;
|
|
1502
|
+
xMax = Math.max(pTop.x, pBot.x) + r;
|
|
1503
|
+
yMin = Math.min(pTop.y, pBot.y) - r;
|
|
1504
|
+
yMax = Math.max(pTop.y, pBot.y) + r;
|
|
1505
|
+
zMin = Math.min(pTop.z, pBot.z) - r;
|
|
1506
|
+
zMax = Math.max(pTop.z, pBot.z) + r;
|
|
1507
|
+
points = [pBot, pTop];
|
|
1508
|
+
}
|
|
1509
|
+
else if (shape.kind === 'hull') {
|
|
1510
|
+
const verts = shape.data.vertices;
|
|
1511
|
+
volume = 1.0;
|
|
1512
|
+
points = verts.map((v) => addVec3(b.p, rotatePointByQuat(b.q, v)));
|
|
1513
|
+
if (points.length > 0) {
|
|
1514
|
+
xMin = points[0].x;
|
|
1515
|
+
xMax = points[0].x;
|
|
1516
|
+
yMin = points[0].y;
|
|
1517
|
+
yMax = points[0].y;
|
|
1518
|
+
zMin = points[0].z;
|
|
1519
|
+
zMax = points[0].z;
|
|
1520
|
+
for (let i = 1; i < points.length; i += 1) {
|
|
1521
|
+
const p = points[i];
|
|
1522
|
+
if (p.x < xMin)
|
|
1523
|
+
xMin = p.x;
|
|
1524
|
+
if (p.x > xMax)
|
|
1525
|
+
xMax = p.x;
|
|
1526
|
+
if (p.y < yMin)
|
|
1527
|
+
yMin = p.y;
|
|
1528
|
+
if (p.y > yMax)
|
|
1529
|
+
yMax = p.y;
|
|
1530
|
+
if (p.z < zMin)
|
|
1531
|
+
zMin = p.z;
|
|
1532
|
+
if (p.z > zMax)
|
|
1533
|
+
zMax = p.z;
|
|
1534
|
+
}
|
|
1535
|
+
volume = Math.max(0.001, (xMax - xMin) * (yMax - yMin) * (zMax - zMin) * 0.5);
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
else if (shape.kind === 'compound') {
|
|
1539
|
+
volume = 0;
|
|
1540
|
+
for (const child of shape.children) {
|
|
1541
|
+
const childCenter = addVec3(b.p, rotatePointByQuat(b.q, child.offset));
|
|
1542
|
+
const childQ = quatMultiply(b.q, child.q);
|
|
1543
|
+
if (child.shape.kind === 'box') {
|
|
1544
|
+
const h = child.shape.half;
|
|
1545
|
+
volume += 8 * h.x * h.y * h.z;
|
|
1546
|
+
const corners = [
|
|
1547
|
+
{ x: -h.x, y: -h.y, z: -h.z },
|
|
1548
|
+
{ x: h.x, y: -h.y, z: -h.z },
|
|
1549
|
+
{ x: -h.x, y: h.y, z: -h.z },
|
|
1550
|
+
{ x: h.x, y: h.y, z: -h.z },
|
|
1551
|
+
{ x: -h.x, y: -h.y, z: h.z },
|
|
1552
|
+
{ x: h.x, y: -h.y, z: h.z },
|
|
1553
|
+
{ x: -h.x, y: h.y, z: h.z },
|
|
1554
|
+
{ x: h.x, y: h.y, z: h.z },
|
|
1555
|
+
];
|
|
1556
|
+
points.push(...corners.map((c) => addVec3(childCenter, rotatePointByQuat(childQ, c))));
|
|
1557
|
+
}
|
|
1558
|
+
else if (child.shape.kind === 'sphere') {
|
|
1559
|
+
const r = child.shape.radius;
|
|
1560
|
+
volume += (4 / 3) * Math.PI * r * r * r;
|
|
1561
|
+
points.push(childCenter, { x: childCenter.x - r, y: childCenter.y, z: childCenter.z }, { x: childCenter.x + r, y: childCenter.y, z: childCenter.z }, { x: childCenter.x, y: childCenter.y - r, z: childCenter.z }, { x: childCenter.x, y: childCenter.y + r, z: childCenter.z }, { x: childCenter.x, y: childCenter.y, z: childCenter.z - r }, { x: childCenter.x, y: childCenter.y, z: childCenter.z + r });
|
|
1562
|
+
}
|
|
1563
|
+
else if (child.shape.kind === 'capsule') {
|
|
1564
|
+
const r = child.shape.radius;
|
|
1565
|
+
const hh = child.shape.halfHeight;
|
|
1566
|
+
volume += (4 / 3) * Math.PI * r * r * r + 2 * Math.PI * r * r * hh;
|
|
1567
|
+
const capTop = addVec3(childCenter, rotatePointByQuat(childQ, { x: 0, y: hh, z: 0 }));
|
|
1568
|
+
const capBot = addVec3(childCenter, rotatePointByQuat(childQ, { x: 0, y: -hh, z: 0 }));
|
|
1569
|
+
points.push(capTop, capBot, { x: capTop.x - r, y: capTop.y, z: capTop.z }, { x: capTop.x + r, y: capTop.y, z: capTop.z }, { x: capTop.x, y: capTop.y - r, z: capTop.z }, { x: capTop.x, y: capTop.y + r, z: capTop.z }, { x: capTop.x, y: capTop.y, z: capTop.z - r }, { x: capTop.x, y: capTop.y, z: capTop.z + r }, { x: capBot.x - r, y: capBot.y, z: capBot.z }, { x: capBot.x + r, y: capBot.y, z: capBot.z }, { x: capBot.x, y: capBot.y - r, z: capBot.z }, { x: capBot.x, y: capBot.y + r, z: capBot.z }, { x: capBot.x, y: capBot.y, z: capBot.z - r }, { x: capBot.x, y: capBot.y, z: capBot.z + r });
|
|
1570
|
+
}
|
|
1571
|
+
else if (child.shape.kind === 'hull') {
|
|
1572
|
+
const verts = child.shape.data.vertices;
|
|
1573
|
+
const hullPoints = verts.map((v) => addVec3(childCenter, rotatePointByQuat(childQ, v)));
|
|
1574
|
+
points.push(...hullPoints);
|
|
1575
|
+
if (hullPoints.length > 0) {
|
|
1576
|
+
let hxMin = hullPoints[0].x;
|
|
1577
|
+
let hxMax = hullPoints[0].x;
|
|
1578
|
+
let hyMin = hullPoints[0].y;
|
|
1579
|
+
let hyMax = hullPoints[0].y;
|
|
1580
|
+
let hzMin = hullPoints[0].z;
|
|
1581
|
+
let hzMax = hullPoints[0].z;
|
|
1582
|
+
for (let i = 1; i < hullPoints.length; i += 1) {
|
|
1583
|
+
const p = hullPoints[i];
|
|
1584
|
+
if (p.x < hxMin)
|
|
1585
|
+
hxMin = p.x;
|
|
1586
|
+
if (p.x > hxMax)
|
|
1587
|
+
hxMax = p.x;
|
|
1588
|
+
if (p.y < hyMin)
|
|
1589
|
+
hyMin = p.y;
|
|
1590
|
+
if (p.y > hyMax)
|
|
1591
|
+
hyMax = p.y;
|
|
1592
|
+
if (p.z < hzMin)
|
|
1593
|
+
hzMin = p.z;
|
|
1594
|
+
if (p.z > hzMax)
|
|
1595
|
+
hzMax = p.z;
|
|
1596
|
+
}
|
|
1597
|
+
volume += Math.max(0.001, (hxMax - hxMin) * (hyMax - hyMin) * (hzMax - hzMin) * 0.5);
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
if (points.length > 0) {
|
|
1602
|
+
xMin = points[0].x;
|
|
1603
|
+
xMax = points[0].x;
|
|
1604
|
+
yMin = points[0].y;
|
|
1605
|
+
yMax = points[0].y;
|
|
1606
|
+
zMin = points[0].z;
|
|
1607
|
+
zMax = points[0].z;
|
|
1608
|
+
for (let i = 1; i < points.length; i += 1) {
|
|
1609
|
+
const p = points[i];
|
|
1610
|
+
if (p.x < xMin)
|
|
1611
|
+
xMin = p.x;
|
|
1612
|
+
if (p.x > xMax)
|
|
1613
|
+
xMax = p.x;
|
|
1614
|
+
if (p.y < yMin)
|
|
1615
|
+
yMin = p.y;
|
|
1616
|
+
if (p.y > yMax)
|
|
1617
|
+
yMax = p.y;
|
|
1618
|
+
if (p.z < zMin)
|
|
1619
|
+
zMin = p.z;
|
|
1620
|
+
if (p.z > zMax)
|
|
1621
|
+
zMax = p.z;
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
if (xMax < bounds.minX || xMin > bounds.maxX || zMax < bounds.minZ || zMin > bounds.maxZ) {
|
|
1626
|
+
return undefined;
|
|
1627
|
+
}
|
|
1628
|
+
if (yMax <= bounds.minY || yMin >= bounds.maxY) {
|
|
1629
|
+
return undefined;
|
|
1630
|
+
}
|
|
1631
|
+
const yBottom = Math.max(bounds.minY, yMin);
|
|
1632
|
+
const yTop = Math.min(bounds.maxY, yMax);
|
|
1633
|
+
const span = Math.max(1e-6, yMax - yMin);
|
|
1634
|
+
const fraction = Math.min(1.0, Math.max(0.0, (yTop - yBottom) / span));
|
|
1635
|
+
let cbX = b.c.x;
|
|
1636
|
+
let cbY = (yBottom + yTop) / 2;
|
|
1637
|
+
let cbZ = b.c.z;
|
|
1638
|
+
if (fraction >= 1.0) {
|
|
1639
|
+
// Fully submerged: center of buoyancy coincides with body centroid (no phantom righting torque)
|
|
1640
|
+
cbX = b.c.x;
|
|
1641
|
+
cbY = b.c.y;
|
|
1642
|
+
cbZ = b.c.z;
|
|
1643
|
+
}
|
|
1644
|
+
else {
|
|
1645
|
+
// Partially submerged: depth-weighted average of submerged sample points relative to fluid surface
|
|
1646
|
+
let sumWeight = 0;
|
|
1647
|
+
let sumX = 0;
|
|
1648
|
+
let sumZ = 0;
|
|
1649
|
+
const surfaceY = bounds.maxY;
|
|
1650
|
+
for (const p of points) {
|
|
1651
|
+
if (p.y < surfaceY) {
|
|
1652
|
+
const depth = surfaceY - p.y;
|
|
1653
|
+
sumWeight += depth;
|
|
1654
|
+
sumX += p.x * depth;
|
|
1655
|
+
sumZ += p.z * depth;
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
if (sumWeight > 1e-9) {
|
|
1659
|
+
cbX = sumX / sumWeight;
|
|
1660
|
+
cbZ = sumZ / sumWeight;
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
return {
|
|
1664
|
+
fraction,
|
|
1665
|
+
centerOfBuoyancy: { x: cbX, y: cbY, z: cbZ },
|
|
1666
|
+
displacedVolume: volume,
|
|
1667
|
+
};
|
|
1668
|
+
}
|
|
1669
|
+
function applyFluidForces(bodies, invInertia, fluids, gravityY, dt) {
|
|
1670
|
+
for (let index = 0; index < bodies.length; index += 1) {
|
|
1671
|
+
const b = bodies[index];
|
|
1672
|
+
if (!solid(b) || !b.isDynamic) {
|
|
1673
|
+
continue;
|
|
1674
|
+
}
|
|
1675
|
+
for (const fluid of fluids) {
|
|
1676
|
+
if (fluid.layer !== undefined && fluid.mask !== undefined) {
|
|
1677
|
+
if ((fluid.mask & b.layer) === 0 || (b.mask & fluid.layer) === 0) {
|
|
1678
|
+
continue;
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
const submergence = computeSubmergence(b, fluid.bounds);
|
|
1682
|
+
if (submergence === undefined || submergence.fraction <= 0) {
|
|
1683
|
+
continue;
|
|
1684
|
+
}
|
|
1685
|
+
const { fraction, centerOfBuoyancy, displacedVolume } = submergence;
|
|
1686
|
+
const fluidDensity = fluid.density ?? 1.0;
|
|
1687
|
+
const linearDragCoeff = fluid.linearDrag ?? 1.0;
|
|
1688
|
+
const angularDragCoeff = fluid.angularDrag ?? 0.5;
|
|
1689
|
+
const flowVel = fluid.flowVelocity ?? ZERO;
|
|
1690
|
+
const effG = gravityY * b.gravityScale;
|
|
1691
|
+
if (Math.abs(effG) > 0 && b.invMassVec.y > 0) {
|
|
1692
|
+
// Buoyant force opposes effective gravity
|
|
1693
|
+
const buoyantForceY = -effG * fluidDensity * displacedVolume * fraction;
|
|
1694
|
+
const buoyantAccelY = buoyantForceY * b.invMassVec.y;
|
|
1695
|
+
b.v.y += buoyantAccelY * dt;
|
|
1696
|
+
const rB = subVec3(centerOfBuoyancy, b.c);
|
|
1697
|
+
const torque = {
|
|
1698
|
+
x: -rB.z * buoyantForceY,
|
|
1699
|
+
y: 0,
|
|
1700
|
+
z: rB.x * buoyantForceY,
|
|
1701
|
+
};
|
|
1702
|
+
const angImpulse = scaleVec3(torque, dt);
|
|
1703
|
+
let dw = mulMat3Vec(invInertia[index], angImpulse);
|
|
1704
|
+
const dwLen = solverSqrt(dotVec3(dw, dw));
|
|
1705
|
+
if (dwLen > 0.5) {
|
|
1706
|
+
dw = scaleVec3(dw, 0.5 / dwLen);
|
|
1707
|
+
}
|
|
1708
|
+
b.w = addVec3(b.w, dw);
|
|
1709
|
+
}
|
|
1710
|
+
const vRel = subVec3(b.v, flowVel);
|
|
1711
|
+
const linDragFactor = 1 / (1 + linearDragCoeff * fraction * dt);
|
|
1712
|
+
b.v = addVec3(scaleVec3(vRel, linDragFactor), flowVel);
|
|
1713
|
+
const angDragFactor = 1 / (1 + angularDragCoeff * fraction * dt);
|
|
1714
|
+
b.w = scaleVec3(b.w, angDragFactor);
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1438
1718
|
/** Runs one deterministic rigid-body step in place over `bodies`. */
|
|
1439
1719
|
export function solveRigidStep(bodies, options) {
|
|
1440
1720
|
/* istanbul ignore next -- worlds are validated far below this bound; guards the packed warm-cache key from silent index collisions. */
|
|
@@ -1589,6 +1869,25 @@ export function solveRigidStep(bodies, options) {
|
|
|
1589
1869
|
b.lowVelFrames = 0;
|
|
1590
1870
|
}
|
|
1591
1871
|
}
|
|
1872
|
+
if (options.fluids && options.fluids.length > 0) {
|
|
1873
|
+
for (const b of bodies) {
|
|
1874
|
+
if (b.isDynamic && b.sleeping) {
|
|
1875
|
+
for (const f of options.fluids) {
|
|
1876
|
+
if (f.layer !== undefined && f.mask !== undefined) {
|
|
1877
|
+
if ((f.mask & b.layer) === 0 || (b.mask & f.layer) === 0) {
|
|
1878
|
+
continue;
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
const sub = computeSubmergence(b, f.bounds);
|
|
1882
|
+
if (sub && sub.fraction > 0) {
|
|
1883
|
+
b.sleeping = false;
|
|
1884
|
+
b.lowVelFrames = 0;
|
|
1885
|
+
break;
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1592
1891
|
for (const m of manifolds) {
|
|
1593
1892
|
wakeIfContacted(bodies[m.a], bodies[m.b]);
|
|
1594
1893
|
wakeIfContacted(bodies[m.b], bodies[m.a]);
|
|
@@ -1713,6 +2012,9 @@ export function solveRigidStep(bodies, options) {
|
|
|
1713
2012
|
b.v.y = b.v.y + options.gravityY * b.gravityScale * h;
|
|
1714
2013
|
}
|
|
1715
2014
|
}
|
|
2015
|
+
if (options.fluids && options.fluids.length > 0) {
|
|
2016
|
+
applyFluidForces(bodies, invInertia, options.fluids, options.gravityY, h);
|
|
2017
|
+
}
|
|
1716
2018
|
for (const joint of joints) {
|
|
1717
2019
|
joint.prepare(jointCtx);
|
|
1718
2020
|
}
|
|
@@ -116,3 +116,16 @@ export interface SplitDeterministicVoxelChunkOptions3D {
|
|
|
116
116
|
* occupied count, and whether any of its voxels touch the specified anchor faces.
|
|
117
117
|
*/
|
|
118
118
|
export declare function splitDeterministicVoxelChunk3D(chunk: DeterministicVoxelChunk3D, options?: SplitDeterministicVoxelChunkOptions3D): readonly VoxelSubChunk3D[];
|
|
119
|
+
export interface DeterministicVoxelCompoundSplitResult3D {
|
|
120
|
+
readonly compounds: readonly (DeterministicVoxelCompoundShape3D | undefined)[];
|
|
121
|
+
readonly preservedBoxesCount: number;
|
|
122
|
+
readonly recookedBoxesCount: number;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Incrementally slices a parent compound collider across partitioned sub-chunks
|
|
126
|
+
* from {@link splitDeterministicVoxelChunk3D}.
|
|
127
|
+
* Preserves intact child box colliders that fall entirely within a sub-chunk's volume
|
|
128
|
+
* without re-cooking, rebasing their offset coordinates to sub-chunk local space.
|
|
129
|
+
* Only re-cooks severed/split boundary voxels that were not covered by preserved boxes.
|
|
130
|
+
*/
|
|
131
|
+
export declare function splitDeterministicVoxelCompoundCollider3D(parentCompound: DeterministicVoxelCompoundShape3D, subChunks: readonly VoxelSubChunk3D[]): DeterministicVoxelCompoundSplitResult3D;
|
package/dist/physics3d-voxel.js
CHANGED
|
@@ -693,3 +693,127 @@ export function splitDeterministicVoxelChunk3D(chunk, options) {
|
|
|
693
693
|
});
|
|
694
694
|
return subChunks;
|
|
695
695
|
}
|
|
696
|
+
/**
|
|
697
|
+
* Incrementally slices a parent compound collider across partitioned sub-chunks
|
|
698
|
+
* from {@link splitDeterministicVoxelChunk3D}.
|
|
699
|
+
* Preserves intact child box colliders that fall entirely within a sub-chunk's volume
|
|
700
|
+
* without re-cooking, rebasing their offset coordinates to sub-chunk local space.
|
|
701
|
+
* Only re-cooks severed/split boundary voxels that were not covered by preserved boxes.
|
|
702
|
+
*/
|
|
703
|
+
export function splitDeterministicVoxelCompoundCollider3D(parentCompound, subChunks) {
|
|
704
|
+
if (subChunks.length === 0) {
|
|
705
|
+
return {
|
|
706
|
+
compounds: [],
|
|
707
|
+
preservedBoxesCount: 0,
|
|
708
|
+
recookedBoxesCount: 0,
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
let totalPreservedBoxes = 0;
|
|
712
|
+
let totalRecookedBoxes = 0;
|
|
713
|
+
const compounds = [];
|
|
714
|
+
for (const subChunk of subChunks) {
|
|
715
|
+
const chunk = subChunk.chunk;
|
|
716
|
+
const cellSize = chunk.cellSize;
|
|
717
|
+
const scX = subChunk.offsetCells.x;
|
|
718
|
+
const scY = subChunk.offsetCells.y;
|
|
719
|
+
const scZ = subChunk.offsetCells.z;
|
|
720
|
+
const maxBoundX = scX + chunk.dimX - 1;
|
|
721
|
+
const maxBoundY = scY + chunk.dimY - 1;
|
|
722
|
+
const maxBoundZ = scZ + chunk.dimZ - 1;
|
|
723
|
+
const totalCells = chunk.dimX * chunk.dimY * chunk.dimZ;
|
|
724
|
+
const coveredInSubChunk = new Uint8Array(totalCells);
|
|
725
|
+
const preservedChildren = [];
|
|
726
|
+
for (const child of parentCompound.children) {
|
|
727
|
+
if (child.shape.type !== 'box') {
|
|
728
|
+
continue;
|
|
729
|
+
}
|
|
730
|
+
const boxMinX = Math.round((child.offset.x - child.shape.halfX) / cellSize + 0.5);
|
|
731
|
+
const boxMaxX = Math.round((child.offset.x + child.shape.halfX) / cellSize - 0.5);
|
|
732
|
+
const boxMinY = Math.round((child.offset.y - child.shape.halfY) / cellSize + 0.5);
|
|
733
|
+
const boxMaxY = Math.round((child.offset.y + child.shape.halfY) / cellSize - 0.5);
|
|
734
|
+
const boxMinZ = Math.round((child.offset.z - child.shape.halfZ) / cellSize + 0.5);
|
|
735
|
+
const boxMaxZ = Math.round((child.offset.z + child.shape.halfZ) / cellSize - 0.5);
|
|
736
|
+
if (boxMinX >= scX && boxMaxX <= maxBoundX &&
|
|
737
|
+
boxMinY >= scY && boxMaxY <= maxBoundY &&
|
|
738
|
+
boxMinZ >= scZ && boxMaxZ <= maxBoundZ) {
|
|
739
|
+
let isIntact = true;
|
|
740
|
+
for (let bz = boxMinZ; bz <= boxMaxZ && isIntact; bz++) {
|
|
741
|
+
for (let by = boxMinY; by <= boxMaxY && isIntact; by++) {
|
|
742
|
+
for (let bx = boxMinX; bx <= boxMaxX; bx++) {
|
|
743
|
+
const lx = bx - scX;
|
|
744
|
+
const ly = by - scY;
|
|
745
|
+
const lz = bz - scZ;
|
|
746
|
+
const idx = lx + chunk.dimX * (ly + chunk.dimY * lz);
|
|
747
|
+
if (chunk.occupancy[idx] === 0) {
|
|
748
|
+
isIntact = false;
|
|
749
|
+
break;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
if (isIntact) {
|
|
755
|
+
for (let bz = boxMinZ; bz <= boxMaxZ; bz++) {
|
|
756
|
+
for (let by = boxMinY; by <= boxMaxY; by++) {
|
|
757
|
+
for (let bx = boxMinX; bx <= boxMaxX; bx++) {
|
|
758
|
+
const lx = bx - scX;
|
|
759
|
+
const ly = by - scY;
|
|
760
|
+
const lz = bz - scZ;
|
|
761
|
+
const idx = lx + chunk.dimX * (ly + chunk.dimY * lz);
|
|
762
|
+
coveredInSubChunk[idx] = 1;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
preservedChildren.push({
|
|
767
|
+
shape: child.shape,
|
|
768
|
+
offset: {
|
|
769
|
+
x: child.offset.x - scX * cellSize,
|
|
770
|
+
y: child.offset.y - scY * cellSize,
|
|
771
|
+
z: child.offset.z - scZ * cellSize,
|
|
772
|
+
},
|
|
773
|
+
...(child.quarterTurns !== undefined ? { quarterTurns: child.quarterTurns } : {}),
|
|
774
|
+
});
|
|
775
|
+
totalPreservedBoxes += 1;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
let uncoveredCount = 0;
|
|
780
|
+
for (let i = 0; i < totalCells; i++) {
|
|
781
|
+
if (chunk.occupancy[i] !== 0 && coveredInSubChunk[i] === 0) {
|
|
782
|
+
uncoveredCount += 1;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
let recookedChildren = [];
|
|
786
|
+
if (uncoveredCount > 0) {
|
|
787
|
+
const uncoveredOccupancy = new Uint8Array(totalCells);
|
|
788
|
+
for (let i = 0; i < totalCells; i++) {
|
|
789
|
+
if (chunk.occupancy[i] !== 0 && coveredInSubChunk[i] === 0) {
|
|
790
|
+
uncoveredOccupancy[i] = 1;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
const uncoveredChunk = {
|
|
794
|
+
dimX: chunk.dimX,
|
|
795
|
+
dimY: chunk.dimY,
|
|
796
|
+
dimZ: chunk.dimZ,
|
|
797
|
+
cellSize: chunk.cellSize,
|
|
798
|
+
occupancy: uncoveredOccupancy,
|
|
799
|
+
};
|
|
800
|
+
recookedChildren = cookSubregionBoxes(uncoveredChunk, 0, 0, 0, chunk.dimX - 1, chunk.dimY - 1, chunk.dimZ - 1);
|
|
801
|
+
totalRecookedBoxes += recookedChildren.length;
|
|
802
|
+
}
|
|
803
|
+
const finalChildren = [...preservedChildren, ...recookedChildren];
|
|
804
|
+
if (finalChildren.length === 0) {
|
|
805
|
+
compounds.push(undefined);
|
|
806
|
+
}
|
|
807
|
+
else {
|
|
808
|
+
compounds.push({
|
|
809
|
+
type: 'compound',
|
|
810
|
+
children: finalChildren,
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
return {
|
|
815
|
+
compounds,
|
|
816
|
+
preservedBoxesCount: totalPreservedBoxes,
|
|
817
|
+
recookedBoxesCount: totalRecookedBoxes,
|
|
818
|
+
};
|
|
819
|
+
}
|
package/dist/physics3d.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type DeterministicPhysicsMaterial } from './deterministic-primitives.js';
|
|
2
2
|
import { type Point3D } from './physics3d-shared.js';
|
|
3
|
+
import { type DeterministicPhysicsAabb3D, type DeterministicFluidVolume3D } from './physics3d-solver.js';
|
|
4
|
+
export type { DeterministicPhysicsAabb3D, DeterministicFluidVolume3D };
|
|
3
5
|
import { type DeterministicPhysicsJoint3D } from './physics3d-joints.js';
|
|
4
6
|
export type DeterministicPhysicsPrimitiveShape3D = {
|
|
5
7
|
readonly type: 'box';
|
|
@@ -364,6 +366,8 @@ export interface DeterministicPhysicsStepResult3D {
|
|
|
364
366
|
readonly contacts: readonly DeterministicPhysicsContactEvent3D[];
|
|
365
367
|
/** Joint ids that broke this step (newly, sorted); sticky once broken. */
|
|
366
368
|
readonly brokenJointIds: readonly string[];
|
|
369
|
+
/** Alias for brokenJointIds requested for ergonomics parity. */
|
|
370
|
+
readonly brokenJoints: readonly string[];
|
|
367
371
|
readonly scheduledQueryResults: readonly {
|
|
368
372
|
readonly id: string;
|
|
369
373
|
readonly hits: readonly DeterministicPhysicsHit3D[];
|
|
@@ -480,6 +484,7 @@ export interface DeterministicPhysicsStepOptions3D {
|
|
|
480
484
|
readonly computeChecksum?: boolean;
|
|
481
485
|
readonly computeBroadphasePairs?: boolean;
|
|
482
486
|
readonly pairs?: readonly (readonly [number, number])[];
|
|
487
|
+
readonly fluids?: readonly DeterministicFluidVolume3D[];
|
|
483
488
|
}
|
|
484
489
|
export declare function stepDeterministicPhysicsWorld3D(world: DeterministicPhysicsWorld3D, options?: DeterministicPhysicsStepOptions3D): DeterministicPhysicsStepResult3D;
|
|
485
490
|
/** O(1) body lookup backed by the per-world query-index cache. */
|
package/dist/physics3d.js
CHANGED
|
@@ -693,7 +693,52 @@ export function setDeterministicBodyVelocity3D(world, bodyId, velocity, angularV
|
|
|
693
693
|
});
|
|
694
694
|
return { ...world, bodies: normalizeBodies(bodies, 'trusted') };
|
|
695
695
|
}
|
|
696
|
+
function validateFluidVolume(fluid) {
|
|
697
|
+
if (typeof fluid.id !== 'string' || fluid.id.length === 0) {
|
|
698
|
+
throw new Error('physics3d fluid: id must be a non-empty string');
|
|
699
|
+
}
|
|
700
|
+
const bounds = fluid.bounds;
|
|
701
|
+
if (!bounds || typeof bounds !== 'object') {
|
|
702
|
+
throw new Error(`physics3d fluid ${fluid.id}: bounds must be an object`);
|
|
703
|
+
}
|
|
704
|
+
const { minX, minY, minZ, maxX, maxY, maxZ } = bounds;
|
|
705
|
+
if (!Number.isFinite(minX) ||
|
|
706
|
+
!Number.isFinite(minY) ||
|
|
707
|
+
!Number.isFinite(minZ) ||
|
|
708
|
+
!Number.isFinite(maxX) ||
|
|
709
|
+
!Number.isFinite(maxY) ||
|
|
710
|
+
!Number.isFinite(maxZ)) {
|
|
711
|
+
throw new Error(`physics3d fluid ${fluid.id}: bounds must contain finite numbers`);
|
|
712
|
+
}
|
|
713
|
+
if (minX > maxX) {
|
|
714
|
+
throw new Error(`physics3d fluid ${fluid.id}: minX must not exceed maxX`);
|
|
715
|
+
}
|
|
716
|
+
if (minY > maxY) {
|
|
717
|
+
throw new Error(`physics3d fluid ${fluid.id}: minY must not exceed maxY`);
|
|
718
|
+
}
|
|
719
|
+
if (minZ > maxZ) {
|
|
720
|
+
throw new Error(`physics3d fluid ${fluid.id}: minZ must not exceed maxZ`);
|
|
721
|
+
}
|
|
722
|
+
if (fluid.density !== undefined && (!Number.isFinite(fluid.density) || fluid.density <= 0)) {
|
|
723
|
+
throw new Error(`physics3d fluid ${fluid.id}: density must be positive`);
|
|
724
|
+
}
|
|
725
|
+
if (fluid.linearDrag !== undefined && (!Number.isFinite(fluid.linearDrag) || fluid.linearDrag < 0)) {
|
|
726
|
+
throw new Error(`physics3d fluid ${fluid.id}: linearDrag must be non-negative`);
|
|
727
|
+
}
|
|
728
|
+
if (fluid.angularDrag !== undefined && (!Number.isFinite(fluid.angularDrag) || fluid.angularDrag < 0)) {
|
|
729
|
+
throw new Error(`physics3d fluid ${fluid.id}: angularDrag must be non-negative`);
|
|
730
|
+
}
|
|
731
|
+
if (fluid.flowVelocity !== undefined) {
|
|
732
|
+
const { x, y, z } = fluid.flowVelocity;
|
|
733
|
+
if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(z)) {
|
|
734
|
+
throw new Error(`physics3d fluid ${fluid.id}: flowVelocity must be finite`);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
696
738
|
export function stepDeterministicPhysicsWorld3D(world, options = {}) {
|
|
739
|
+
for (const fluid of options.fluids ?? []) {
|
|
740
|
+
validateFluidVolume(fluid);
|
|
741
|
+
}
|
|
697
742
|
const scheduledQueries = sortScheduledQueries(options.scheduledQueries ?? []);
|
|
698
743
|
const prePhysicsScheduledQueryResults = scheduledQueries
|
|
699
744
|
.filter((query) => query.phase === 'pre-physics')
|
|
@@ -711,7 +756,7 @@ export function stepDeterministicPhysicsWorld3D(world, options = {}) {
|
|
|
711
756
|
}
|
|
712
757
|
const dt = options.dtTicks ?? 1;
|
|
713
758
|
const gravityY = options.gravityY ?? 0;
|
|
714
|
-
const rigid = runRigidSolver(world, dt, gravityY, velocityIterations, substeps, options.joints ?? [], options.pairs);
|
|
759
|
+
const rigid = runRigidSolver(world, dt, gravityY, velocityIterations, substeps, options.joints ?? [], options.pairs, options.fluids);
|
|
715
760
|
const constrained = solveConstraints3D(rigid.bodies, options.constraints ?? []);
|
|
716
761
|
const solvedBodies = constrained.bodies;
|
|
717
762
|
// Dynamic-involved solid-collision events come from the solver's manifolds (so
|
|
@@ -783,6 +828,7 @@ export function stepDeterministicPhysicsWorld3D(world, options = {}) {
|
|
|
783
828
|
world: nextWorld,
|
|
784
829
|
contacts: events,
|
|
785
830
|
brokenJointIds: rigid.brokenJointIds,
|
|
831
|
+
brokenJoints: rigid.brokenJointIds,
|
|
786
832
|
scheduledQueryResults,
|
|
787
833
|
prePhysicsScheduledQueryResults,
|
|
788
834
|
postPhysicsScheduledQueryResults,
|
|
@@ -2236,7 +2282,7 @@ function sleepingRebuildIsNoop(body, sb) {
|
|
|
2236
2282
|
&& eq(q(sb.w.x), body.angularVel.x) && eq(q(sb.w.y), body.angularVel.y) && eq(q(sb.w.z), body.angularVel.z)
|
|
2237
2283
|
&& eq(sb.lowVelFrames, body.lowVelFrames);
|
|
2238
2284
|
}
|
|
2239
|
-
function runRigidSolver(world, dt, gravityY, velocityIterations, substeps, joints, pairs) {
|
|
2285
|
+
function runRigidSolver(world, dt, gravityY, velocityIterations, substeps, joints, pairs, fluids) {
|
|
2240
2286
|
const source = world.bodies;
|
|
2241
2287
|
const indexById = new Map(source.map((body, index) => [body.id, index]));
|
|
2242
2288
|
const solverBodies = source.map((body, index) => buildSolverBody(body, index));
|
|
@@ -2281,6 +2327,7 @@ function runRigidSolver(world, dt, gravityY, velocityIterations, substeps, joint
|
|
|
2281
2327
|
warm,
|
|
2282
2328
|
pairs,
|
|
2283
2329
|
joints: solverJoints,
|
|
2330
|
+
fluids,
|
|
2284
2331
|
});
|
|
2285
2332
|
// Post-solve safety clamp: no fast body may end past its TOI along its motion.
|
|
2286
2333
|
for (const [index, clamp] of fastClamps) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@series-inc/rundot-syncplay",
|
|
3
|
-
"version": "5.28.0-beta.
|
|
3
|
+
"version": "5.28.0-beta.4",
|
|
4
4
|
"description": "Kinetix orchestration, rollback, replay, late-join, and deterministic networking for RUN.game",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
"test:core": "node --expose-gc --import tsx --test --test-concurrency=1 tests/canonical.test.ts tests/canonical-portability.test.ts tests/runtime-session.test.ts tests/kinetix-runtime-session.test.ts tests/runtime-support.test.ts tests/runtime-guards.test.ts tests/r3f-render-adapter.test.ts tests/snapshot-cost.test.ts tests/sdkSession.test.ts tests/input-authority.test.ts tests/session-wire.test.ts tests/runtime-room-metadata.test.ts tests/session-snapshot.test.ts tests/authority-room.test.ts tests/networked-client-snapshot.test.ts tests/runner.test.ts tests/testing.test.ts tests/browser-session.test.ts tests/secret-config.test.ts tests/secret-protocol.test.ts tests/secret-authority.test.ts tests/secret-client.test.ts tests/late-join-checksum.test.ts tests/late-join-input-backfill.test.ts tests/replay-scoring.test.ts tests/bot-backfill.test.ts tests/latency-simulation.test.ts tests/production-input-budget.test.ts tests/time-sync.test.ts tests/match-log.test.ts tests/spectator.test.ts tests/synctest.test.ts tests/instant-replay.test.ts tests/session-promotion.test.ts tests/physics3d-broadphase-stats.test.ts tests/entrypoints.test.ts tests/export-surface.test.ts tests/module-seam.test.ts tests/module-contract-portability.test.ts tests/module-identity.test.ts tests/module-corpus.test.ts tests/component-model.test.ts tests/component-model-rollback.test.ts tests/component-model-integration.test.ts tests/actors-ai.test.ts tests/character-3d.test.ts tests/character-3d-certification.test.ts tests/combat-modules.test.ts tests/combat-modules-integration.test.ts tests/firearm.test.ts tests/gameplay-effects.test.ts tests/spatial-interaction.test.ts tests/stats-abilities.test.ts tests/inventory-equipment.test.ts tests/inventory-equipment-certification.test.ts tests/platformer-2d.test.ts tests/platformer-2d-certification.test.ts tests/module-promotion.test.ts tests/module-docs.test.ts tests/module-bundle-budget.test.ts tests/published-side-effects.test.ts tests/host-timing.test.ts tests/test-manifest.test.ts tests/coarse-region.test.ts tests/input-codec.test.ts tests/command-ingress.test.ts tests/session-reconfigure.test.ts tests/prediction-mode.test.ts tests/ephemeral-channel.test.ts tests/runner-surface.test.ts tests/runner-harness.test.ts tests/effects-adapter-bounds.test.ts tests/simulated-match-secrets.test.ts tests/run-glue-surface.test.mjs core/tests/core-boundary.test.mjs tests/math-core-parity.test.ts tests/math-profile.test.ts tests/movement3d-kcc-unit-contract.test.ts tests/movement3d-static-ground.test.ts",
|
|
169
169
|
"test:sdk-contract": "node --import tsx --test tests/sdk-runtime-contract.test.ts",
|
|
170
170
|
"test:soak": "tsx --test tests/runtime-soak.test.ts",
|
|
171
|
-
"test:extended": "tsx --test tests/kcc-vehicle-characterization.test.ts tests/animation.test.ts tests/asset-cooking.test.ts tests/backend-proof-checksum-vectors.test.ts tests/bot-documents.test.ts tests/bot-primitives.test.ts tests/collider-cooking.test.ts tests/collision.test.ts tests/command-timeline.test.ts tests/config-bundle.test.ts tests/cosmetic-physics3d.test.ts tests/deterministic-primitives.test.ts tests/ecs-lite.test.ts tests/effects-adapter.test.ts tests/engine-runtime.test.ts tests/errors.test.ts tests/events.test.ts tests/input-button.test.ts tests/load-128-players.test.ts tests/math.test.ts tests/movement.test.ts tests/movement3d.test.ts tests/multiclient-authority.test.ts tests/navigation.test.ts tests/noise.test.ts tests/physics-cert.test.ts tests/physics2d.test.ts tests/physics3d-ccd.test.ts tests/physics3d-coverage.test.ts tests/physics3d-debug-wireframe.test.ts tests/physics3d-destruction-cert.test.ts tests/physics3d-forces-and-contacts.test.ts tests/physics3d-geometry-limits.test.ts tests/physics3d-heightfield.test.ts tests/physics3d-hull.test.ts tests/physics3d-joints.test.ts tests/physics3d-kinematic-mesh.test.ts tests/physics3d-kinematic-poses.test.ts tests/physics3d-kinematic-transforms.test.ts tests/physics3d-mass.test.ts tests/physics3d-materials.test.ts tests/physics3d-mesh-onesided.test.ts tests/physics3d-queries-capsule-childindex.test.ts tests/physics3d-query-index.test.ts tests/physics3d-recipes.test.ts tests/physics3d-rotation-convention.test.ts tests/physics3d-shape-builders.test.ts tests/physics3d-shared.test.ts tests/physics3d-sleeping-manifold-reuse.test.ts tests/physics3d-solver.test.ts tests/physics3d-static-memoization.test.ts tests/physics3d-static-overlap-memo.test.ts tests/physics3d-cylinder-hull.test.ts tests/physics3d-stacking.test.ts tests/physics3d-toi.test.ts tests/physics3d-vehicle.test.ts tests/physics3d-voxel-carving.test.ts tests/physics3d-voxel-dda.test.ts tests/physics3d-voxel-split.test.ts tests/physics3d-voxel.test.ts tests/physics3d-world-edit.test.ts tests/physics3d.test.ts tests/physics-vector-generator.test.ts tests/random.test.ts tests/rollback-history.test.ts tests/schema-artifacts.test.ts tests/schema-codegen.test.ts tests/schema-dsl-binary.test.ts tests/schema.test.ts tests/signals.test.ts tests/sparse-set.test.ts tests/static-checker.test.ts tests/system-lifecycle.test.ts tests/wire-canonical-sentinels.test.ts tests/ws-frame.test.ts",
|
|
171
|
+
"test:extended": "tsx --test tests/kcc-vehicle-characterization.test.ts tests/animation.test.ts tests/asset-cooking.test.ts tests/backend-proof-checksum-vectors.test.ts tests/bot-documents.test.ts tests/bot-primitives.test.ts tests/collider-cooking.test.ts tests/collision.test.ts tests/command-timeline.test.ts tests/config-bundle.test.ts tests/cosmetic-physics3d.test.ts tests/deterministic-primitives.test.ts tests/ecs-lite.test.ts tests/effects-adapter.test.ts tests/engine-runtime.test.ts tests/errors.test.ts tests/events.test.ts tests/input-button.test.ts tests/load-128-players.test.ts tests/math.test.ts tests/movement.test.ts tests/movement3d.test.ts tests/multiclient-authority.test.ts tests/navigation.test.ts tests/noise.test.ts tests/physics-cert.test.ts tests/physics2d.test.ts tests/physics3d-buoyancy.test.ts tests/physics3d-ccd.test.ts tests/physics3d-coverage.test.ts tests/physics3d-debug-wireframe.test.ts tests/physics3d-destruction-cert.test.ts tests/physics3d-forces-and-contacts.test.ts tests/physics3d-geometry-limits.test.ts tests/physics3d-heightfield.test.ts tests/physics3d-hull.test.ts tests/physics3d-joints.test.ts tests/physics3d-kinematic-mesh.test.ts tests/physics3d-kinematic-poses.test.ts tests/physics3d-kinematic-transforms.test.ts tests/physics3d-mass.test.ts tests/physics3d-materials.test.ts tests/physics3d-mesh-onesided.test.ts tests/physics3d-queries-capsule-childindex.test.ts tests/physics3d-query-index.test.ts tests/physics3d-recipes.test.ts tests/physics3d-rotation-convention.test.ts tests/physics3d-shape-builders.test.ts tests/physics3d-shared.test.ts tests/physics3d-sleeping-manifold-reuse.test.ts tests/physics3d-solver.test.ts tests/physics3d-static-memoization.test.ts tests/physics3d-static-overlap-memo.test.ts tests/physics3d-cylinder-hull.test.ts tests/physics3d-stacking.test.ts tests/physics3d-toi.test.ts tests/physics3d-vehicle.test.ts tests/physics3d-voxel-carving.test.ts tests/physics3d-voxel-dda.test.ts tests/physics3d-voxel-split.test.ts tests/physics3d-voxel.test.ts tests/physics3d-world-edit.test.ts tests/physics3d.test.ts tests/physics-vector-generator.test.ts tests/random.test.ts tests/rollback-history.test.ts tests/schema-artifacts.test.ts tests/schema-codegen.test.ts tests/schema-dsl-binary.test.ts tests/schema.test.ts tests/signals.test.ts tests/sparse-set.test.ts tests/static-checker.test.ts tests/system-lifecycle.test.ts tests/wire-canonical-sentinels.test.ts tests/ws-frame.test.ts",
|
|
172
172
|
"test:ci": "npm run build && npm run test",
|
|
173
173
|
"build:native": "node core/scripts/build-native.mjs",
|
|
174
174
|
"build:mobile-native": "node core/scripts/build-mobile-native.mjs",
|