@flighthq/physics3d-abi 0.4.0-next.1827.9db114b

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 (39) hide show
  1. package/dist/contract.d.ts +6 -0
  2. package/dist/contract.d.ts.map +1 -0
  3. package/dist/contract.js +6 -0
  4. package/dist/contract.js.map +1 -0
  5. package/dist/index.d.ts +2 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +2 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/physics3DAbi.d.ts +11 -0
  10. package/dist/physics3DAbi.d.ts.map +1 -0
  11. package/dist/physics3DAbi.js +32 -0
  12. package/dist/physics3DAbi.js.map +1 -0
  13. package/dist/physics3DAbiBuffer.d.ts +10 -0
  14. package/dist/physics3DAbiBuffer.d.ts.map +1 -0
  15. package/dist/physics3DAbiBuffer.js +81 -0
  16. package/dist/physics3DAbiBuffer.js.map +1 -0
  17. package/dist/physics3DAbiCommand.d.ts +17 -0
  18. package/dist/physics3DAbiCommand.d.ts.map +1 -0
  19. package/dist/physics3DAbiCommand.js +554 -0
  20. package/dist/physics3DAbiCommand.js.map +1 -0
  21. package/dist/physics3DAbiLayout.d.ts +216 -0
  22. package/dist/physics3DAbiLayout.d.ts.map +1 -0
  23. package/dist/physics3DAbiLayout.js +221 -0
  24. package/dist/physics3DAbiLayout.js.map +1 -0
  25. package/dist/physics3DAbiQuery.d.ts +7 -0
  26. package/dist/physics3DAbiQuery.d.ts.map +1 -0
  27. package/dist/physics3DAbiQuery.js +16 -0
  28. package/dist/physics3DAbiQuery.js.map +1 -0
  29. package/dist/referencePhysics3DAbi.d.ts +3 -0
  30. package/dist/referencePhysics3DAbi.d.ts.map +1 -0
  31. package/dist/referencePhysics3DAbi.js +1165 -0
  32. package/dist/referencePhysics3DAbi.js.map +1 -0
  33. package/package.json +50 -0
  34. package/src/physics3DAbi.test.ts +584 -0
  35. package/src/physics3DAbiBuffer.test.ts +117 -0
  36. package/src/physics3DAbiCommand.test.ts +368 -0
  37. package/src/physics3DAbiLayout.test.ts +64 -0
  38. package/src/physics3DAbiQuery.test.ts +122 -0
  39. package/src/referencePhysics3DAbi.test.ts +19 -0
@@ -0,0 +1,1165 @@
1
+ import { getCollisionHeightfieldValidationStatus3D, getCollisionShapeValidationStatus3D, getCollisionTriangleMeshValidationStatus3D, registerBuiltInCollisionFaceQueries3D, registerBuiltInCollisionPairTests3D, registerBuiltInCollisionSupports3D, } from '@flighthq/collision/contract';
2
+ import { addPhysics3DBody, addPhysics3DCollider, addPhysics3DJoint, applyPhysics3DForce, applyPhysics3DForceAtPoint, applyPhysics3DLinearImpulse, applyPhysics3DLinearImpulseAtPoint, applyPhysics3DTorque, createPhysics3DBallAndSocketJoint, createPhysics3DCollider, createPhysics3DConeTwistJoint, createPhysics3DDistanceJoint, createPhysics3DFixedJoint, createPhysics3DGeneric6DofJoint, createPhysics3DHingeJoint, createPhysics3DJointReaction, createPhysics3DQueryResult, createPhysics3DRayResult, createPhysics3DShapeCastResult, createPhysics3DSliderJoint, createPhysics3DWorld, createRigidBody3D, isPhysics3DBodyStateValid, isPhysics3DColliderStateValid, isPhysics3DContactStateValid, isPhysics3DGravityValid, isPhysics3DJointStateValid, isPhysics3DPositionIterationsValid, isPhysics3DSolverConfigValid, isPhysics3DSubstepsValid, isPhysics3DTimestepValid, isPhysics3DVelocityIterationsValid, queryPhysics3DPoint, queryPhysics3DRay, queryPhysics3DRayClosest, queryPhysics3DRegion, queryPhysics3DShapeCast, refreshRigidBody3DWorldInertia, registerBuiltInPhysics3DJointSolvers, removePhysics3DBody, removePhysics3DCollider, removePhysics3DJoint, setPhysics3DBodyBullet, setPhysics3DBodyFixedRotation, setPhysics3DBodySleepEnabled, setPhysics3DBodyTransform, setPhysics3DBodyType, setRigidBody3DMassData, stepPhysics3D, wakePhysics3DBody, writePhysics3DJointReaction, } from '@flighthq/physics3d/contract';
3
+ import { Physics3DAbiBodyFlag, Physics3DAbiBodyType, Physics3DAbiBodyValueStride, Physics3DAbiCapability, Physics3DAbiCommandByteLength, Physics3DAbiCommandHeaderByteLength, Physics3DAbiCommandKind, Physics3DAbiCommandMagic, Physics3DAbiCommandRecordHeaderByteLength, Physics3DAbiContactFlag, Physics3DAbiContactIdStride, Physics3DAbiContactPointValueStride, Physics3DAbiContactValueStride, Physics3DAbiJointFlag, Physics3DAbiJointKind, Physics3DAbiJointValueStride, Physics3DAbiQueryValueStride, Physics3DAbiSetColliderPayloadOffset, Physics3DAbiShapeHeaderByteLength, Physics3DAbiShapeKind, Physics3DAbiVersion, } from './physics3DAbiLayout';
4
+ export function createReferencePhysics3DAbi() {
5
+ registerBuiltInCollisionSupports3D();
6
+ registerBuiltInCollisionPairTests3D();
7
+ registerBuiltInCollisionFaceQueries3D();
8
+ const worlds = new Map();
9
+ let nextWorldHandle = 1;
10
+ return {
11
+ version: Physics3DAbiVersion,
12
+ capabilities: Physics3DAbiCapability.ContactHooks |
13
+ Physics3DAbiCapability.PersistentWorlds |
14
+ Physics3DAbiCapability.Queries |
15
+ Physics3DAbiCapability.SelectiveReadback,
16
+ createWorld() {
17
+ if (nextWorldHandle > 0xffffffff)
18
+ return 0;
19
+ const handle = nextWorldHandle;
20
+ nextWorldHandle += 1;
21
+ const world = createPhysics3DWorld();
22
+ registerBuiltInPhysics3DJointSolvers(world);
23
+ worlds.set(handle, createReferenceWorld(world));
24
+ return handle;
25
+ },
26
+ destroyWorld(handle) {
27
+ if (worlds.get(handle)?.stepping === true)
28
+ return false;
29
+ return worlds.delete(handle);
30
+ },
31
+ getWorldStatus(handle) {
32
+ const state = worlds.get(handle);
33
+ if (state === undefined)
34
+ return 'Stale';
35
+ return state.stepping ? 'Busy' : 'Ready';
36
+ },
37
+ execute(handle, commands, out) {
38
+ const state = worlds.get(handle);
39
+ if (state === undefined)
40
+ return failExecution(out, 'StaleWorld', 0, Physics3DAbiCommandHeaderByteLength, 0);
41
+ if (state.stepping)
42
+ return failExecution(out, 'BusyWorld', 0, Physics3DAbiCommandHeaderByteLength, 0);
43
+ return executeCommands(state, commands, out);
44
+ },
45
+ step(handle, dt, hooks) {
46
+ const state = worlds.get(handle);
47
+ if (state === undefined)
48
+ return 'StaleWorld';
49
+ if (state.stepping)
50
+ return 'BusyWorld';
51
+ return stepReferenceWorld(state, dt, hooks);
52
+ },
53
+ readBodies(handle, bodyIds, out) {
54
+ const state = worlds.get(handle);
55
+ if (state === undefined || state.stepping)
56
+ return false;
57
+ readBodies(state, bodyIds, out);
58
+ return true;
59
+ },
60
+ readContacts(handle, selection, out) {
61
+ const state = worlds.get(handle);
62
+ if (state === undefined || state.stepping)
63
+ return false;
64
+ readContacts(state, selection, out);
65
+ return true;
66
+ },
67
+ readJoints(handle, out) {
68
+ const state = worlds.get(handle);
69
+ if (state === undefined || state.stepping)
70
+ return false;
71
+ readJoints(state, out);
72
+ return true;
73
+ },
74
+ queryPoint(handle, x, y, z, filter, out) {
75
+ const state = worlds.get(handle);
76
+ if (state === undefined || state.stepping)
77
+ return false;
78
+ queryPhysics3DPoint(state.world, x, y, z, state.query, filter ?? undefined);
79
+ writeQueryHits(state, state.query, out);
80
+ return true;
81
+ },
82
+ queryRay(handle, originX, originY, originZ, directionX, directionY, directionZ, maxFraction, closest, filter, out) {
83
+ const state = worlds.get(handle);
84
+ if (state === undefined || state.stepping)
85
+ return false;
86
+ const query = closest ? queryPhysics3DRayClosest : queryPhysics3DRay;
87
+ query(state.world, originX, originY, originZ, directionX, directionY, directionZ, state.ray, maxFraction, filter ?? undefined);
88
+ writeRayHits(state, out);
89
+ return true;
90
+ },
91
+ queryRegion(handle, region, filter, out) {
92
+ const state = worlds.get(handle);
93
+ if (state === undefined || state.stepping)
94
+ return false;
95
+ queryPhysics3DRegion(state.world, region, state.query, filter ?? undefined);
96
+ writeQueryHits(state, state.query, out);
97
+ return true;
98
+ },
99
+ queryShapeCast(handle, shape, dx, dy, dz, maxFraction, filter, out) {
100
+ const state = worlds.get(handle);
101
+ if (state === undefined || state.stepping)
102
+ return false;
103
+ queryPhysics3DShapeCast(state.world, shape, dx, dy, dz, state.shapeCast, maxFraction, filter ?? undefined);
104
+ writeShapeCastHit(state, out);
105
+ return true;
106
+ },
107
+ };
108
+ }
109
+ function createReferenceWorld(world) {
110
+ let state;
111
+ state = {
112
+ world,
113
+ bodyById: new Map(),
114
+ idByBody: new Map(),
115
+ bodyIds: [],
116
+ colliderById: new Map(),
117
+ idByCollider: new Map(),
118
+ jointById: new Map(),
119
+ idByJoint: new Map(),
120
+ jointIds: [],
121
+ query: createPhysics3DQueryResult(),
122
+ ray: createPhysics3DRayResult(),
123
+ shapeCast: createPhysics3DShapeCastResult(),
124
+ reaction: createPhysics3DJointReaction(),
125
+ bodyValues: new Array(Physics3DAbiBodyValueStride).fill(0),
126
+ jointCommonValues: new Array(16).fill(0),
127
+ jointKindValues: new Array(14).fill(0),
128
+ activeHooks: null,
129
+ stepping: false,
130
+ preSolveHook(_world, contact) {
131
+ const hooks = state.activeHooks;
132
+ if (hooks?.preSolve !== null && hooks?.preSolve !== undefined) {
133
+ invokeContactHook(state, contact, hooks.buffer, hooks.preSolve);
134
+ }
135
+ },
136
+ postSolveHook(_world, contact) {
137
+ const hooks = state.activeHooks;
138
+ if (hooks?.postSolve !== null && hooks?.postSolve !== undefined) {
139
+ invokeContactHook(state, contact, hooks.buffer, hooks.postSolve);
140
+ }
141
+ },
142
+ };
143
+ return state;
144
+ }
145
+ function executeCommands(state, commands, out) {
146
+ if (!isCommandBufferValid(commands)) {
147
+ return failExecution(out, 'InvalidBuffer', 0, Physics3DAbiCommandHeaderByteLength, 0);
148
+ }
149
+ const view = new DataView(commands.data.buffer, commands.data.byteOffset, commands.data.byteLength);
150
+ let byteOffset = Physics3DAbiCommandHeaderByteLength;
151
+ for (let commandIndex = 0; commandIndex < commands.commandCount; commandIndex += 1) {
152
+ if (byteOffset + Physics3DAbiCommandRecordHeaderByteLength > commands.byteLength) {
153
+ return failExecution(out, 'InvalidBuffer', commandIndex, byteOffset, 0);
154
+ }
155
+ const kind = view.getUint32(byteOffset, true);
156
+ const byteLength = view.getUint32(byteOffset + 4, true);
157
+ if (byteLength < Physics3DAbiCommandRecordHeaderByteLength ||
158
+ byteLength % 8 !== 0 ||
159
+ byteOffset + byteLength > commands.byteLength) {
160
+ return failExecution(out, 'InvalidBuffer', commandIndex, byteOffset, kind);
161
+ }
162
+ const record = {
163
+ view,
164
+ start: byteOffset,
165
+ payload: byteOffset + Physics3DAbiCommandRecordHeaderByteLength,
166
+ byteLength,
167
+ kind,
168
+ objectId: view.getUint32(byteOffset + 8, true),
169
+ relatedId: view.getUint32(byteOffset + 12, true),
170
+ };
171
+ const status = executeCommand(state, record);
172
+ if (status !== 'Complete')
173
+ return failExecution(out, status, commandIndex, byteOffset, kind);
174
+ byteOffset += byteLength;
175
+ }
176
+ if (byteOffset !== commands.byteLength) {
177
+ return failExecution(out, 'InvalidBuffer', commands.commandCount, byteOffset, 0);
178
+ }
179
+ out.status = 'Complete';
180
+ out.commandIndex = commands.commandCount;
181
+ out.byteOffset = byteOffset;
182
+ out.commandKind = 0;
183
+ return true;
184
+ }
185
+ function executeCommand(state, command) {
186
+ if (command.kind === Physics3DAbiCommandKind.SetGravity)
187
+ return executeSetGravity(state, command);
188
+ if (command.kind === Physics3DAbiCommandKind.SetSolverConfig)
189
+ return executeSetSolverConfig(state, command);
190
+ if (command.kind === Physics3DAbiCommandKind.SetBody)
191
+ return executeSetBody(state, command);
192
+ if (command.kind === Physics3DAbiCommandKind.DestroyBody)
193
+ return executeDestroyBody(state, command);
194
+ if (command.kind === Physics3DAbiCommandKind.SetCollider)
195
+ return executeSetCollider(state, command);
196
+ if (command.kind === Physics3DAbiCommandKind.DestroyCollider)
197
+ return executeDestroyCollider(state, command);
198
+ if (command.kind === Physics3DAbiCommandKind.SetJoint)
199
+ return executeSetJoint(state, command);
200
+ if (command.kind === Physics3DAbiCommandKind.DestroyJoint)
201
+ return executeDestroyJoint(state, command);
202
+ if (command.kind === Physics3DAbiCommandKind.ApplyForce)
203
+ return executeBodyAction(state, command, applyPhysics3DForce);
204
+ if (command.kind === Physics3DAbiCommandKind.ApplyForceAtPoint) {
205
+ return executeBodyPointAction(state, command, applyPhysics3DForceAtPoint);
206
+ }
207
+ if (command.kind === Physics3DAbiCommandKind.ApplyLinearImpulse) {
208
+ return executeBodyAction(state, command, applyPhysics3DLinearImpulse);
209
+ }
210
+ if (command.kind === Physics3DAbiCommandKind.ApplyLinearImpulseAtPoint) {
211
+ return executeBodyPointAction(state, command, applyPhysics3DLinearImpulseAtPoint);
212
+ }
213
+ if (command.kind === Physics3DAbiCommandKind.ApplyTorque)
214
+ return executeBodyAction(state, command, applyPhysics3DTorque);
215
+ if (command.kind === Physics3DAbiCommandKind.WakeBody)
216
+ return executeWakeBody(state, command);
217
+ return 'InvalidCommand';
218
+ }
219
+ function executeSetGravity(state, command) {
220
+ if (command.byteLength !== Physics3DAbiCommandByteLength.SetGravity ||
221
+ command.objectId !== 0 ||
222
+ command.relatedId !== 0) {
223
+ return 'InvalidCommand';
224
+ }
225
+ const x = command.view.getFloat64(command.payload, true);
226
+ const y = command.view.getFloat64(command.payload + 8, true);
227
+ const z = command.view.getFloat64(command.payload + 16, true);
228
+ if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(z))
229
+ return 'RejectedMutation';
230
+ state.world.gravityX = x;
231
+ state.world.gravityY = y;
232
+ state.world.gravityZ = z;
233
+ return 'Complete';
234
+ }
235
+ function executeSetSolverConfig(state, command) {
236
+ if (command.byteLength !== Physics3DAbiCommandByteLength.SetSolverConfig ||
237
+ command.objectId !== 0 ||
238
+ command.relatedId !== 0) {
239
+ return 'InvalidCommand';
240
+ }
241
+ const flags = command.view.getUint32(command.payload, true);
242
+ if ((flags & 0b111) !== flags ||
243
+ command.view.getUint32(command.payload + 24, true) !== 0 ||
244
+ command.view.getUint32(command.payload + 28, true) !== 0) {
245
+ return 'InvalidCommand';
246
+ }
247
+ const config = {
248
+ allowSleeping: (flags & 1) !== 0,
249
+ continuousCollision: (flags & (1 << 1)) !== 0,
250
+ substeps: command.view.getUint32(command.payload + 4, true),
251
+ maxCcdSubsteps: command.view.getUint32(command.payload + 8, true),
252
+ maxCcdRotationSubsteps: command.view.getUint32(command.payload + 12, true),
253
+ sleepLinearThreshold: command.view.getFloat64(command.payload + 32, true),
254
+ sleepAngularThreshold: command.view.getFloat64(command.payload + 40, true),
255
+ timeToSleep: command.view.getFloat64(command.payload + 48, true),
256
+ sequentialImpulse: {
257
+ velocityIterations: command.view.getUint32(command.payload + 16, true),
258
+ positionIterations: command.view.getUint32(command.payload + 20, true),
259
+ penetrationSlop: command.view.getFloat64(command.payload + 56, true),
260
+ positionCorrection: command.view.getFloat64(command.payload + 64, true),
261
+ restitutionThreshold: command.view.getFloat64(command.payload + 72, true),
262
+ warmStarting: (flags & (1 << 2)) !== 0,
263
+ },
264
+ };
265
+ if (!isPhysics3DSubstepsValid(config) ||
266
+ !isPhysics3DVelocityIterationsValid(config) ||
267
+ !isPhysics3DPositionIterationsValid(config) ||
268
+ !isPhysics3DSolverConfigValid(config)) {
269
+ return 'RejectedMutation';
270
+ }
271
+ state.world.config = config;
272
+ return 'Complete';
273
+ }
274
+ function executeSetBody(state, command) {
275
+ if (command.byteLength !== Physics3DAbiCommandByteLength.SetBody ||
276
+ !isObjectId(command.objectId) ||
277
+ command.relatedId !== 0) {
278
+ return 'InvalidCommand';
279
+ }
280
+ const flags = command.view.getUint32(command.payload, true);
281
+ if ((flags & PHYSICS3D_ABI_BODY_FLAG_MASK) !== flags || command.view.getUint32(command.payload + 4, true) !== 0) {
282
+ return 'InvalidCommand';
283
+ }
284
+ const type = decodeBodyType(flags & Physics3DAbiBodyFlag.TypeMask);
285
+ const values = readFloat64Values(command, 8, state.bodyValues);
286
+ if (type === null || !isBodyValueBlockValid(values))
287
+ return 'RejectedMutation';
288
+ let body = state.bodyById.get(command.objectId);
289
+ const added = body === undefined;
290
+ body ??= createRigidBody3D(type);
291
+ if (!setPhysics3DBodyType(body, type))
292
+ return 'RejectedMutation';
293
+ if (!setPhysics3DBodyFixedRotation(body, (flags & Physics3DAbiBodyFlag.FixedRotation) !== 0)) {
294
+ return 'RejectedMutation';
295
+ }
296
+ if (!setPhysics3DBodyBullet(body, (flags & Physics3DAbiBodyFlag.Bullet) !== 0))
297
+ return 'RejectedMutation';
298
+ if (!setPhysics3DBodySleepEnabled(body, (flags & Physics3DAbiBodyFlag.SleepEnabled) !== 0)) {
299
+ return 'RejectedMutation';
300
+ }
301
+ if (!setPhysics3DBodyTransform(body, values[0], values[1], values[2], values[3], values[4], values[5], values[6])) {
302
+ return 'RejectedMutation';
303
+ }
304
+ setRigidBody3DMassData(body, {
305
+ mass: values[19],
306
+ inertiaXX: values[20],
307
+ inertiaYY: values[21],
308
+ inertiaZZ: values[22],
309
+ inertiaXY: values[23],
310
+ inertiaXZ: values[24],
311
+ inertiaYZ: values[25],
312
+ centerX: values[26],
313
+ centerY: values[27],
314
+ centerZ: values[28],
315
+ });
316
+ refreshRigidBody3DWorldInertia(body);
317
+ writeBodyDynamicValues(body, values, flags);
318
+ if (added) {
319
+ addPhysics3DBody(state.world, body);
320
+ state.bodyById.set(command.objectId, body);
321
+ state.idByBody.set(body, command.objectId);
322
+ insertSorted(state.bodyIds, command.objectId);
323
+ }
324
+ return 'Complete';
325
+ }
326
+ function executeDestroyBody(state, command) {
327
+ if (command.byteLength !== Physics3DAbiCommandByteLength.DestroyBody ||
328
+ !isObjectId(command.objectId) ||
329
+ command.relatedId !== 0) {
330
+ return 'InvalidCommand';
331
+ }
332
+ const body = state.bodyById.get(command.objectId);
333
+ if (body === undefined)
334
+ return 'MissingBody';
335
+ for (const [id, held] of state.colliderById) {
336
+ if (held.bodyId !== command.objectId)
337
+ continue;
338
+ state.colliderById.delete(id);
339
+ state.idByCollider.delete(held.collider);
340
+ }
341
+ for (const [id, joint] of state.jointById) {
342
+ if (joint.bodyA !== body.index && joint.bodyB !== body.index)
343
+ continue;
344
+ state.jointById.delete(id);
345
+ state.idByJoint.delete(joint);
346
+ removeSorted(state.jointIds, id);
347
+ }
348
+ removePhysics3DBody(state.world, body);
349
+ state.bodyById.delete(command.objectId);
350
+ state.idByBody.delete(body);
351
+ removeSorted(state.bodyIds, command.objectId);
352
+ return 'Complete';
353
+ }
354
+ function executeSetCollider(state, command) {
355
+ if (!isObjectId(command.objectId) ||
356
+ !isObjectId(command.relatedId) ||
357
+ command.byteLength < Physics3DAbiCommandByteLength.SetColliderMinimum) {
358
+ return 'InvalidCommand';
359
+ }
360
+ const body = state.bodyById.get(command.relatedId);
361
+ if (body === undefined)
362
+ return 'MissingBody';
363
+ const colliderFlags = command.view.getUint32(command.payload, true);
364
+ if ((colliderFlags & 1) !== colliderFlags)
365
+ return 'InvalidCommand';
366
+ const shapeCode = command.view.getUint32(command.payload + Physics3DAbiSetColliderPayloadOffset.Shape, true);
367
+ if (shapeCode < Physics3DAbiShapeKind.Sphere || shapeCode > Physics3DAbiShapeKind.Heightfield) {
368
+ return 'UnsupportedShape';
369
+ }
370
+ const shape = readShape(command, command.payload + Physics3DAbiSetColliderPayloadOffset.Shape);
371
+ if (shape === null)
372
+ return 'InvalidCommand';
373
+ if (!isShapeValid(shape))
374
+ return 'RejectedMutation';
375
+ if (body.type !== 'static' && (shape.kind === 'triangle-mesh' || shape.kind === 'heightfield')) {
376
+ return 'RejectedMutation';
377
+ }
378
+ const density = command.view.getFloat64(command.payload + 16, true);
379
+ const friction = command.view.getFloat64(command.payload + 24, true);
380
+ const restitution = command.view.getFloat64(command.payload + 32, true);
381
+ const categoryBits = command.view.getUint32(command.payload + 4, true);
382
+ const maskBits = command.view.getUint32(command.payload + 8, true);
383
+ const groupIndex = command.view.getInt32(command.payload + 12, true);
384
+ if (![density, friction, restitution].every((value) => Number.isFinite(value) && value >= 0)) {
385
+ return 'RejectedMutation';
386
+ }
387
+ const collider = createPhysics3DCollider(shape, { density, friction, restitution }, { categoryBits, maskBits, groupIndex }, (colliderFlags & 1) !== 0);
388
+ const previous = state.colliderById.get(command.objectId);
389
+ if (previous !== undefined) {
390
+ const previousBody = state.bodyById.get(previous.bodyId);
391
+ if (previousBody === undefined)
392
+ return 'MissingBody';
393
+ removePhysics3DCollider(state.world, previousBody, previous.collider);
394
+ state.idByCollider.delete(previous.collider);
395
+ }
396
+ addPhysics3DCollider(state.world, body, collider);
397
+ state.colliderById.set(command.objectId, { bodyId: command.relatedId, collider });
398
+ state.idByCollider.set(collider, command.objectId);
399
+ return 'Complete';
400
+ }
401
+ function executeDestroyCollider(state, command) {
402
+ if (command.byteLength !== Physics3DAbiCommandByteLength.DestroyCollider ||
403
+ !isObjectId(command.objectId) ||
404
+ command.relatedId !== 0) {
405
+ return 'InvalidCommand';
406
+ }
407
+ const held = state.colliderById.get(command.objectId);
408
+ if (held === undefined)
409
+ return 'MissingCollider';
410
+ const body = state.bodyById.get(held.bodyId);
411
+ if (body === undefined || !removePhysics3DCollider(state.world, body, held.collider))
412
+ return 'MissingBody';
413
+ state.colliderById.delete(command.objectId);
414
+ state.idByCollider.delete(held.collider);
415
+ return 'Complete';
416
+ }
417
+ function executeSetJoint(state, command) {
418
+ if (command.byteLength !== Physics3DAbiCommandByteLength.SetJoint ||
419
+ !isObjectId(command.objectId) ||
420
+ command.relatedId !== 0) {
421
+ return 'InvalidCommand';
422
+ }
423
+ const kind = command.view.getUint32(command.payload, true);
424
+ if (kind < Physics3DAbiJointKind.BallAndSocket || kind > Physics3DAbiJointKind.Generic6Dof) {
425
+ return 'UnsupportedJoint';
426
+ }
427
+ const bodyAId = command.view.getUint32(command.payload + 4, true);
428
+ const bodyBId = command.view.getUint32(command.payload + 8, true);
429
+ if (!isObjectId(bodyAId) || !isObjectId(bodyBId))
430
+ return 'InvalidCommand';
431
+ const bodyA = state.bodyById.get(bodyAId);
432
+ const bodyB = state.bodyById.get(bodyBId);
433
+ if (bodyA === undefined || bodyB === undefined)
434
+ return 'MissingBody';
435
+ const flags = command.view.getUint32(command.payload + 12, true);
436
+ if ((flags & getJointFlagMask(kind)) !== flags)
437
+ return 'InvalidCommand';
438
+ const common = readFloat64Values(command, 16, state.jointCommonValues);
439
+ const values = readFloat64Values(command, 144, state.jointKindValues);
440
+ if (!isJointValueBlockValid(kind, common, values))
441
+ return 'RejectedMutation';
442
+ const joint = createJoint(kind, bodyA.index, bodyB.index, flags, common, values);
443
+ if (joint === null)
444
+ return 'UnsupportedJoint';
445
+ joint.broken = (flags & (1 << 1)) !== 0;
446
+ const previous = state.jointById.get(command.objectId);
447
+ if (previous !== undefined) {
448
+ removePhysics3DJoint(state.world, previous);
449
+ state.idByJoint.delete(previous);
450
+ }
451
+ addPhysics3DJoint(state.world, joint);
452
+ state.jointById.set(command.objectId, joint);
453
+ state.idByJoint.set(joint, command.objectId);
454
+ if (previous === undefined)
455
+ insertSorted(state.jointIds, command.objectId);
456
+ return 'Complete';
457
+ }
458
+ function executeDestroyJoint(state, command) {
459
+ if (command.byteLength !== Physics3DAbiCommandByteLength.DestroyJoint ||
460
+ !isObjectId(command.objectId) ||
461
+ command.relatedId !== 0) {
462
+ return 'InvalidCommand';
463
+ }
464
+ const joint = state.jointById.get(command.objectId);
465
+ if (joint === undefined)
466
+ return 'MissingJoint';
467
+ removePhysics3DJoint(state.world, joint);
468
+ state.jointById.delete(command.objectId);
469
+ state.idByJoint.delete(joint);
470
+ removeSorted(state.jointIds, command.objectId);
471
+ return 'Complete';
472
+ }
473
+ function executeBodyAction(state, command, action) {
474
+ if (command.byteLength !== Physics3DAbiCommandByteLength.BodyAction ||
475
+ !isObjectId(command.objectId) ||
476
+ command.relatedId !== 0) {
477
+ return 'InvalidCommand';
478
+ }
479
+ const body = state.bodyById.get(command.objectId);
480
+ if (body === undefined)
481
+ return 'MissingBody';
482
+ return action(body, command.view.getFloat64(command.payload, true), command.view.getFloat64(command.payload + 8, true), command.view.getFloat64(command.payload + 16, true))
483
+ ? 'Complete'
484
+ : 'RejectedMutation';
485
+ }
486
+ function executeBodyPointAction(state, command, action) {
487
+ if (command.byteLength !== Physics3DAbiCommandByteLength.BodyAction ||
488
+ !isObjectId(command.objectId) ||
489
+ command.relatedId !== 0) {
490
+ return 'InvalidCommand';
491
+ }
492
+ const body = state.bodyById.get(command.objectId);
493
+ if (body === undefined)
494
+ return 'MissingBody';
495
+ return action(body, command.view.getFloat64(command.payload, true), command.view.getFloat64(command.payload + 8, true), command.view.getFloat64(command.payload + 16, true), command.view.getFloat64(command.payload + 24, true), command.view.getFloat64(command.payload + 32, true), command.view.getFloat64(command.payload + 40, true))
496
+ ? 'Complete'
497
+ : 'RejectedMutation';
498
+ }
499
+ function executeWakeBody(state, command) {
500
+ if (command.byteLength !== Physics3DAbiCommandByteLength.WakeBody ||
501
+ !isObjectId(command.objectId) ||
502
+ command.relatedId !== 0) {
503
+ return 'InvalidCommand';
504
+ }
505
+ const body = state.bodyById.get(command.objectId);
506
+ if (body === undefined)
507
+ return 'MissingBody';
508
+ wakePhysics3DBody(body);
509
+ return 'Complete';
510
+ }
511
+ function createJoint(kind, bodyA, bodyB, flags, common, values) {
512
+ const options = {
513
+ bodyA,
514
+ bodyB,
515
+ localAnchorAX: common[0],
516
+ localAnchorAY: common[1],
517
+ localAnchorAZ: common[2],
518
+ localAnchorBX: common[3],
519
+ localAnchorBY: common[4],
520
+ localAnchorBZ: common[5],
521
+ breakForce: common[6],
522
+ breakTorque: common[7],
523
+ collideConnected: (flags & 1) !== 0,
524
+ };
525
+ const frames = {
526
+ ...options,
527
+ localRotationAX: common[8],
528
+ localRotationAY: common[9],
529
+ localRotationAZ: common[10],
530
+ localRotationAW: common[11],
531
+ localRotationBX: common[12],
532
+ localRotationBY: common[13],
533
+ localRotationBZ: common[14],
534
+ localRotationBW: common[15],
535
+ };
536
+ if (kind === Physics3DAbiJointKind.BallAndSocket)
537
+ return createPhysics3DBallAndSocketJoint(options);
538
+ if (kind === Physics3DAbiJointKind.Distance) {
539
+ return createPhysics3DDistanceJoint({
540
+ ...options,
541
+ length: values[0],
542
+ frequencyHz: values[1],
543
+ dampingRatio: values[2],
544
+ minLength: values[3],
545
+ maxLength: values[4],
546
+ enableSpring: (flags & (1 << 2)) !== 0,
547
+ enableLimit: (flags & (1 << 3)) !== 0,
548
+ });
549
+ }
550
+ if (kind === Physics3DAbiJointKind.Fixed)
551
+ return createPhysics3DFixedJoint(frames);
552
+ if (kind === Physics3DAbiJointKind.Hinge) {
553
+ return createPhysics3DHingeJoint({
554
+ ...frames,
555
+ lowerAngle: values[0],
556
+ upperAngle: values[1],
557
+ motorSpeed: values[2],
558
+ maxMotorTorque: values[3],
559
+ limitFrequencyHz: values[4],
560
+ limitDampingRatio: values[5],
561
+ enableLimit: (flags & (1 << 2)) !== 0,
562
+ enableMotor: (flags & (1 << 3)) !== 0,
563
+ enableLimitSpring: (flags & (1 << 4)) !== 0,
564
+ });
565
+ }
566
+ if (kind === Physics3DAbiJointKind.Slider) {
567
+ return createPhysics3DSliderJoint({
568
+ ...frames,
569
+ lowerTranslation: values[0],
570
+ upperTranslation: values[1],
571
+ motorSpeed: values[2],
572
+ maxMotorForce: values[3],
573
+ limitFrequencyHz: values[4],
574
+ limitDampingRatio: values[5],
575
+ enableLimit: (flags & (1 << 2)) !== 0,
576
+ enableMotor: (flags & (1 << 3)) !== 0,
577
+ enableLimitSpring: (flags & (1 << 4)) !== 0,
578
+ });
579
+ }
580
+ if (kind === Physics3DAbiJointKind.ConeTwist) {
581
+ return createPhysics3DConeTwistJoint({
582
+ ...frames,
583
+ swingLimitY: values[0],
584
+ swingLimitZ: values[1],
585
+ lowerTwistAngle: values[2],
586
+ upperTwistAngle: values[3],
587
+ limitFrequencyHz: values[4],
588
+ limitDampingRatio: values[5],
589
+ enableSwingLimit: (flags & (1 << 2)) !== 0,
590
+ enableTwistLimit: (flags & (1 << 3)) !== 0,
591
+ enableLimitSpring: (flags & (1 << 4)) !== 0,
592
+ });
593
+ }
594
+ if (kind === Physics3DAbiJointKind.Generic6Dof) {
595
+ return createPhysics3DGeneric6DofJoint({
596
+ ...frames,
597
+ lowerLinearX: values[0],
598
+ lowerLinearY: values[1],
599
+ lowerLinearZ: values[2],
600
+ upperLinearX: values[3],
601
+ upperLinearY: values[4],
602
+ upperLinearZ: values[5],
603
+ lowerAngularX: values[6],
604
+ lowerAngularY: values[7],
605
+ lowerAngularZ: values[8],
606
+ upperAngularX: values[9],
607
+ upperAngularY: values[10],
608
+ upperAngularZ: values[11],
609
+ limitFrequencyHz: values[12],
610
+ limitDampingRatio: values[13],
611
+ enableLimitSpring: (flags & (1 << 2)) !== 0,
612
+ });
613
+ }
614
+ return null;
615
+ }
616
+ function readShape(command, byteOffset) {
617
+ if (byteOffset + Physics3DAbiShapeHeaderByteLength > command.start + command.byteLength)
618
+ return null;
619
+ const kind = command.view.getUint32(byteOffset, true);
620
+ const scalarCount = command.view.getUint32(byteOffset + 4, true);
621
+ const integerCount = command.view.getUint32(byteOffset + 8, true);
622
+ const version = command.view.getUint32(byteOffset + 12, true);
623
+ if (kind !== Physics3DAbiShapeKind.TriangleMesh && kind !== Physics3DAbiShapeKind.Heightfield && version !== 0) {
624
+ return null;
625
+ }
626
+ const scalarOffset = byteOffset + Physics3DAbiShapeHeaderByteLength;
627
+ const integerOffset = scalarOffset + scalarCount * 8;
628
+ const unalignedShapeEnd = integerOffset + integerCount * 4;
629
+ const shapeEnd = align8(unalignedShapeEnd);
630
+ if (shapeEnd !== command.start + command.byteLength)
631
+ return null;
632
+ for (let i = unalignedShapeEnd; i < shapeEnd; i += 1) {
633
+ if (command.view.getUint8(i) !== 0)
634
+ return null;
635
+ }
636
+ const values = new Array(scalarCount);
637
+ for (let i = 0; i < scalarCount; i += 1)
638
+ values[i] = command.view.getFloat64(scalarOffset + i * 8, true);
639
+ if (!areFinite(values))
640
+ return null;
641
+ const integers = new Array(integerCount);
642
+ for (let i = 0; i < integerCount; i += 1)
643
+ integers[i] = command.view.getUint32(integerOffset + i * 4, true);
644
+ if (kind === Physics3DAbiShapeKind.Sphere && scalarCount === 4 && integerCount === 0) {
645
+ return { kind: 'sphere', x: values[0], y: values[1], z: values[2], radius: values[3] };
646
+ }
647
+ if (kind === Physics3DAbiShapeKind.Aabb && scalarCount === 6 && integerCount === 0) {
648
+ return {
649
+ kind: 'aabb',
650
+ minX: values[0],
651
+ minY: values[1],
652
+ minZ: values[2],
653
+ maxX: values[3],
654
+ maxY: values[4],
655
+ maxZ: values[5],
656
+ };
657
+ }
658
+ if (kind === Physics3DAbiShapeKind.Box && scalarCount === 10 && integerCount === 0) {
659
+ return {
660
+ kind: 'box',
661
+ x: values[0],
662
+ y: values[1],
663
+ z: values[2],
664
+ halfX: values[3],
665
+ halfY: values[4],
666
+ halfZ: values[5],
667
+ rotationX: values[6],
668
+ rotationY: values[7],
669
+ rotationZ: values[8],
670
+ rotationW: values[9],
671
+ };
672
+ }
673
+ if ((kind === Physics3DAbiShapeKind.Capsule || kind === Physics3DAbiShapeKind.Cylinder) &&
674
+ scalarCount === 7 &&
675
+ integerCount === 0) {
676
+ const shape = {
677
+ x0: values[0],
678
+ y0: values[1],
679
+ z0: values[2],
680
+ x1: values[3],
681
+ y1: values[4],
682
+ z1: values[5],
683
+ radius: values[6],
684
+ };
685
+ return kind === Physics3DAbiShapeKind.Capsule ? { kind: 'capsule', ...shape } : { kind: 'cylinder', ...shape };
686
+ }
687
+ if (kind === Physics3DAbiShapeKind.Cone && scalarCount === 7 && integerCount === 0) {
688
+ return {
689
+ kind: 'cone',
690
+ apexX: values[0],
691
+ apexY: values[1],
692
+ apexZ: values[2],
693
+ baseX: values[3],
694
+ baseY: values[4],
695
+ baseZ: values[5],
696
+ radius: values[6],
697
+ };
698
+ }
699
+ if (kind === Physics3DAbiShapeKind.Convex && integerCount === 0)
700
+ return { kind: 'convex', points: values };
701
+ if (kind === Physics3DAbiShapeKind.TriangleMesh && scalarCount >= 7) {
702
+ return {
703
+ kind: 'triangle-mesh',
704
+ version,
705
+ x: values[0],
706
+ y: values[1],
707
+ z: values[2],
708
+ rotationX: values[3],
709
+ rotationY: values[4],
710
+ rotationZ: values[5],
711
+ rotationW: values[6],
712
+ points: values.slice(7),
713
+ indices: integers,
714
+ };
715
+ }
716
+ if (kind === Physics3DAbiShapeKind.Heightfield && scalarCount >= 9 && integerCount === 2) {
717
+ return {
718
+ kind: 'heightfield',
719
+ columns: integers[0],
720
+ rows: integers[1],
721
+ version,
722
+ cellSizeX: values[0],
723
+ cellSizeZ: values[1],
724
+ x: values[2],
725
+ y: values[3],
726
+ z: values[4],
727
+ rotationX: values[5],
728
+ rotationY: values[6],
729
+ rotationZ: values[7],
730
+ rotationW: values[8],
731
+ heights: values.slice(9),
732
+ };
733
+ }
734
+ return null;
735
+ }
736
+ function isShapeValid(shape) {
737
+ if (shape.kind === 'triangle-mesh')
738
+ return getCollisionTriangleMeshValidationStatus3D(shape) === null;
739
+ if (shape.kind === 'heightfield')
740
+ return getCollisionHeightfieldValidationStatus3D(shape) === null;
741
+ return getCollisionShapeValidationStatus3D(shape) === null;
742
+ }
743
+ function stepReferenceWorld(state, dt, hooks) {
744
+ const world = state.world;
745
+ if (!canStep(world, dt))
746
+ return 'Declined';
747
+ if (hooks !== null && (hooks.preSolve !== null || hooks.postSolve !== null) && !hasHookCapacity(hooks.buffer)) {
748
+ return 'InsufficientHookBuffer';
749
+ }
750
+ const previousPreSolve = world.contactHooks.preSolve;
751
+ const previousPostSolve = world.contactHooks.postSolve;
752
+ state.stepping = true;
753
+ state.activeHooks = hooks;
754
+ world.contactHooks.preSolve = hooks?.preSolve === null || hooks === null ? null : state.preSolveHook;
755
+ world.contactHooks.postSolve = hooks?.postSolve === null || hooks === null ? null : state.postSolveHook;
756
+ try {
757
+ stepPhysics3D(world, dt);
758
+ }
759
+ finally {
760
+ world.contactHooks.preSolve = previousPreSolve;
761
+ world.contactHooks.postSolve = previousPostSolve;
762
+ state.activeHooks = null;
763
+ state.stepping = false;
764
+ }
765
+ return 'Complete';
766
+ }
767
+ function canStep(world, dt) {
768
+ return (isPhysics3DTimestepValid(dt) &&
769
+ isPhysics3DSubstepsValid(world.config) &&
770
+ isPhysics3DVelocityIterationsValid(world.config) &&
771
+ isPhysics3DPositionIterationsValid(world.config) &&
772
+ isPhysics3DSolverConfigValid(world.config) &&
773
+ isPhysics3DGravityValid(world) &&
774
+ isPhysics3DBodyStateValid(world) &&
775
+ isPhysics3DColliderStateValid(world) &&
776
+ isPhysics3DContactStateValid(world) &&
777
+ isPhysics3DJointStateValid(world));
778
+ }
779
+ function hasHookCapacity(buffer) {
780
+ return (getContactCapacity(buffer) >= 1 &&
781
+ buffer.pointFeatureIds.length >= 4 &&
782
+ buffer.pointValues.length >= 4 * Physics3DAbiContactPointValueStride);
783
+ }
784
+ function invokeContactHook(state, contact, buffer, hook) {
785
+ clearContactBuffer(buffer);
786
+ writeContact(state, contact, buffer, 0, 0);
787
+ buffer.count = 1;
788
+ buffer.pointCount = contact.pointCount;
789
+ buffer.requiredCount = 1;
790
+ buffer.requiredPointCount = contact.pointCount;
791
+ hook(buffer);
792
+ const values = 0;
793
+ const flags = buffer.flags[0];
794
+ const friction = buffer.values[values + 3];
795
+ const restitution = buffer.values[values + 4];
796
+ if (!Number.isFinite(friction) || friction < 0 || !Number.isFinite(restitution) || restitution < 0) {
797
+ throw new Error('Physics3D ABI contact hook produced invalid contact values');
798
+ }
799
+ contact.enabled = (flags & Physics3DAbiContactFlag.Enabled) !== 0;
800
+ contact.friction = friction;
801
+ contact.restitution = restitution;
802
+ }
803
+ function readBodies(state, bodyIds, out) {
804
+ out.count = 0;
805
+ out.requiredCount = 0;
806
+ const capacity = Math.min(out.ids.length, out.flags.length, Math.floor(out.values.length / Physics3DAbiBodyValueStride));
807
+ if (bodyIds === null) {
808
+ out.requiredCount = state.bodyIds.length;
809
+ for (let i = 0; i < state.bodyIds.length && out.count < capacity; i += 1) {
810
+ const id = state.bodyIds[i];
811
+ const body = state.bodyById.get(id);
812
+ if (body === undefined)
813
+ continue;
814
+ writeBody(id, body, out, out.count);
815
+ out.count += 1;
816
+ }
817
+ return;
818
+ }
819
+ for (let i = 0; i < bodyIds.length; i += 1) {
820
+ const id = bodyIds[i];
821
+ const body = state.bodyById.get(id);
822
+ if (body === undefined)
823
+ continue;
824
+ out.requiredCount += 1;
825
+ if (out.count >= capacity)
826
+ continue;
827
+ writeBody(id, body, out, out.count);
828
+ out.count += 1;
829
+ }
830
+ }
831
+ function readContacts(state, selection, out) {
832
+ clearContactBuffer(out);
833
+ const contacts = selection === 'All'
834
+ ? state.world.contacts
835
+ : selection === 'Began'
836
+ ? state.world.events.began
837
+ : state.world.events.ended;
838
+ const contactCapacity = getContactCapacity(out);
839
+ const pointCapacity = Math.min(out.pointFeatureIds.length, Math.floor(out.pointValues.length / Physics3DAbiContactPointValueStride));
840
+ let prefixFits = true;
841
+ for (let i = 0; i < contacts.length; i += 1) {
842
+ const contact = contacts[i];
843
+ out.requiredCount += 1;
844
+ out.requiredPointCount += contact.pointCount;
845
+ if (!prefixFits || out.count >= contactCapacity || out.pointCount + contact.pointCount > pointCapacity) {
846
+ prefixFits = false;
847
+ continue;
848
+ }
849
+ writeContact(state, contact, out, out.count, out.pointCount);
850
+ out.count += 1;
851
+ out.pointCount += contact.pointCount;
852
+ }
853
+ }
854
+ function readJoints(state, out) {
855
+ out.count = 0;
856
+ out.requiredCount = state.jointIds.length;
857
+ const capacity = Math.min(out.ids.length, out.flags.length, Math.floor(out.values.length / Physics3DAbiJointValueStride));
858
+ for (let i = 0; i < state.jointIds.length; i += 1) {
859
+ if (out.count >= capacity)
860
+ break;
861
+ const id = state.jointIds[i];
862
+ const joint = state.jointById.get(id);
863
+ if (joint === undefined)
864
+ continue;
865
+ const at = out.count;
866
+ out.ids[at] = id;
867
+ out.flags[at] = joint.broken ? Physics3DAbiJointFlag.Broken : 0;
868
+ writePhysics3DJointReaction(state.world, joint, state.world.previousTimestep, state.reaction);
869
+ const valueAt = at * Physics3DAbiJointValueStride;
870
+ out.values[valueAt] = state.reaction.forceX;
871
+ out.values[valueAt + 1] = state.reaction.forceY;
872
+ out.values[valueAt + 2] = state.reaction.forceZ;
873
+ out.values[valueAt + 3] = state.reaction.torqueX;
874
+ out.values[valueAt + 4] = state.reaction.torqueY;
875
+ out.values[valueAt + 5] = state.reaction.torqueZ;
876
+ out.count += 1;
877
+ }
878
+ }
879
+ function writeBody(id, body, out, at) {
880
+ out.ids[at] = id;
881
+ out.flags[at] = encodeBodyFlags(body);
882
+ const valueAt = at * Physics3DAbiBodyValueStride;
883
+ out.values[valueAt] = body.x;
884
+ out.values[valueAt + 1] = body.y;
885
+ out.values[valueAt + 2] = body.z;
886
+ out.values[valueAt + 3] = body.orientationX;
887
+ out.values[valueAt + 4] = body.orientationY;
888
+ out.values[valueAt + 5] = body.orientationZ;
889
+ out.values[valueAt + 6] = body.orientationW;
890
+ out.values[valueAt + 7] = body.velocityX;
891
+ out.values[valueAt + 8] = body.velocityY;
892
+ out.values[valueAt + 9] = body.velocityZ;
893
+ out.values[valueAt + 10] = body.angularVelocityX;
894
+ out.values[valueAt + 11] = body.angularVelocityY;
895
+ out.values[valueAt + 12] = body.angularVelocityZ;
896
+ out.values[valueAt + 13] = body.forceX;
897
+ out.values[valueAt + 14] = body.forceY;
898
+ out.values[valueAt + 15] = body.forceZ;
899
+ out.values[valueAt + 16] = body.torqueX;
900
+ out.values[valueAt + 17] = body.torqueY;
901
+ out.values[valueAt + 18] = body.torqueZ;
902
+ out.values[valueAt + 19] = body.mass;
903
+ out.values[valueAt + 20] = body.inertiaXX;
904
+ out.values[valueAt + 21] = body.inertiaYY;
905
+ out.values[valueAt + 22] = body.inertiaZZ;
906
+ out.values[valueAt + 23] = body.inertiaXY;
907
+ out.values[valueAt + 24] = body.inertiaXZ;
908
+ out.values[valueAt + 25] = body.inertiaYZ;
909
+ out.values[valueAt + 26] = body.centerX;
910
+ out.values[valueAt + 27] = body.centerY;
911
+ out.values[valueAt + 28] = body.centerZ;
912
+ out.values[valueAt + 29] = body.linearDamping;
913
+ out.values[valueAt + 30] = body.angularDamping;
914
+ out.values[valueAt + 31] = body.gravityScale;
915
+ out.values[valueAt + 32] = body.sleepTimer;
916
+ }
917
+ function writeContact(state, contact, out, at, pointAt) {
918
+ const bodyA = state.world.bodyByIndex.get(contact.bodyA);
919
+ const bodyB = state.world.bodyByIndex.get(contact.bodyB);
920
+ const colliderA = bodyA?.colliders[contact.colliderA];
921
+ const colliderB = bodyB?.colliders[contact.colliderB];
922
+ const idAt = at * Physics3DAbiContactIdStride;
923
+ out.ids[idAt] = bodyA === undefined ? 0 : (state.idByBody.get(bodyA) ?? 0);
924
+ out.ids[idAt + 1] = bodyB === undefined ? 0 : (state.idByBody.get(bodyB) ?? 0);
925
+ out.ids[idAt + 2] = colliderA === undefined ? 0 : (state.idByCollider.get(colliderA) ?? 0);
926
+ out.ids[idAt + 3] = colliderB === undefined ? 0 : (state.idByCollider.get(colliderB) ?? 0);
927
+ let flags = 0;
928
+ if (contact.enabled)
929
+ flags |= Physics3DAbiContactFlag.Enabled;
930
+ if (contact.sensor)
931
+ flags |= Physics3DAbiContactFlag.Sensor;
932
+ if (contact.touching)
933
+ flags |= Physics3DAbiContactFlag.Touching;
934
+ out.flags[at] = flags;
935
+ out.pointStarts[at] = pointAt;
936
+ out.pointCounts[at] = contact.pointCount;
937
+ const valueAt = at * Physics3DAbiContactValueStride;
938
+ out.values[valueAt] = contact.normalX;
939
+ out.values[valueAt + 1] = contact.normalY;
940
+ out.values[valueAt + 2] = contact.normalZ;
941
+ out.values[valueAt + 3] = contact.friction;
942
+ out.values[valueAt + 4] = contact.restitution;
943
+ for (let i = 0; i < contact.pointCount; i += 1) {
944
+ const point = contact.points[i];
945
+ const destination = pointAt + i;
946
+ out.pointFeatureIds[destination] = point.featureId >>> 0;
947
+ const pointValueAt = destination * Physics3DAbiContactPointValueStride;
948
+ out.pointValues[pointValueAt] = point.x;
949
+ out.pointValues[pointValueAt + 1] = point.y;
950
+ out.pointValues[pointValueAt + 2] = point.z;
951
+ out.pointValues[pointValueAt + 3] = point.depth;
952
+ out.pointValues[pointValueAt + 4] = point.rAX;
953
+ out.pointValues[pointValueAt + 5] = point.rAY;
954
+ out.pointValues[pointValueAt + 6] = point.rAZ;
955
+ out.pointValues[pointValueAt + 7] = point.rBX;
956
+ out.pointValues[pointValueAt + 8] = point.rBY;
957
+ out.pointValues[pointValueAt + 9] = point.rBZ;
958
+ }
959
+ }
960
+ function clearContactBuffer(out) {
961
+ out.count = 0;
962
+ out.pointCount = 0;
963
+ out.requiredCount = 0;
964
+ out.requiredPointCount = 0;
965
+ }
966
+ function getContactCapacity(out) {
967
+ return Math.min(out.flags.length, out.pointStarts.length, out.pointCounts.length, Math.floor(out.ids.length / Physics3DAbiContactIdStride), Math.floor(out.values.length / Physics3DAbiContactValueStride));
968
+ }
969
+ function writeQueryHits(state, source, out) {
970
+ clearQueryBuffer(out, source.hitCount);
971
+ const capacity = getQueryCapacity(out);
972
+ for (let i = 0; i < source.hitCount && i < capacity; i += 1) {
973
+ const hit = source.hits[i];
974
+ writeQueryIdentity(state, hit.body, hit.collider, out, i);
975
+ clearQueryValues(out, i);
976
+ out.count += 1;
977
+ }
978
+ }
979
+ function writeRayHits(state, out) {
980
+ clearQueryBuffer(out, state.ray.hitCount);
981
+ const capacity = getQueryCapacity(out);
982
+ for (let i = 0; i < state.ray.hitCount && i < capacity; i += 1) {
983
+ const hit = state.ray.hits[i];
984
+ writeQueryIdentity(state, hit.body, hit.collider, out, i);
985
+ writeQueryValues(out, i, hit.fraction, hit.x, hit.y, hit.z, hit.normalX, hit.normalY, hit.normalZ);
986
+ out.count += 1;
987
+ }
988
+ }
989
+ function writeShapeCastHit(state, out) {
990
+ const hit = state.shapeCast;
991
+ clearQueryBuffer(out, hit.hit ? 1 : 0);
992
+ if (!hit.hit || getQueryCapacity(out) === 0 || hit.body === null || hit.collider === null)
993
+ return;
994
+ writeQueryIdentity(state, hit.body, hit.collider, out, 0);
995
+ writeQueryValues(out, 0, hit.fraction, hit.x, hit.y, hit.z, hit.normalX, hit.normalY, hit.normalZ);
996
+ out.count = 1;
997
+ }
998
+ function writeQueryIdentity(state, body, collider, out, at) {
999
+ out.bodyIds[at] = state.idByBody.get(body) ?? 0;
1000
+ out.colliderIds[at] = state.idByCollider.get(collider) ?? 0;
1001
+ }
1002
+ function clearQueryBuffer(out, requiredCount) {
1003
+ out.count = 0;
1004
+ out.requiredCount = requiredCount;
1005
+ }
1006
+ function clearQueryValues(out, at) {
1007
+ const valueAt = at * Physics3DAbiQueryValueStride;
1008
+ for (let i = 0; i < Physics3DAbiQueryValueStride; i += 1)
1009
+ out.values[valueAt + i] = 0;
1010
+ }
1011
+ function writeQueryValues(out, at, fraction, x, y, z, normalX, normalY, normalZ) {
1012
+ const valueAt = at * Physics3DAbiQueryValueStride;
1013
+ out.values[valueAt] = fraction;
1014
+ out.values[valueAt + 1] = x;
1015
+ out.values[valueAt + 2] = y;
1016
+ out.values[valueAt + 3] = z;
1017
+ out.values[valueAt + 4] = normalX;
1018
+ out.values[valueAt + 5] = normalY;
1019
+ out.values[valueAt + 6] = normalZ;
1020
+ }
1021
+ function getQueryCapacity(out) {
1022
+ return Math.min(out.bodyIds.length, out.colliderIds.length, Math.floor(out.values.length / Physics3DAbiQueryValueStride));
1023
+ }
1024
+ function isCommandBufferValid(commands) {
1025
+ if (commands.data.byteLength < Physics3DAbiCommandHeaderByteLength ||
1026
+ !Number.isSafeInteger(commands.byteLength) ||
1027
+ commands.byteLength < Physics3DAbiCommandHeaderByteLength ||
1028
+ commands.byteLength > commands.data.byteLength ||
1029
+ !Number.isSafeInteger(commands.commandCount) ||
1030
+ commands.commandCount < 0 ||
1031
+ commands.commandCount >
1032
+ Math.floor((commands.byteLength - Physics3DAbiCommandHeaderByteLength) / Physics3DAbiCommandRecordHeaderByteLength)) {
1033
+ return false;
1034
+ }
1035
+ const view = new DataView(commands.data.buffer, commands.data.byteOffset, commands.data.byteLength);
1036
+ return (view.getUint32(0, true) === Physics3DAbiCommandMagic &&
1037
+ view.getUint32(4, true) === Physics3DAbiVersion &&
1038
+ view.getUint32(8, true) === commands.byteLength &&
1039
+ view.getUint32(12, true) === commands.commandCount);
1040
+ }
1041
+ function failExecution(out, status, commandIndex, byteOffset, commandKind) {
1042
+ out.status = status;
1043
+ out.commandIndex = commandIndex;
1044
+ out.byteOffset = byteOffset;
1045
+ out.commandKind = commandKind;
1046
+ return false;
1047
+ }
1048
+ function readFloat64Values(command, payloadByteOffset, values) {
1049
+ const byteOffset = command.payload + payloadByteOffset;
1050
+ for (let i = 0; i < values.length; i += 1)
1051
+ values[i] = command.view.getFloat64(byteOffset + i * 8, true);
1052
+ return values;
1053
+ }
1054
+ function decodeBodyType(type) {
1055
+ if (type === Physics3DAbiBodyType.Dynamic)
1056
+ return 'dynamic';
1057
+ if (type === Physics3DAbiBodyType.Kinematic)
1058
+ return 'kinematic';
1059
+ if (type === Physics3DAbiBodyType.Static)
1060
+ return 'static';
1061
+ return null;
1062
+ }
1063
+ function encodeBodyFlags(body) {
1064
+ let flags = body.type === 'kinematic'
1065
+ ? Physics3DAbiBodyType.Kinematic
1066
+ : body.type === 'static'
1067
+ ? Physics3DAbiBodyType.Static
1068
+ : 0;
1069
+ if (body.fixedRotation)
1070
+ flags |= Physics3DAbiBodyFlag.FixedRotation;
1071
+ if (body.bullet)
1072
+ flags |= Physics3DAbiBodyFlag.Bullet;
1073
+ if (body.sleeping)
1074
+ flags |= Physics3DAbiBodyFlag.Sleeping;
1075
+ if (body.sleepEnabled)
1076
+ flags |= Physics3DAbiBodyFlag.SleepEnabled;
1077
+ return flags;
1078
+ }
1079
+ function writeBodyDynamicValues(body, values, flags) {
1080
+ const movable = body.type !== 'static';
1081
+ const dynamic = body.type === 'dynamic';
1082
+ const rotates = movable && !body.fixedRotation;
1083
+ body.velocityX = movable ? values[7] : 0;
1084
+ body.velocityY = movable ? values[8] : 0;
1085
+ body.velocityZ = movable ? values[9] : 0;
1086
+ body.angularVelocityX = rotates ? values[10] : 0;
1087
+ body.angularVelocityY = rotates ? values[11] : 0;
1088
+ body.angularVelocityZ = rotates ? values[12] : 0;
1089
+ body.forceX = dynamic ? values[13] : 0;
1090
+ body.forceY = dynamic ? values[14] : 0;
1091
+ body.forceZ = dynamic ? values[15] : 0;
1092
+ body.torqueX = dynamic && rotates ? values[16] : 0;
1093
+ body.torqueY = dynamic && rotates ? values[17] : 0;
1094
+ body.torqueZ = dynamic && rotates ? values[18] : 0;
1095
+ body.linearDamping = values[29];
1096
+ body.angularDamping = values[30];
1097
+ body.gravityScale = values[31];
1098
+ body.sleepTimer = movable && body.sleepEnabled ? values[32] : 0;
1099
+ body.sleeping = movable && body.sleepEnabled && (flags & Physics3DAbiBodyFlag.Sleeping) !== 0;
1100
+ }
1101
+ function isBodyValueBlockValid(values) {
1102
+ if (!areFinite(values))
1103
+ return false;
1104
+ if (values[19] < 0 || values[29] < 0 || values[30] < 0 || values[32] < 0)
1105
+ return false;
1106
+ const orientationLengthSquared = values[3] * values[3] + values[4] * values[4] + values[5] * values[5] + values[6] * values[6];
1107
+ return orientationLengthSquared > 0;
1108
+ }
1109
+ function isJointValueBlockValid(kind, common, values) {
1110
+ for (let i = 0; i < common.length; i += 1) {
1111
+ if ((i === 6 || i === 7) && common[i] === Number.POSITIVE_INFINITY)
1112
+ continue;
1113
+ if (!Number.isFinite(common[i]))
1114
+ return false;
1115
+ }
1116
+ for (let i = 0; i < values.length; i += 1) {
1117
+ if (kind === Physics3DAbiJointKind.Distance && i === 4 && values[i] === Number.POSITIVE_INFINITY)
1118
+ continue;
1119
+ if (!Number.isFinite(values[i]))
1120
+ return false;
1121
+ }
1122
+ return true;
1123
+ }
1124
+ function areFinite(values) {
1125
+ for (let i = 0; i < values.length; i += 1) {
1126
+ if (!Number.isFinite(values[i]))
1127
+ return false;
1128
+ }
1129
+ return true;
1130
+ }
1131
+ function isObjectId(value) {
1132
+ return Number.isInteger(value) && value > 0 && value <= 0xffffffff;
1133
+ }
1134
+ function getJointFlagMask(kind) {
1135
+ if (kind === Physics3DAbiJointKind.Distance)
1136
+ return 0b1111;
1137
+ if (kind === Physics3DAbiJointKind.Hinge ||
1138
+ kind === Physics3DAbiJointKind.Slider ||
1139
+ kind === Physics3DAbiJointKind.ConeTwist) {
1140
+ return 0b11111;
1141
+ }
1142
+ if (kind === Physics3DAbiJointKind.Generic6Dof)
1143
+ return 0b111;
1144
+ return 0b11;
1145
+ }
1146
+ function insertSorted(values, value) {
1147
+ let at = values.length;
1148
+ while (at > 0 && values[at - 1] > value)
1149
+ at -= 1;
1150
+ values.splice(at, 0, value);
1151
+ }
1152
+ function removeSorted(values, value) {
1153
+ const at = values.indexOf(value);
1154
+ if (at >= 0)
1155
+ values.splice(at, 1);
1156
+ }
1157
+ function align8(value) {
1158
+ return Math.ceil(value / 8) * 8;
1159
+ }
1160
+ const PHYSICS3D_ABI_BODY_FLAG_MASK = Physics3DAbiBodyFlag.TypeMask |
1161
+ Physics3DAbiBodyFlag.FixedRotation |
1162
+ Physics3DAbiBodyFlag.Bullet |
1163
+ Physics3DAbiBodyFlag.Sleeping |
1164
+ Physics3DAbiBodyFlag.SleepEnabled;
1165
+ //# sourceMappingURL=referencePhysics3DAbi.js.map