@opsydyn/effect-three-rapier 0.3.0 → 0.6.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/CHANGELOG.md +43 -0
- package/README.md +61 -0
- package/dist/deterministic.d.ts +7 -0
- package/dist/deterministic.d.ts.map +1 -0
- package/dist/deterministic.js +387 -0
- package/dist/deterministic.js.map +12 -0
- package/dist/engine.d.ts +14 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +160 -27
- package/dist/index.js.map +6 -4
- package/dist/snapshot.d.ts +41 -0
- package/dist/snapshot.d.ts.map +1 -0
- package/dist/worker.d.ts +131 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +361 -0
- package/dist/worker.js.map +11 -0
- package/package.json +21 -4
- package/src/deterministic.ts +33 -0
- package/src/engine.ts +400 -0
- package/src/index.ts +6 -329
- package/src/snapshot.ts +130 -0
- package/src/worker.ts +432 -0
package/dist/index.js
CHANGED
|
@@ -1,13 +1,105 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import RAPIER from "@dimforge/rapier3d-compat";
|
|
3
|
+
|
|
4
|
+
// src/engine.ts
|
|
3
5
|
import { interactionBits } from "@opsydyn/effect-three";
|
|
6
|
+
|
|
7
|
+
// src/snapshot.ts
|
|
8
|
+
var format = 1;
|
|
9
|
+
var encoder = new TextEncoder;
|
|
10
|
+
var decoder = new TextDecoder;
|
|
11
|
+
var writeSnapshot = (index, world) => {
|
|
12
|
+
const parts = [Uint8Array.of(format)];
|
|
13
|
+
const count = (value) => {
|
|
14
|
+
const bytes = new Uint8Array(4);
|
|
15
|
+
new DataView(bytes.buffer).setUint32(0, value, true);
|
|
16
|
+
parts.push(bytes);
|
|
17
|
+
};
|
|
18
|
+
const handle = (value) => {
|
|
19
|
+
const bytes = new Uint8Array(8);
|
|
20
|
+
new DataView(bytes.buffer).setFloat64(0, value, true);
|
|
21
|
+
parts.push(bytes);
|
|
22
|
+
};
|
|
23
|
+
const text = (value) => {
|
|
24
|
+
const bytes = encoder.encode(value);
|
|
25
|
+
count(bytes.length);
|
|
26
|
+
parts.push(bytes);
|
|
27
|
+
};
|
|
28
|
+
count(index.bodies.length);
|
|
29
|
+
for (const body of index.bodies) {
|
|
30
|
+
text(body.key);
|
|
31
|
+
handle(body.handle);
|
|
32
|
+
count(body.colliders.length);
|
|
33
|
+
for (const collider of body.colliders) {
|
|
34
|
+
handle(collider.handle);
|
|
35
|
+
text(collider.part === undefined ? "" : `:${collider.part}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
count(index.joints.length);
|
|
39
|
+
for (const joint of index.joints) {
|
|
40
|
+
text(joint.id);
|
|
41
|
+
handle(joint.handle);
|
|
42
|
+
text(joint.a);
|
|
43
|
+
text(joint.b);
|
|
44
|
+
}
|
|
45
|
+
parts.push(world);
|
|
46
|
+
const out = new Uint8Array(parts.reduce((length, part) => length + part.length, 0));
|
|
47
|
+
let at = 0;
|
|
48
|
+
for (const part of parts) {
|
|
49
|
+
out.set(part, at);
|
|
50
|
+
at += part.length;
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
};
|
|
54
|
+
var readSnapshot = (snapshot) => {
|
|
55
|
+
if (snapshot[0] !== format)
|
|
56
|
+
throw new Error("Not a snapshot of an effect-three Rapier world");
|
|
57
|
+
const view = new DataView(snapshot.buffer, snapshot.byteOffset, snapshot.byteLength);
|
|
58
|
+
let at = 1;
|
|
59
|
+
const count = () => {
|
|
60
|
+
const value = view.getUint32(at, true);
|
|
61
|
+
at += 4;
|
|
62
|
+
return value;
|
|
63
|
+
};
|
|
64
|
+
const handle = () => {
|
|
65
|
+
const value = view.getFloat64(at, true);
|
|
66
|
+
at += 8;
|
|
67
|
+
return value;
|
|
68
|
+
};
|
|
69
|
+
const text = () => {
|
|
70
|
+
const length = count();
|
|
71
|
+
const value = decoder.decode(snapshot.subarray(at, at + length));
|
|
72
|
+
at += length;
|
|
73
|
+
return value;
|
|
74
|
+
};
|
|
75
|
+
function collider() {
|
|
76
|
+
const colliderHandle = handle();
|
|
77
|
+
const part = text();
|
|
78
|
+
return part === "" ? { handle: colliderHandle } : { handle: colliderHandle, part: part.slice(1) };
|
|
79
|
+
}
|
|
80
|
+
function body() {
|
|
81
|
+
const key = text();
|
|
82
|
+
const bodyHandle = handle();
|
|
83
|
+
return { key, handle: bodyHandle, colliders: Array.from({ length: count() }, collider) };
|
|
84
|
+
}
|
|
85
|
+
const bodies = Array.from({ length: count() }, body);
|
|
86
|
+
const joints = Array.from({ length: count() }, () => ({
|
|
87
|
+
id: text(),
|
|
88
|
+
handle: handle(),
|
|
89
|
+
a: text(),
|
|
90
|
+
b: text()
|
|
91
|
+
}));
|
|
92
|
+
return { index: { bodies, joints }, world: snapshot.subarray(at) };
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// src/engine.ts
|
|
4
96
|
var vector = ([x, y, z]) => ({ x, y, z });
|
|
5
97
|
var rotation = ([x, y, z, w]) => ({ x, y, z, w });
|
|
6
|
-
var
|
|
7
|
-
dynamic:
|
|
8
|
-
fixed:
|
|
9
|
-
kinematic:
|
|
10
|
-
};
|
|
98
|
+
var bodyType = (rapier, type) => ({
|
|
99
|
+
dynamic: rapier.RigidBodyType.Dynamic,
|
|
100
|
+
fixed: rapier.RigidBodyType.Fixed,
|
|
101
|
+
kinematic: rapier.RigidBodyType.KinematicPositionBased
|
|
102
|
+
})[type];
|
|
11
103
|
var shapeDesc = (rapier, shape) => {
|
|
12
104
|
switch (shape._tag) {
|
|
13
105
|
case "Cuboid":
|
|
@@ -27,13 +119,13 @@ var shapeDesc = (rapier, shape) => {
|
|
|
27
119
|
}
|
|
28
120
|
};
|
|
29
121
|
var colliderDesc = (rapier, collider) => shapeDesc(rapier, collider.shape).setTranslation(...collider.translation).setRotation(rotation(collider.rotation));
|
|
30
|
-
var reporting = (colliders, body) => {
|
|
122
|
+
var reporting = (rapier, colliders, body) => {
|
|
31
123
|
for (const collider of colliders) {
|
|
32
124
|
if (body.contactForces === null) {
|
|
33
|
-
collider.setActiveEvents(
|
|
125
|
+
collider.setActiveEvents(rapier.ActiveEvents.COLLISION_EVENTS);
|
|
34
126
|
continue;
|
|
35
127
|
}
|
|
36
|
-
collider.setActiveEvents(
|
|
128
|
+
collider.setActiveEvents(rapier.ActiveEvents.COLLISION_EVENTS | rapier.ActiveEvents.CONTACT_FORCE_EVENTS);
|
|
37
129
|
collider.setContactForceEventThreshold(body.contactForces);
|
|
38
130
|
}
|
|
39
131
|
};
|
|
@@ -50,8 +142,8 @@ var surface = (colliders, body) => {
|
|
|
50
142
|
collider.setSolverGroups(interactionBits(body.solverGroups));
|
|
51
143
|
}
|
|
52
144
|
};
|
|
53
|
-
var motion = (rigidBody, body) => {
|
|
54
|
-
rigidBody.setBodyType(
|
|
145
|
+
var motion = (rapier, rigidBody, body) => {
|
|
146
|
+
rigidBody.setBodyType(bodyType(rapier, body.type), true);
|
|
55
147
|
rigidBody.setLinearDamping(body.linearDamping);
|
|
56
148
|
rigidBody.setAngularDamping(body.angularDamping);
|
|
57
149
|
rigidBody.setGravityScale(body.gravityScale, true);
|
|
@@ -59,13 +151,13 @@ var motion = (rigidBody, body) => {
|
|
|
59
151
|
};
|
|
60
152
|
var limitsOf = (joint) => joint.kind._tag === "Revolute" || joint.kind._tag === "Prismatic" ? joint.kind.limits : null;
|
|
61
153
|
var motorOf = (joint) => joint.kind._tag === "Revolute" || joint.kind._tag === "Prismatic" ? joint.kind.motor : null;
|
|
62
|
-
var drive = (made, motor) => {
|
|
63
|
-
if (motor !== null && made instanceof
|
|
154
|
+
var drive = (rapier, made, motor) => {
|
|
155
|
+
if (motor !== null && made instanceof rapier.UnitImpulseJoint) {
|
|
64
156
|
made.configureMotor(motor.position, motor.velocity, motor.stiffness, motor.damping);
|
|
65
157
|
}
|
|
66
158
|
};
|
|
67
|
-
var limit = (made, limits) => {
|
|
68
|
-
if (limits !== null && made instanceof
|
|
159
|
+
var limit = (rapier, made, limits) => {
|
|
160
|
+
if (limits !== null && made instanceof rapier.UnitImpulseJoint)
|
|
69
161
|
made.setLimits(...limits);
|
|
70
162
|
};
|
|
71
163
|
var jointData = (rapier, joint) => {
|
|
@@ -93,18 +185,26 @@ var pair = (a, b) => ({
|
|
|
93
185
|
...a.part === undefined ? {} : { aPart: a.part },
|
|
94
186
|
...b.part === undefined ? {} : { bPart: b.part }
|
|
95
187
|
});
|
|
96
|
-
var
|
|
97
|
-
const world = new rapier.World(vector(initial.gravity));
|
|
188
|
+
var hostWorld = (rapier) => (world, index = { bodies: [], joints: [] }) => {
|
|
98
189
|
const events = new rapier.EventQueue(true);
|
|
99
|
-
const bodies = new Map
|
|
100
|
-
|
|
101
|
-
|
|
190
|
+
const bodies = new Map(index.bodies.map((body) => [
|
|
191
|
+
body.key,
|
|
192
|
+
{
|
|
193
|
+
rigidBody: world.getRigidBody(body.handle),
|
|
194
|
+
colliders: body.colliders.map((collider) => world.getCollider(collider.handle))
|
|
195
|
+
}
|
|
196
|
+
]));
|
|
197
|
+
const keysByCollider = new Map(index.bodies.flatMap(({ key, colliders }) => colliders.map(({ handle, part }) => [handle, part === undefined ? { key } : { key, part }])));
|
|
198
|
+
const joints = new Map(index.joints.map(({ id, handle, a, b }) => [
|
|
199
|
+
id,
|
|
200
|
+
{ joint: world.getImpulseJoint(handle), a, b }
|
|
201
|
+
]));
|
|
102
202
|
const add = (key, body, colliders, pose) => {
|
|
103
|
-
const desc = new rapier.RigidBodyDesc(
|
|
203
|
+
const desc = new rapier.RigidBodyDesc(bodyType(rapier, body.type)).setTranslation(...pose.position).setRotation(rotation(pose.quaternion)).setLinvel(...body.linearVelocity).setAngvel(vector(body.angularVelocity)).setLinearDamping(body.linearDamping).setAngularDamping(body.angularDamping).setGravityScale(body.gravityScale).setCcdEnabled(body.ccd);
|
|
104
204
|
const rigidBody = world.createRigidBody(desc);
|
|
105
205
|
const made = colliders.map((collider) => world.createCollider(colliderDesc(rapier, collider), rigidBody));
|
|
106
206
|
surface(made, body);
|
|
107
|
-
reporting(made, body);
|
|
207
|
+
reporting(rapier, made, body);
|
|
108
208
|
bodies.set(key, { rigidBody, colliders: made });
|
|
109
209
|
made.forEach((collider, i) => {
|
|
110
210
|
const part = colliders[i]?.part;
|
|
@@ -129,8 +229,8 @@ var createWorld = (rapier) => (initial) => {
|
|
|
129
229
|
if (first === undefined || second === undefined)
|
|
130
230
|
return;
|
|
131
231
|
const made = world.createImpulseJoint(jointData(rapier, joint), first.rigidBody, second.rigidBody, true);
|
|
132
|
-
limit(made, limitsOf(joint));
|
|
133
|
-
drive(made, motorOf(joint));
|
|
232
|
+
limit(rapier, made, limitsOf(joint));
|
|
233
|
+
drive(rapier, made, motorOf(joint));
|
|
134
234
|
made.setContactsEnabled(joint.contacts);
|
|
135
235
|
joints.set(id, { joint: made, a, b });
|
|
136
236
|
};
|
|
@@ -168,6 +268,10 @@ var createWorld = (rapier) => (initial) => {
|
|
|
168
268
|
});
|
|
169
269
|
}
|
|
170
270
|
const drainForces = () => events.drainContactForceEvents(recordForce);
|
|
271
|
+
function indexed(collider) {
|
|
272
|
+
const part = keysByCollider.get(collider.handle)?.part;
|
|
273
|
+
return part === undefined ? { handle: collider.handle } : { handle: collider.handle, part };
|
|
274
|
+
}
|
|
171
275
|
return {
|
|
172
276
|
configure: (physics) => {
|
|
173
277
|
world.gravity = vector(physics.gravity);
|
|
@@ -177,9 +281,9 @@ var createWorld = (rapier) => (initial) => {
|
|
|
177
281
|
const held = bodies.get(key);
|
|
178
282
|
if (held === undefined)
|
|
179
283
|
return;
|
|
180
|
-
motion(held.rigidBody, body);
|
|
284
|
+
motion(rapier, held.rigidBody, body);
|
|
181
285
|
surface(held.colliders, body);
|
|
182
|
-
reporting(held.colliders, body);
|
|
286
|
+
reporting(rapier, held.colliders, body);
|
|
183
287
|
},
|
|
184
288
|
teleport: (key, pose) => {
|
|
185
289
|
const held = bodies.get(key);
|
|
@@ -233,6 +337,19 @@ var createWorld = (rapier) => (initial) => {
|
|
|
233
337
|
}
|
|
234
338
|
return false;
|
|
235
339
|
},
|
|
340
|
+
snapshot: () => writeSnapshot({
|
|
341
|
+
bodies: [...bodies].map(([key, held]) => ({
|
|
342
|
+
key,
|
|
343
|
+
handle: held.rigidBody.handle,
|
|
344
|
+
colliders: held.colliders.map(indexed)
|
|
345
|
+
})),
|
|
346
|
+
joints: [...joints].map(([id, { joint, a, b }]) => ({
|
|
347
|
+
id,
|
|
348
|
+
handle: joint.handle,
|
|
349
|
+
a,
|
|
350
|
+
b
|
|
351
|
+
}))
|
|
352
|
+
}, world.takeSnapshot()),
|
|
236
353
|
dispose: () => {
|
|
237
354
|
bodies.clear();
|
|
238
355
|
keysByCollider.clear();
|
|
@@ -242,13 +359,29 @@ var createWorld = (rapier) => (initial) => {
|
|
|
242
359
|
}
|
|
243
360
|
};
|
|
244
361
|
};
|
|
362
|
+
var engineOf = (rapier) => {
|
|
363
|
+
const host = hostWorld(rapier);
|
|
364
|
+
return {
|
|
365
|
+
createWorld: (initial) => host(new rapier.World(vector(initial.gravity))),
|
|
366
|
+
restoreWorld: (_physics, snapshot) => {
|
|
367
|
+
const { index, world } = readSnapshot(snapshot);
|
|
368
|
+
return {
|
|
369
|
+
world: host(rapier.World.restoreSnapshot(world), index),
|
|
370
|
+
bodies: index.bodies.map((body) => body.key),
|
|
371
|
+
joints: index.joints.map((joint) => joint.id)
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
// src/index.ts
|
|
245
378
|
var loadRapier = async () => {
|
|
246
379
|
await RAPIER.init();
|
|
247
|
-
return
|
|
380
|
+
return engineOf(RAPIER);
|
|
248
381
|
};
|
|
249
382
|
export {
|
|
250
383
|
loadRapier
|
|
251
384
|
};
|
|
252
385
|
|
|
253
|
-
//# debugId=
|
|
386
|
+
//# debugId=BF71FE688A93448964756E2164756E21
|
|
254
387
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/index.ts"],
|
|
3
|
+
"sources": ["../src/index.ts", "../src/engine.ts", "../src/snapshot.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * Rapier physics for `@opsydyn/effect-three`: a `PhysicsEngine` that the scene graph\n * steps. Load it once, before making the environment, and pass it on:\n *\n * ```ts\n * const physics = await loadRapier();\n * const environment = EffectThreeFoldkit.makeEnvironment(window, { physics });\n * ```\n *\n * Bodies are described on meshes (`body()`) under a scene's `physics()`; this package\n * only turns those descriptions into Rapier bodies and colliders, as react-three-rapier's\n * `RigidBody` does (`ae5c3fe`, `src/utils/utils-rigidbody.ts` and `utils-collider.ts`),\n * and joints into impulse joints, as its joint hooks do (`src/hooks/joints.ts`).\n *\n * Rapier (`@dimforge/rapier3d-compat`) is Apache-2.0; its WebAssembly is embedded, so\n * nothing extra is fetched.\n *\n * @module\n */\nimport RAPIER from '@dimforge/rapier3d-compat';\nimport { interactionBits } from '@opsydyn/effect-three';\nimport type {\n Body,\n BodyPose,\n Collider,\n ColliderShape,\n Collision,\n Physics,\n ContactForce,\n JointLimits,\n JointMotor,\n PhysicsEngine,\n PhysicsJoint,\n PhysicsWorld,\n Vec3,\n} from '@opsydyn/effect-three';\n\ntype Rapier = typeof RAPIER;\n\nconst vector = ([x, y, z]: Vec3) => ({ x, y, z });\n\nconst rotation = ([x, y, z, w]: BodyPose['quaternion']) => ({ x, y, z, w });\n\n/** Body types by our names. Kinematic bodies are position based, as react-three-rapier's default. */\nconst bodyTypes = {\n dynamic: RAPIER.RigidBodyType.Dynamic,\n fixed: RAPIER.RigidBodyType.Fixed,\n kinematic: RAPIER.RigidBodyType.KinematicPositionBased,\n} satisfies Record<Body['type'], RAPIER.RigidBodyType>;\n\n/** The collider description for a shape; a hull Rapier cannot build becomes a small ball. */\nconst shapeDesc = (rapier: Rapier, shape: ColliderShape): RAPIER.ColliderDesc => {\n switch (shape._tag) {\n case 'Cuboid':\n return rapier.ColliderDesc.cuboid(...shape.halfExtents);\n case 'Ball':\n return rapier.ColliderDesc.ball(shape.radius);\n case 'Hull':\n return rapier.ColliderDesc.convexHull(shape.points) ?? rapier.ColliderDesc.ball(1e-3);\n case 'Capsule':\n return rapier.ColliderDesc.capsule(shape.halfHeight, shape.radius);\n case 'Cylinder':\n return rapier.ColliderDesc.cylinder(shape.halfHeight, shape.radius);\n case 'Cone':\n return rapier.ColliderDesc.cone(shape.halfHeight, shape.radius);\n case 'Trimesh':\n return rapier.ColliderDesc.trimesh(shape.vertices, shape.indices);\n }\n};\n\n/** A collider placed in its body. */\nconst colliderDesc = (rapier: Rapier, collider: Collider): RAPIER.ColliderDesc =>\n shapeDesc(rapier, collider.shape)\n .setTranslation(...collider.translation)\n .setRotation(rotation(collider.rotation));\n\n/**\n * The events a body's colliders report: collisions always, contact forces over its\n * threshold when it has one (react-three-rapier's `onContactForce` turns on\n * `CONTACT_FORCE_EVENTS`).\n */\nconst reporting = (colliders: ReadonlyArray<RAPIER.Collider>, body: Body): void => {\n for (const collider of colliders) {\n if (body.contactForces === null) {\n collider.setActiveEvents(RAPIER.ActiveEvents.COLLISION_EVENTS);\n continue;\n }\n collider.setActiveEvents(\n RAPIER.ActiveEvents.COLLISION_EVENTS | RAPIER.ActiveEvents.CONTACT_FORCE_EVENTS,\n );\n collider.setContactForceEventThreshold(body.contactForces);\n }\n};\n\n/**\n * Applies a body's surface and mass settings to its colliders. A given mass is shared\n * among them; otherwise each has density 1.\n */\nconst surface = (colliders: ReadonlyArray<RAPIER.Collider>, body: Body): void => {\n for (const collider of colliders) {\n collider.setFriction(body.friction);\n collider.setRestitution(body.restitution);\n collider.setSensor(body.sensor);\n if (body.mass === null) collider.setDensity(1);\n else collider.setMass(body.mass / colliders.length);\n collider.setCollisionGroups(interactionBits(body.collisionGroups));\n collider.setSolverGroups(interactionBits(body.solverGroups));\n }\n};\n\n/** Applies a body's motion settings. */\nconst motion = (rigidBody: RAPIER.RigidBody, body: Body): void => {\n rigidBody.setBodyType(bodyTypes[body.type], true);\n rigidBody.setLinearDamping(body.linearDamping);\n rigidBody.setAngularDamping(body.angularDamping);\n rigidBody.setGravityScale(body.gravityScale, true);\n rigidBody.enableCcd(body.ccd);\n};\n\n/** The limits a joint has, if it is a hinge or slider with limits. */\nconst limitsOf = (joint: PhysicsJoint): JointLimits | null =>\n joint.kind._tag === 'Revolute' || joint.kind._tag === 'Prismatic' ? joint.kind.limits : null;\n\n/** The motor a joint has, if it is a hinge or slider with one. */\nconst motorOf = (joint: PhysicsJoint): JointMotor | null =>\n joint.kind._tag === 'Revolute' || joint.kind._tag === 'Prismatic' ? joint.kind.motor : null;\n\n/** Drives a hinge or slider once made: Rapier's `configureMotor`, set on the joint. */\nconst drive = (made: RAPIER.ImpulseJoint, motor: JointMotor | null): void => {\n if (motor !== null && made instanceof RAPIER.UnitImpulseJoint) {\n made.configureMotor(motor.position, motor.velocity, motor.stiffness, motor.damping);\n }\n};\n\n/**\n * Limits a hinge or slider once made. React-three-rapier sets them on the joint data, but\n * Rapier's `JointData.intoRaw` (0.21) passes them on for prismatic joints only, so a\n * hinge's would be lost: they are set on the joint instead.\n */\nconst limit = (made: RAPIER.ImpulseJoint, limits: JointLimits | null): void => {\n if (limits !== null && made instanceof RAPIER.UnitImpulseJoint) made.setLimits(...limits);\n};\n\n/** Rapier's joint data for a joint, anchors in each body's space. */\nconst jointData = (rapier: Rapier, joint: PhysicsJoint): RAPIER.JointData => {\n const a = vector(joint.anchorA);\n const b = vector(joint.anchorB);\n const { kind } = joint;\n switch (kind._tag) {\n case 'Fixed':\n return rapier.JointData.fixed(a, rotation(kind.frameA), b, rotation(kind.frameB));\n case 'Spherical':\n return rapier.JointData.spherical(a, b);\n case 'Revolute':\n return rapier.JointData.revolute(a, b, vector(kind.axis));\n case 'Prismatic':\n return rapier.JointData.prismatic(a, b, vector(kind.axis));\n case 'Rope':\n return rapier.JointData.rope(kind.length, a, b);\n case 'Spring':\n return rapier.JointData.spring(kind.restLength, kind.stiffness, kind.damping, a, b);\n }\n};\n\n/** Which body a collider belongs to, and which part of it, by name. */\ntype Owner = { readonly key: string; readonly part?: string };\n\n/** Two colliders' owners as an event's `a` and `b`, with their parts. */\nconst pair = (a: Owner, b: Owner) => ({\n a: a.key,\n b: b.key,\n ...(a.part === undefined ? {} : { aPart: a.part }),\n ...(b.part === undefined ? {} : { bPart: b.part }),\n});\n\ntype Held = {\n readonly rigidBody: RAPIER.RigidBody;\n readonly colliders: ReadonlyArray<RAPIER.Collider>;\n};\n\nconst createWorld =\n (rapier: Rapier) =>\n (initial: Physics): PhysicsWorld => {\n const world = new rapier.World(vector(initial.gravity));\n const events = new rapier.EventQueue(true);\n const bodies = new Map<string, Held>();\n /** Each collider's body, and the part of it the collider is (when named). */\n const keysByCollider = new Map<number, Owner>();\n const joints = new Map<\n string,\n { readonly joint: RAPIER.ImpulseJoint; readonly a: string; readonly b: string }\n >();\n\n const add: PhysicsWorld['add'] = (key, body, colliders, pose) => {\n const desc = new rapier.RigidBodyDesc(bodyTypes[body.type])\n .setTranslation(...pose.position)\n .setRotation(rotation(pose.quaternion))\n .setLinvel(...body.linearVelocity)\n .setAngvel(vector(body.angularVelocity))\n .setLinearDamping(body.linearDamping)\n .setAngularDamping(body.angularDamping)\n .setGravityScale(body.gravityScale)\n .setCcdEnabled(body.ccd);\n const rigidBody = world.createRigidBody(desc);\n const made = colliders.map((collider) =>\n world.createCollider(colliderDesc(rapier, collider), rigidBody),\n );\n surface(made, body);\n reporting(made, body);\n bodies.set(key, { rigidBody, colliders: made });\n made.forEach((collider, i) => {\n const part = colliders[i]?.part;\n keysByCollider.set(collider.handle, { key, ...(part === undefined ? {} : { part }) });\n });\n };\n\n const remove: PhysicsWorld['remove'] = (key) => {\n const held = bodies.get(key);\n if (held === undefined) return;\n for (const collider of held.colliders) keysByCollider.delete(collider.handle);\n // Rapier removes the body's joints with it; forget them, as their handles are reused.\n for (const [id, joined] of joints)\n if (joined.a === key || joined.b === key) joints.delete(id);\n world.removeRigidBody(held.rigidBody);\n bodies.delete(key);\n };\n\n const addJoint: PhysicsWorld['addJoint'] = (id, joint, a, b) => {\n const first = bodies.get(a);\n const second = bodies.get(b);\n if (first === undefined || second === undefined) return;\n const made = world.createImpulseJoint(\n jointData(rapier, joint),\n first.rigidBody,\n second.rigidBody,\n true,\n );\n limit(made, limitsOf(joint));\n drive(made, motorOf(joint));\n made.setContactsEnabled(joint.contacts);\n joints.set(id, { joint: made, a, b });\n };\n\n const removeJoint: PhysicsWorld['removeJoint'] = (id) => {\n const joined = joints.get(id);\n if (joined === undefined) return;\n world.removeImpulseJoint(joined.joint, true);\n joints.delete(id);\n };\n\n const collisionsOf = (): ReadonlyArray<Collision> => {\n const collisions: Array<Collision> = [];\n events.drainCollisionEvents((first, second, started) => {\n const a = keysByCollider.get(first);\n const b = keysByCollider.get(second);\n if (a !== undefined && b !== undefined) collisions.push({ ...pair(a, b), started });\n });\n return collisions;\n };\n\n /** Contact force events since the last call, kept across steps until asked for. */\n let forces: Array<ContactForce> = [];\n function recordForce(event: RAPIER.TempContactForceEvent): void {\n const a = keysByCollider.get(event.collider1());\n const b = keysByCollider.get(event.collider2());\n if (a === undefined || b === undefined) return;\n const total = event.totalForce();\n const direction = event.maxForceDirection();\n forces.push({\n ...pair(a, b),\n totalForce: [total.x, total.y, total.z],\n totalForceMagnitude: event.totalForceMagnitude(),\n maxForceDirection: [direction.x, direction.y, direction.z],\n maxForceMagnitude: event.maxForceMagnitude(),\n });\n }\n const drainForces = (): void => events.drainContactForceEvents(recordForce);\n\n return {\n configure: (physics) => {\n world.gravity = vector(physics.gravity);\n },\n add,\n update: (key, body) => {\n const held = bodies.get(key);\n if (held === undefined) return;\n motion(held.rigidBody, body);\n surface(held.colliders, body);\n reporting(held.colliders, body);\n },\n teleport: (key, pose) => {\n const held = bodies.get(key);\n if (held === undefined) return;\n held.rigidBody.setTranslation(vector(pose.position), true);\n held.rigidBody.setRotation(rotation(pose.quaternion), true);\n held.rigidBody.setLinvel({ x: 0, y: 0, z: 0 }, true);\n held.rigidBody.setAngvel({ x: 0, y: 0, z: 0 }, true);\n },\n moveKinematic: (key, pose) => {\n const held = bodies.get(key);\n if (held === undefined) return;\n held.rigidBody.setNextKinematicTranslation(vector(pose.position));\n held.rigidBody.setNextKinematicRotation(rotation(pose.quaternion));\n },\n applyImpulse: (key, impulse) => {\n bodies.get(key)?.rigidBody.applyImpulse(vector(impulse), true);\n },\n remove,\n addJoint,\n removeJoint,\n step: (seconds) => {\n world.timestep = seconds;\n world.step(events);\n drainForces();\n return collisionsOf();\n },\n contactForces: () => {\n const drained = forces;\n forces = [];\n return drained;\n },\n // react-three-rapier's Debug: Rapier's own line rendering of colliders and joints.\n debugLines: () => {\n const { vertices, colors } = world.debugRender();\n return { vertices, colors };\n },\n pose: (key) => {\n const held = bodies.get(key);\n if (held === undefined) return undefined;\n const { x, y, z } = held.rigidBody.translation();\n const turn = held.rigidBody.rotation();\n return { position: [x, y, z], quaternion: [turn.x, turn.y, turn.z, turn.w] };\n },\n awake: () => {\n for (const { rigidBody } of bodies.values()) {\n if (rigidBody.isDynamic() && !rigidBody.isSleeping()) return true;\n }\n return false;\n },\n dispose: () => {\n bodies.clear();\n keysByCollider.clear();\n joints.clear();\n events.free();\n world.free();\n },\n };\n };\n\n/**\n * Loads Rapier's WebAssembly and returns the engine. Call once per page; the engine makes\n * a world for each scene with physics.\n */\nexport const loadRapier = async (): Promise<PhysicsEngine> => {\n await RAPIER.init();\n return { createWorld: createWorld(RAPIER) };\n};\n"
|
|
5
|
+
"/**\n * Rapier physics for `@opsydyn/effect-three`: a `PhysicsEngine` that the scene graph\n * steps. Load it once, before making the environment, and pass it on:\n *\n * ```ts\n * const physics = await loadRapier();\n * const environment = EffectThreeFoldkit.makeEnvironment(window, { physics });\n * ```\n *\n * Bodies are described on meshes (`body()`) under a scene's `physics()`; this package\n * only turns those descriptions into Rapier bodies and colliders, as react-three-rapier's\n * `RigidBody` does (`ae5c3fe`, `src/utils/utils-rigidbody.ts` and `utils-collider.ts`),\n * and joints into impulse joints, as its joint hooks do (`src/hooks/joints.ts`).\n *\n * Rapier (`@dimforge/rapier3d-compat`) is Apache-2.0; its WebAssembly is embedded, so\n * nothing extra is fetched. For a simulation that must come out the same on every\n * machine (lockstep, replays shared as links), load Rapier's deterministic build from\n * `@opsydyn/effect-three-rapier/deterministic` instead.\n *\n * @module\n */\nimport RAPIER from '@dimforge/rapier3d-compat';\nimport type { PhysicsEngine } from '@opsydyn/effect-three';\n\nimport { engineOf } from './engine.ts';\n\n/**\n * Loads Rapier's WebAssembly and returns the engine. Call once per page; the engine makes\n * a world for each scene with physics.\n */\nexport const loadRapier = async (): Promise<PhysicsEngine> => {\n await RAPIER.init();\n return engineOf(RAPIER);\n};\n",
|
|
6
|
+
"/**\n * The engine itself, for whichever Rapier build is loaded: the standard one\n * (`@dimforge/rapier3d-compat`, from the package's main entry) or the deterministic one\n * (`/deterministic`). Both have the same API.\n *\n * @module\n */\nimport type RAPIER from '@dimforge/rapier3d-compat';\nimport { interactionBits } from '@opsydyn/effect-three';\nimport type {\n Body,\n BodyPose,\n Collider,\n ColliderShape,\n Collision,\n Physics,\n ContactForce,\n JointLimits,\n JointMotor,\n PhysicsEngine,\n PhysicsJoint,\n PhysicsWorld,\n Vec3,\n} from '@opsydyn/effect-three';\n\nimport { type IndexedBody, readSnapshot, type SnapshotIndex, writeSnapshot } from './snapshot.ts';\n\n/** A loaded Rapier module: either build. */\nexport type Rapier = typeof RAPIER;\n\nconst vector = ([x, y, z]: Vec3) => ({ x, y, z });\n\nconst rotation = ([x, y, z, w]: BodyPose['quaternion']) => ({ x, y, z, w });\n\n/** Body types by our names. Kinematic bodies are position based, as react-three-rapier's default. */\nconst bodyType = (rapier: Rapier, type: Body['type']): RAPIER.RigidBodyType =>\n ({\n dynamic: rapier.RigidBodyType.Dynamic,\n fixed: rapier.RigidBodyType.Fixed,\n kinematic: rapier.RigidBodyType.KinematicPositionBased,\n })[type];\n\n/** The collider description for a shape; a hull Rapier cannot build becomes a small ball. */\nconst shapeDesc = (rapier: Rapier, shape: ColliderShape): RAPIER.ColliderDesc => {\n switch (shape._tag) {\n case 'Cuboid':\n return rapier.ColliderDesc.cuboid(...shape.halfExtents);\n case 'Ball':\n return rapier.ColliderDesc.ball(shape.radius);\n case 'Hull':\n return rapier.ColliderDesc.convexHull(shape.points) ?? rapier.ColliderDesc.ball(1e-3);\n case 'Capsule':\n return rapier.ColliderDesc.capsule(shape.halfHeight, shape.radius);\n case 'Cylinder':\n return rapier.ColliderDesc.cylinder(shape.halfHeight, shape.radius);\n case 'Cone':\n return rapier.ColliderDesc.cone(shape.halfHeight, shape.radius);\n case 'Trimesh':\n return rapier.ColliderDesc.trimesh(shape.vertices, shape.indices);\n }\n};\n\n/** A collider placed in its body. */\nconst colliderDesc = (rapier: Rapier, collider: Collider): RAPIER.ColliderDesc =>\n shapeDesc(rapier, collider.shape)\n .setTranslation(...collider.translation)\n .setRotation(rotation(collider.rotation));\n\n/**\n * The events a body's colliders report: collisions always, contact forces over its\n * threshold when it has one (react-three-rapier's `onContactForce` turns on\n * `CONTACT_FORCE_EVENTS`).\n */\nconst reporting = (rapier: Rapier, colliders: ReadonlyArray<RAPIER.Collider>, body: Body): void => {\n for (const collider of colliders) {\n if (body.contactForces === null) {\n collider.setActiveEvents(rapier.ActiveEvents.COLLISION_EVENTS);\n continue;\n }\n collider.setActiveEvents(\n rapier.ActiveEvents.COLLISION_EVENTS | rapier.ActiveEvents.CONTACT_FORCE_EVENTS,\n );\n collider.setContactForceEventThreshold(body.contactForces);\n }\n};\n\n/**\n * Applies a body's surface and mass settings to its colliders. A given mass is shared\n * among them; otherwise each has density 1.\n */\nconst surface = (colliders: ReadonlyArray<RAPIER.Collider>, body: Body): void => {\n for (const collider of colliders) {\n collider.setFriction(body.friction);\n collider.setRestitution(body.restitution);\n collider.setSensor(body.sensor);\n if (body.mass === null) collider.setDensity(1);\n else collider.setMass(body.mass / colliders.length);\n collider.setCollisionGroups(interactionBits(body.collisionGroups));\n collider.setSolverGroups(interactionBits(body.solverGroups));\n }\n};\n\n/** Applies a body's motion settings. */\nconst motion = (rapier: Rapier, rigidBody: RAPIER.RigidBody, body: Body): void => {\n rigidBody.setBodyType(bodyType(rapier, body.type), true);\n rigidBody.setLinearDamping(body.linearDamping);\n rigidBody.setAngularDamping(body.angularDamping);\n rigidBody.setGravityScale(body.gravityScale, true);\n rigidBody.enableCcd(body.ccd);\n};\n\n/** The limits a joint has, if it is a hinge or slider with limits. */\nconst limitsOf = (joint: PhysicsJoint): JointLimits | null =>\n joint.kind._tag === 'Revolute' || joint.kind._tag === 'Prismatic' ? joint.kind.limits : null;\n\n/** The motor a joint has, if it is a hinge or slider with one. */\nconst motorOf = (joint: PhysicsJoint): JointMotor | null =>\n joint.kind._tag === 'Revolute' || joint.kind._tag === 'Prismatic' ? joint.kind.motor : null;\n\n/** Drives a hinge or slider once made: Rapier's `configureMotor`, set on the joint. */\nconst drive = (rapier: Rapier, made: RAPIER.ImpulseJoint, motor: JointMotor | null): void => {\n if (motor !== null && made instanceof rapier.UnitImpulseJoint) {\n made.configureMotor(motor.position, motor.velocity, motor.stiffness, motor.damping);\n }\n};\n\n/**\n * Limits a hinge or slider once made. React-three-rapier sets them on the joint data, but\n * Rapier's `JointData.intoRaw` (0.21) passes them on for prismatic joints only, so a\n * hinge's would be lost: they are set on the joint instead.\n */\nconst limit = (rapier: Rapier, made: RAPIER.ImpulseJoint, limits: JointLimits | null): void => {\n if (limits !== null && made instanceof rapier.UnitImpulseJoint) made.setLimits(...limits);\n};\n\n/** Rapier's joint data for a joint, anchors in each body's space. */\nconst jointData = (rapier: Rapier, joint: PhysicsJoint): RAPIER.JointData => {\n const a = vector(joint.anchorA);\n const b = vector(joint.anchorB);\n const { kind } = joint;\n switch (kind._tag) {\n case 'Fixed':\n return rapier.JointData.fixed(a, rotation(kind.frameA), b, rotation(kind.frameB));\n case 'Spherical':\n return rapier.JointData.spherical(a, b);\n case 'Revolute':\n return rapier.JointData.revolute(a, b, vector(kind.axis));\n case 'Prismatic':\n return rapier.JointData.prismatic(a, b, vector(kind.axis));\n case 'Rope':\n return rapier.JointData.rope(kind.length, a, b);\n case 'Spring':\n return rapier.JointData.spring(kind.restLength, kind.stiffness, kind.damping, a, b);\n }\n};\n\n/** Which body a collider belongs to, and which part of it, by name. */\ntype Owner = { readonly key: string; readonly part?: string };\n\n/** Two colliders' owners as an event's `a` and `b`, with their parts. */\nconst pair = (a: Owner, b: Owner) => ({\n a: a.key,\n b: b.key,\n ...(a.part === undefined ? {} : { aPart: a.part }),\n ...(b.part === undefined ? {} : { bPart: b.part }),\n});\n\ntype Held = {\n readonly rigidBody: RAPIER.RigidBody;\n readonly colliders: ReadonlyArray<RAPIER.Collider>;\n};\n\ntype Joined = { readonly joint: RAPIER.ImpulseJoint; readonly a: string; readonly b: string };\n\n/**\n * A Rapier world as a `PhysicsWorld`: a new one, or one restored from a snapshot with the\n * index of what it holds.\n */\nconst hostWorld =\n (rapier: Rapier) =>\n (world: RAPIER.World, index: SnapshotIndex = { bodies: [], joints: [] }): PhysicsWorld => {\n const events = new rapier.EventQueue(true);\n const bodies = new Map<string, Held>(\n index.bodies.map((body) => [\n body.key,\n {\n rigidBody: world.getRigidBody(body.handle),\n colliders: body.colliders.map((collider) => world.getCollider(collider.handle)),\n },\n ]),\n );\n /** Each collider's body, and the part of it the collider is (when named). */\n const keysByCollider = new Map<number, Owner>(\n index.bodies.flatMap(({ key, colliders }) =>\n colliders.map(({ handle, part }) => [handle, part === undefined ? { key } : { key, part }]),\n ),\n );\n const joints = new Map<string, Joined>(\n index.joints.map(({ id, handle, a, b }) => [\n id,\n { joint: world.getImpulseJoint(handle), a, b },\n ]),\n );\n\n const add: PhysicsWorld['add'] = (key, body, colliders, pose) => {\n const desc = new rapier.RigidBodyDesc(bodyType(rapier, body.type))\n .setTranslation(...pose.position)\n .setRotation(rotation(pose.quaternion))\n .setLinvel(...body.linearVelocity)\n .setAngvel(vector(body.angularVelocity))\n .setLinearDamping(body.linearDamping)\n .setAngularDamping(body.angularDamping)\n .setGravityScale(body.gravityScale)\n .setCcdEnabled(body.ccd);\n const rigidBody = world.createRigidBody(desc);\n const made = colliders.map((collider) =>\n world.createCollider(colliderDesc(rapier, collider), rigidBody),\n );\n surface(made, body);\n reporting(rapier, made, body);\n bodies.set(key, { rigidBody, colliders: made });\n made.forEach((collider, i) => {\n const part = colliders[i]?.part;\n keysByCollider.set(collider.handle, { key, ...(part === undefined ? {} : { part }) });\n });\n };\n\n const remove: PhysicsWorld['remove'] = (key) => {\n const held = bodies.get(key);\n if (held === undefined) return;\n for (const collider of held.colliders) keysByCollider.delete(collider.handle);\n // Rapier removes the body's joints with it; forget them, as their handles are reused.\n for (const [id, joined] of joints)\n if (joined.a === key || joined.b === key) joints.delete(id);\n world.removeRigidBody(held.rigidBody);\n bodies.delete(key);\n };\n\n const addJoint: PhysicsWorld['addJoint'] = (id, joint, a, b) => {\n const first = bodies.get(a);\n const second = bodies.get(b);\n if (first === undefined || second === undefined) return;\n const made = world.createImpulseJoint(\n jointData(rapier, joint),\n first.rigidBody,\n second.rigidBody,\n true,\n );\n limit(rapier, made, limitsOf(joint));\n drive(rapier, made, motorOf(joint));\n made.setContactsEnabled(joint.contacts);\n joints.set(id, { joint: made, a, b });\n };\n\n const removeJoint: PhysicsWorld['removeJoint'] = (id) => {\n const joined = joints.get(id);\n if (joined === undefined) return;\n world.removeImpulseJoint(joined.joint, true);\n joints.delete(id);\n };\n\n const collisionsOf = (): ReadonlyArray<Collision> => {\n const collisions: Array<Collision> = [];\n events.drainCollisionEvents((first, second, started) => {\n const a = keysByCollider.get(first);\n const b = keysByCollider.get(second);\n if (a !== undefined && b !== undefined) collisions.push({ ...pair(a, b), started });\n });\n return collisions;\n };\n\n /** Contact force events since the last call, kept across steps until asked for. */\n let forces: Array<ContactForce> = [];\n function recordForce(event: RAPIER.TempContactForceEvent): void {\n const a = keysByCollider.get(event.collider1());\n const b = keysByCollider.get(event.collider2());\n if (a === undefined || b === undefined) return;\n const total = event.totalForce();\n const direction = event.maxForceDirection();\n forces.push({\n ...pair(a, b),\n totalForce: [total.x, total.y, total.z],\n totalForceMagnitude: event.totalForceMagnitude(),\n maxForceDirection: [direction.x, direction.y, direction.z],\n maxForceMagnitude: event.maxForceMagnitude(),\n });\n }\n const drainForces = (): void => events.drainContactForceEvents(recordForce);\n\n /** A collider as a snapshot indexes it: its handle, and its part when named. */\n function indexed(collider: RAPIER.Collider): IndexedBody['colliders'][number] {\n const part = keysByCollider.get(collider.handle)?.part;\n return part === undefined ? { handle: collider.handle } : { handle: collider.handle, part };\n }\n\n return {\n configure: (physics) => {\n world.gravity = vector(physics.gravity);\n },\n add,\n update: (key, body) => {\n const held = bodies.get(key);\n if (held === undefined) return;\n motion(rapier, held.rigidBody, body);\n surface(held.colliders, body);\n reporting(rapier, held.colliders, body);\n },\n teleport: (key, pose) => {\n const held = bodies.get(key);\n if (held === undefined) return;\n held.rigidBody.setTranslation(vector(pose.position), true);\n held.rigidBody.setRotation(rotation(pose.quaternion), true);\n held.rigidBody.setLinvel({ x: 0, y: 0, z: 0 }, true);\n held.rigidBody.setAngvel({ x: 0, y: 0, z: 0 }, true);\n },\n moveKinematic: (key, pose) => {\n const held = bodies.get(key);\n if (held === undefined) return;\n held.rigidBody.setNextKinematicTranslation(vector(pose.position));\n held.rigidBody.setNextKinematicRotation(rotation(pose.quaternion));\n },\n applyImpulse: (key, impulse) => {\n bodies.get(key)?.rigidBody.applyImpulse(vector(impulse), true);\n },\n remove,\n addJoint,\n removeJoint,\n step: (seconds) => {\n world.timestep = seconds;\n world.step(events);\n drainForces();\n return collisionsOf();\n },\n contactForces: () => {\n const drained = forces;\n forces = [];\n return drained;\n },\n // react-three-rapier's Debug: Rapier's own line rendering of colliders and joints.\n debugLines: () => {\n const { vertices, colors } = world.debugRender();\n return { vertices, colors };\n },\n pose: (key) => {\n const held = bodies.get(key);\n if (held === undefined) return undefined;\n const { x, y, z } = held.rigidBody.translation();\n const turn = held.rigidBody.rotation();\n return { position: [x, y, z], quaternion: [turn.x, turn.y, turn.z, turn.w] };\n },\n awake: () => {\n for (const { rigidBody } of bodies.values()) {\n if (rigidBody.isDynamic() && !rigidBody.isSleeping()) return true;\n }\n return false;\n },\n // Rapier's world, and which of its bodies, colliders and joints are which.\n snapshot: () =>\n writeSnapshot(\n {\n bodies: [...bodies].map(([key, held]) => ({\n key,\n handle: held.rigidBody.handle,\n colliders: held.colliders.map(indexed),\n })),\n joints: [...joints].map(([id, { joint, a, b }]) => ({\n id,\n handle: joint.handle,\n a,\n b,\n })),\n },\n world.takeSnapshot(),\n ),\n dispose: () => {\n bodies.clear();\n keysByCollider.clear();\n joints.clear();\n events.free();\n world.free();\n },\n };\n };\n\n/** The engine over a loaded Rapier module. */\nexport const engineOf = (rapier: Rapier): PhysicsEngine => {\n const host = hostWorld(rapier);\n return {\n createWorld: (initial: Physics) => host(new rapier.World(vector(initial.gravity))),\n // A snapshot carries its gravity and everything else in Rapier's world.\n restoreWorld: (_physics, snapshot) => {\n const { index, world } = readSnapshot(snapshot);\n return {\n world: host(rapier.World.restoreSnapshot(world), index),\n bodies: index.bodies.map((body) => body.key),\n joints: index.joints.map((joint) => joint.id),\n };\n },\n };\n};\n",
|
|
7
|
+
"/**\n * A snapshot of one of this package's worlds: Rapier's own (`World.takeSnapshot`), and an\n * index of which of its bodies, colliders and joints are which, by the keys the scene\n * graph knows them by. Nothing here needs Rapier, so the page side of a worker\n * (`remotePhysics`) can read the index of a snapshot the worker took.\n *\n * The layout: a format byte; the bodies (each its key, handle, and colliders with their\n * handles and parts); the joints (each its id, handle and bodies); then Rapier's bytes.\n * Counts and string lengths are 32-bit, handles 64-bit floats (Rapier's own numbers),\n * all little-endian.\n *\n * @module\n */\n\n/** A body in a snapshot: its key, Rapier handle, and its colliders'. */\nexport type IndexedBody = {\n readonly key: string;\n readonly handle: number;\n readonly colliders: ReadonlyArray<{ readonly handle: number; readonly part?: string }>;\n};\n\n/** A joint in a snapshot: its id, Rapier handle, and the keys of its bodies. */\nexport type IndexedJoint = {\n readonly id: string;\n readonly handle: number;\n readonly a: string;\n readonly b: string;\n};\n\nexport type SnapshotIndex = {\n readonly bodies: ReadonlyArray<IndexedBody>;\n readonly joints: ReadonlyArray<IndexedJoint>;\n};\n\n/** The format byte this version writes and reads. */\nconst format = 1;\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/** Writes `index` and Rapier's `world` bytes as one snapshot. */\nexport const writeSnapshot = (index: SnapshotIndex, world: Uint8Array): Uint8Array => {\n const parts: Array<Uint8Array> = [Uint8Array.of(format)];\n const count = (value: number): void => {\n const bytes = new Uint8Array(4);\n new DataView(bytes.buffer).setUint32(0, value, true);\n parts.push(bytes);\n };\n const handle = (value: number): void => {\n const bytes = new Uint8Array(8);\n new DataView(bytes.buffer).setFloat64(0, value, true);\n parts.push(bytes);\n };\n const text = (value: string): void => {\n const bytes = encoder.encode(value);\n count(bytes.length);\n parts.push(bytes);\n };\n count(index.bodies.length);\n for (const body of index.bodies) {\n text(body.key);\n handle(body.handle);\n count(body.colliders.length);\n for (const collider of body.colliders) {\n handle(collider.handle);\n // A part is written with a leading mark, so that no part and an empty one differ.\n text(collider.part === undefined ? '' : `:${collider.part}`);\n }\n }\n count(index.joints.length);\n for (const joint of index.joints) {\n text(joint.id);\n handle(joint.handle);\n text(joint.a);\n text(joint.b);\n }\n parts.push(world);\n const out = new Uint8Array(parts.reduce((length, part) => length + part.length, 0));\n let at = 0;\n for (const part of parts) {\n out.set(part, at);\n at += part.length;\n }\n return out;\n};\n\n/** Reads a snapshot written by `writeSnapshot`: its index, and Rapier's bytes. */\nexport const readSnapshot = (\n snapshot: Uint8Array,\n): { readonly index: SnapshotIndex; readonly world: Uint8Array } => {\n if (snapshot[0] !== format) throw new Error('Not a snapshot of an effect-three Rapier world');\n const view = new DataView(snapshot.buffer, snapshot.byteOffset, snapshot.byteLength);\n let at = 1;\n const count = (): number => {\n const value = view.getUint32(at, true);\n at += 4;\n return value;\n };\n const handle = (): number => {\n const value = view.getFloat64(at, true);\n at += 8;\n return value;\n };\n const text = (): string => {\n const length = count();\n const value = decoder.decode(snapshot.subarray(at, at + length));\n at += length;\n return value;\n };\n function collider(): IndexedBody['colliders'][number] {\n const colliderHandle = handle();\n const part = text();\n return part === ''\n ? { handle: colliderHandle }\n : { handle: colliderHandle, part: part.slice(1) };\n }\n function body(): IndexedBody {\n const key = text();\n const bodyHandle = handle();\n return { key, handle: bodyHandle, colliders: Array.from({ length: count() }, collider) };\n }\n const bodies: Array<IndexedBody> = Array.from({ length: count() }, body);\n const joints: Array<IndexedJoint> = Array.from({ length: count() }, () => ({\n id: text(),\n handle: handle(),\n a: text(),\n b: text(),\n }));\n return { index: { bodies, joints }, world: snapshot.subarray(at) };\n};\n"
|
|
6
8
|
],
|
|
7
|
-
"mappings": "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",
|
|
8
|
-
"debugId": "
|
|
9
|
+
"mappings": "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",
|
|
10
|
+
"debugId": "BF71FE688A93448964756E2164756E21",
|
|
9
11
|
"names": []
|
|
10
12
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A snapshot of one of this package's worlds: Rapier's own (`World.takeSnapshot`), and an
|
|
3
|
+
* index of which of its bodies, colliders and joints are which, by the keys the scene
|
|
4
|
+
* graph knows them by. Nothing here needs Rapier, so the page side of a worker
|
|
5
|
+
* (`remotePhysics`) can read the index of a snapshot the worker took.
|
|
6
|
+
*
|
|
7
|
+
* The layout: a format byte; the bodies (each its key, handle, and colliders with their
|
|
8
|
+
* handles and parts); the joints (each its id, handle and bodies); then Rapier's bytes.
|
|
9
|
+
* Counts and string lengths are 32-bit, handles 64-bit floats (Rapier's own numbers),
|
|
10
|
+
* all little-endian.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
/** A body in a snapshot: its key, Rapier handle, and its colliders'. */
|
|
15
|
+
export type IndexedBody = {
|
|
16
|
+
readonly key: string;
|
|
17
|
+
readonly handle: number;
|
|
18
|
+
readonly colliders: ReadonlyArray<{
|
|
19
|
+
readonly handle: number;
|
|
20
|
+
readonly part?: string;
|
|
21
|
+
}>;
|
|
22
|
+
};
|
|
23
|
+
/** A joint in a snapshot: its id, Rapier handle, and the keys of its bodies. */
|
|
24
|
+
export type IndexedJoint = {
|
|
25
|
+
readonly id: string;
|
|
26
|
+
readonly handle: number;
|
|
27
|
+
readonly a: string;
|
|
28
|
+
readonly b: string;
|
|
29
|
+
};
|
|
30
|
+
export type SnapshotIndex = {
|
|
31
|
+
readonly bodies: ReadonlyArray<IndexedBody>;
|
|
32
|
+
readonly joints: ReadonlyArray<IndexedJoint>;
|
|
33
|
+
};
|
|
34
|
+
/** Writes `index` and Rapier's `world` bytes as one snapshot. */
|
|
35
|
+
export declare const writeSnapshot: (index: SnapshotIndex, world: Uint8Array) => Uint8Array;
|
|
36
|
+
/** Reads a snapshot written by `writeSnapshot`: its index, and Rapier's bytes. */
|
|
37
|
+
export declare const readSnapshot: (snapshot: Uint8Array) => {
|
|
38
|
+
readonly index: SnapshotIndex;
|
|
39
|
+
readonly world: Uint8Array;
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=snapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../src/snapshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,wEAAwE;AACxE,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxF,CAAC;AAEF,gFAAgF;AAChF,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IAC5C,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;CAC9C,CAAC;AAQF,iEAAiE;AACjE,eAAO,MAAM,aAAa,UAAW,aAAa,SAAS,UAAU,KAAG,UA2CvE,CAAC;AAEF,kFAAkF;AAClF,eAAO,MAAM,YAAY,aACb,UAAU,KACnB;IAAE,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;CAwC7D,CAAC"}
|
package/dist/worker.d.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Physics in a worker, behind the same engine contract (ADR-017). In the page,
|
|
3
|
+
* `remotePhysics(worker)` is a `PhysicsEngine` whose worlds send what the scene graph asks
|
|
4
|
+
* of them to the worker, a frame's worth in one message, and answer from what the worker
|
|
5
|
+
* last sent back. In the worker, `servePhysics(self, loadRapier())` does what each world
|
|
6
|
+
* is asked with a real engine and sends back the steps' collisions and forces and every
|
|
7
|
+
* body's pose. Nothing here imports Rapier, so the page does not load its WebAssembly.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* // physics.worker.ts
|
|
11
|
+
* import { loadRapier } from '@opsydyn/effect-three-rapier/deterministic';
|
|
12
|
+
* import { servePhysics } from '@opsydyn/effect-three-rapier/worker';
|
|
13
|
+
* servePhysics(self, loadRapier());
|
|
14
|
+
*
|
|
15
|
+
* // the page
|
|
16
|
+
* import { remotePhysics } from '@opsydyn/effect-three-rapier/worker';
|
|
17
|
+
* const worker = new Worker(new URL('./physics.worker.ts', import.meta.url), { type: 'module' });
|
|
18
|
+
* const environment = EffectThreeFoldkit.makeEnvironment(window, { physics: remotePhysics(worker) });
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* The stepping is pipelined: what a world shows and reports lags what it was asked by
|
|
22
|
+
* the time the worker takes to answer, about a frame. A world on `physics({ until })` is
|
|
23
|
+
* reported as there only once all it was asked has come back, so its checksum is the one
|
|
24
|
+
* an engine in the page would give, a frame later.
|
|
25
|
+
*
|
|
26
|
+
* @module
|
|
27
|
+
*/
|
|
28
|
+
import type { Body, BodyPose, Collider, Collision, ContactForce, DebugLines, Physics, PhysicsEngine, PhysicsJoint, Vec3 } from '@opsydyn/effect-three';
|
|
29
|
+
/** One thing a world is asked to do, as `PhysicsWorld`'s method of that name. */
|
|
30
|
+
export type Call = {
|
|
31
|
+
readonly _tag: 'Configure';
|
|
32
|
+
readonly physics: Physics;
|
|
33
|
+
} | {
|
|
34
|
+
readonly _tag: 'Add';
|
|
35
|
+
readonly key: string;
|
|
36
|
+
readonly body: Body;
|
|
37
|
+
readonly colliders: ReadonlyArray<Collider>;
|
|
38
|
+
readonly pose: BodyPose;
|
|
39
|
+
} | {
|
|
40
|
+
readonly _tag: 'Update';
|
|
41
|
+
readonly key: string;
|
|
42
|
+
readonly body: Body;
|
|
43
|
+
} | {
|
|
44
|
+
readonly _tag: 'Teleport';
|
|
45
|
+
readonly key: string;
|
|
46
|
+
readonly pose: BodyPose;
|
|
47
|
+
} | {
|
|
48
|
+
readonly _tag: 'MoveKinematic';
|
|
49
|
+
readonly key: string;
|
|
50
|
+
readonly pose: BodyPose;
|
|
51
|
+
} | {
|
|
52
|
+
readonly _tag: 'ApplyImpulse';
|
|
53
|
+
readonly key: string;
|
|
54
|
+
readonly impulse: Vec3;
|
|
55
|
+
} | {
|
|
56
|
+
readonly _tag: 'Remove';
|
|
57
|
+
readonly key: string;
|
|
58
|
+
} | {
|
|
59
|
+
readonly _tag: 'AddJoint';
|
|
60
|
+
readonly id: string;
|
|
61
|
+
readonly joint: PhysicsJoint;
|
|
62
|
+
readonly a: string;
|
|
63
|
+
readonly b: string;
|
|
64
|
+
} | {
|
|
65
|
+
readonly _tag: 'RemoveJoint';
|
|
66
|
+
readonly id: string;
|
|
67
|
+
} | {
|
|
68
|
+
readonly _tag: 'Step';
|
|
69
|
+
readonly seconds: number;
|
|
70
|
+
} | {
|
|
71
|
+
readonly _tag: 'Snapshot';
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* What the page sends the worker. A world's creation is answered as its batch 1; the
|
|
75
|
+
* batches after it are numbered on from 2.
|
|
76
|
+
*/
|
|
77
|
+
export type ToWorker = {
|
|
78
|
+
readonly _tag: 'Create';
|
|
79
|
+
readonly world: number;
|
|
80
|
+
readonly physics: Physics;
|
|
81
|
+
/** A snapshot to make the world from (`PhysicsEngine.restoreWorld`). */
|
|
82
|
+
readonly snapshot?: Uint8Array;
|
|
83
|
+
} | {
|
|
84
|
+
readonly _tag: 'Batch';
|
|
85
|
+
readonly world: number;
|
|
86
|
+
readonly batch: number;
|
|
87
|
+
readonly calls: ReadonlyArray<Call>;
|
|
88
|
+
} | {
|
|
89
|
+
readonly _tag: 'Dispose';
|
|
90
|
+
readonly world: number;
|
|
91
|
+
};
|
|
92
|
+
/** What the worker sends back after each batch, or why one could not be done. */
|
|
93
|
+
export type FromWorker = {
|
|
94
|
+
readonly _tag: 'Done';
|
|
95
|
+
readonly world: number;
|
|
96
|
+
readonly batch: number;
|
|
97
|
+
readonly collisions: ReadonlyArray<Collision>;
|
|
98
|
+
readonly contactForces: ReadonlyArray<ContactForce>;
|
|
99
|
+
readonly poses: ReadonlyArray<readonly [string, BodyPose]>;
|
|
100
|
+
readonly awake: boolean;
|
|
101
|
+
/** The world as lines, while it is configured to draw them. */
|
|
102
|
+
readonly debugLines: DebugLines | null;
|
|
103
|
+
/** The world's snapshot, when the batch asked for one. */
|
|
104
|
+
readonly snapshot?: Uint8Array;
|
|
105
|
+
} | {
|
|
106
|
+
readonly _tag: 'Failed';
|
|
107
|
+
readonly world: number;
|
|
108
|
+
readonly reason: string;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Either end of the channel: a `Worker` in the page, the worker's own global scope (`self`)
|
|
112
|
+
* inside it, or a `MessagePort`.
|
|
113
|
+
*/
|
|
114
|
+
export type PhysicsPort = {
|
|
115
|
+
readonly postMessage: (message: unknown) => void;
|
|
116
|
+
readonly addEventListener: (type: 'message', listener: (event: MessageEvent) => void) => void;
|
|
117
|
+
/** A `MessagePort`'s: it delivers nothing to its listeners until started. */
|
|
118
|
+
readonly start?: () => void;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* A physics engine in a worker, for the page: each world it makes is made in the worker
|
|
122
|
+
* that `servePhysics` runs in, on the far end of `port`.
|
|
123
|
+
*/
|
|
124
|
+
export declare const remotePhysics: (port: PhysicsPort) => PhysicsEngine;
|
|
125
|
+
/**
|
|
126
|
+
* Serves the worlds a page's `remotePhysics` makes, with `engine` (or the engine it is
|
|
127
|
+
* loading): in the worker, `servePhysics(self, loadRapier())`. Messages are handled in
|
|
128
|
+
* the order they came, once the engine has loaded.
|
|
129
|
+
*/
|
|
130
|
+
export declare const servePhysics: (port: PhysicsPort, engine: PhysicsEngine | Promise<PhysicsEngine>) => void;
|
|
131
|
+
//# sourceMappingURL=worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"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"}
|