@aethervtt/shard-physics 0.0.1 → 0.2.0
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/dist/index.d.ts +3 -2
- package/dist/index.js +8 -2
- package/dist/methods.js +2 -1
- package/dist/plugin.d.ts +9 -3
- package/dist/plugin.js +26 -261
- package/dist/rapier.d.ts +22 -0
- package/dist/rapier.js +27 -0
- package/dist/render.d.ts +5 -0
- package/dist/render.js +264 -0
- package/dist/track/format.d.ts +58 -0
- package/dist/track/format.js +171 -0
- package/dist/track/golden.json +238 -0
- package/dist/track/hash.d.ts +12 -0
- package/dist/track/hash.js +41 -0
- package/dist/track/index.d.ts +3 -0
- package/dist/track/index.js +44 -0
- package/dist/track/record.d.ts +79 -0
- package/dist/track/record.js +286 -0
- package/dist/track/scene.d.ts +74 -0
- package/dist/track/scene.js +153 -0
- package/dist/track/test-scenes.d.ts +6 -0
- package/dist/track/test-scenes.js +113 -0
- package/dist/worker/client.d.ts +44 -0
- package/dist/worker/client.js +163 -0
- package/dist/worker/index.d.ts +8 -0
- package/dist/worker/index.js +13 -0
- package/dist/worker/protocol.d.ts +38 -0
- package/dist/worker/protocol.js +0 -0
- package/dist/worker/serve.d.ts +34 -0
- package/dist/worker/serve.js +111 -0
- package/dist/worker/test-worker.d.ts +1 -0
- package/dist/worker/test-worker.js +18 -0
- package/dist/worker/testing.d.ts +11 -0
- package/dist/worker/testing.js +26 -0
- package/dist/worker/track-worker.d.ts +1 -0
- package/dist/worker/track-worker.js +2 -0
- package/dist/world.d.ts +13 -6
- package/dist/world.js +9 -13
- package/package.json +26 -8
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { characterSystem } from './character.js';
|
|
2
2
|
export { BODY_KINDS, type BodyKind, CharacterController, CharacterGroundEvent, type CharacterGroundEventData, CharacterIntent, CharacterState, Collider, CollisionEvent, type CollisionEventData, ContactForceEvent, type ContactForceEventData, ExternalForce, ExternalImpulse, GravitySource, JOINT_KINDS, Joint, Mass, PhysicsConfig, type PhysicsConfigValue, PhysicsParked, PhysicsRange, type PhysicsRangeValue, RigidBody, SHAPES, type Shape, Velocity, } from './components.js';
|
|
3
3
|
export { physicsMethods } from './methods.js';
|
|
4
|
-
export { Physics, PhysicsSystems, physics, physics2dPlugin, physics3dPlugin } from './plugin.js';
|
|
5
|
-
export { type
|
|
4
|
+
export { Physics, type PhysicsPluginOptions, PhysicsSystems, physics, physics2dPlugin, physics3dPlugin, } from './plugin.js';
|
|
5
|
+
export { type LoadRapierOptions, loadRapier, type Rapier, type RapierVariant } from './rapier.js';
|
|
6
|
+
export { type BodyRecord, CHARACTER_OFFSET, type CharacterRecord, createRayHit, type MeshLookup, type PhysicsStats, PhysicsWorld, type QueryOptions, type QueryShape, type RayHit, } from './world.js';
|
package/dist/index.js
CHANGED
|
@@ -22,11 +22,17 @@ import {
|
|
|
22
22
|
Velocity
|
|
23
23
|
} from "./components.js";
|
|
24
24
|
import { physicsMethods } from "./methods.js";
|
|
25
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
Physics,
|
|
27
|
+
PhysicsSystems,
|
|
28
|
+
physics,
|
|
29
|
+
physics2dPlugin,
|
|
30
|
+
physics3dPlugin
|
|
31
|
+
} from "./plugin.js";
|
|
32
|
+
import { loadRapier } from "./rapier.js";
|
|
26
33
|
import {
|
|
27
34
|
CHARACTER_OFFSET,
|
|
28
35
|
createRayHit,
|
|
29
|
-
loadRapier,
|
|
30
36
|
PhysicsWorld
|
|
31
37
|
} from "./world.js";
|
|
32
38
|
export {
|
package/dist/methods.js
CHANGED
|
@@ -98,12 +98,13 @@ const physicsMethods = [
|
|
|
98
98
|
},
|
|
99
99
|
{
|
|
100
100
|
name: "physics.describe",
|
|
101
|
-
description: "Physics state: dimension, gravity, bodies by kind and how many sleep, colliders by shape, joints, contact pairs, colliders waiting for a mesh, bodies parked out of range (large worlds) and the range, the last step time, and every character controller with its state (grounded, ground, velocity, up).",
|
|
101
|
+
description: "Physics state: dimension, Rapier variant (regular or deterministic), gravity, bodies by kind and how many sleep, colliders by shape, joints, contact pairs, colliders waiting for a mesh, bodies parked out of range (large worlds) and the range, the last step time, and every character controller with its state (grounded, ground, velocity, up).",
|
|
102
102
|
params: defineSchema("physics/DescribeParams", {}),
|
|
103
103
|
handler: ({ world }) => {
|
|
104
104
|
const physics = ready(world);
|
|
105
105
|
return {
|
|
106
106
|
dimension: physics.dim,
|
|
107
|
+
variant: physics.variant,
|
|
107
108
|
gravity: physics.config.gravity,
|
|
108
109
|
interpolate: physics.config.interpolate,
|
|
109
110
|
paused: physics.config.paused,
|
package/dist/plugin.d.ts
CHANGED
|
@@ -6,8 +6,14 @@ export { Physics };
|
|
|
6
6
|
export declare const PhysicsSystems: import("@aethervtt/shard-core").SystemSetDef;
|
|
7
7
|
/** The physics world, or `physics/not-ready` before the plugin's `ready` step. */
|
|
8
8
|
export declare function physics(world: World): PhysicsWorld;
|
|
9
|
+
export interface PhysicsPluginOptions {
|
|
10
|
+
/**
|
|
11
|
+
* Run on Rapier's deterministic build: the same results on every machine and browser, at some
|
|
12
|
+
* cost in speed (0053). Default false.
|
|
13
|
+
*/
|
|
14
|
+
deterministic?: boolean;
|
|
15
|
+
}
|
|
9
16
|
/** 3D rigid bodies, colliders, joints, and scene queries (Rapier). */
|
|
10
|
-
export declare
|
|
17
|
+
export declare function physics3dPlugin(options?: PhysicsPluginOptions): Plugin;
|
|
11
18
|
/** 2D rigid bodies, colliders, joints, and scene queries in the XY plane (Rapier 2D). */
|
|
12
|
-
export declare
|
|
13
|
-
export declare const collidersOverlay: import("@aethervtt/shard-render").OverlayDef;
|
|
19
|
+
export declare function physics2dPlugin(options?: PhysicsPluginOptions): Plugin;
|
package/dist/plugin.js
CHANGED
|
@@ -9,8 +9,7 @@ import {
|
|
|
9
9
|
PostUpdate,
|
|
10
10
|
ShardError
|
|
11
11
|
} from "@aethervtt/shard-core";
|
|
12
|
-
import {
|
|
13
|
-
import { FixedTime } from "@aethervtt/shard-runtime";
|
|
12
|
+
import { FixedTime, FrameDemand } from "@aethervtt/shard-runtime";
|
|
14
13
|
import {
|
|
15
14
|
GlobalTransform,
|
|
16
15
|
GridCell,
|
|
@@ -23,7 +22,6 @@ import { characterSystem } from "./character.js";
|
|
|
23
22
|
import * as componentsModule from "./components.js";
|
|
24
23
|
import {
|
|
25
24
|
CharacterController,
|
|
26
|
-
CharacterState,
|
|
27
25
|
Collider,
|
|
28
26
|
CollisionEvent,
|
|
29
27
|
ContactForceEvent,
|
|
@@ -39,8 +37,11 @@ import {
|
|
|
39
37
|
import { createGravitySources, gatherGravitySources, sampleGravity } from "./gravity.js";
|
|
40
38
|
import { physicsMethods } from "./methods.js";
|
|
41
39
|
import * as pluginModule from "./plugin.js";
|
|
42
|
-
import { isGrid, parentOf,
|
|
43
|
-
import { loadRapier
|
|
40
|
+
import { isGrid, parentOf, worldToLocal } from "./pose.js";
|
|
41
|
+
import { loadRapier } from "./rapier.js";
|
|
42
|
+
import * as renderModule from "./render.js";
|
|
43
|
+
import { rendererMeshes } from "./render.js";
|
|
44
|
+
import { Physics, PhysicsWorld } from "./world.js";
|
|
44
45
|
const PhysicsSystems = defineSystemSet("physics/PhysicsSystems");
|
|
45
46
|
function physics(world) {
|
|
46
47
|
const p = world.tryResource(Physics);
|
|
@@ -376,6 +377,8 @@ const syncOut = defineSystem({
|
|
|
376
377
|
visit: void 0,
|
|
377
378
|
world,
|
|
378
379
|
tick: 0,
|
|
380
|
+
/** Awake bodies sync-out wrote this step: while any are, on-demand apps keep rendering. */
|
|
381
|
+
awake: 0,
|
|
379
382
|
pos: new Float64Array(3),
|
|
380
383
|
rot: new Float64Array(4),
|
|
381
384
|
rootIdentity: true,
|
|
@@ -400,6 +403,7 @@ const syncOut = defineSystem({
|
|
|
400
403
|
s.visit ??= (handle) => {
|
|
401
404
|
const record = p.bodyByHandle.get(handle);
|
|
402
405
|
if (!record || record.kind === KIND_FIXED) return;
|
|
406
|
+
s.awake++;
|
|
403
407
|
const o = record.slot * 7;
|
|
404
408
|
const curr = p.curr;
|
|
405
409
|
for (let k = 0; k < 7; k++) p.prev[o + k] = curr[o + k];
|
|
@@ -450,7 +454,9 @@ const syncOut = defineSystem({
|
|
|
450
454
|
c.velTicks[row] = s.tick;
|
|
451
455
|
}
|
|
452
456
|
};
|
|
457
|
+
s.awake = 0;
|
|
453
458
|
p.raw.islands.forEachActiveRigidBodyHandle(s.visit);
|
|
459
|
+
world.tryResource(FrameDemand)?.set("physics", s.awake > 0);
|
|
454
460
|
}
|
|
455
461
|
});
|
|
456
462
|
const interpolate = defineSystem({
|
|
@@ -552,10 +558,11 @@ function observe(world) {
|
|
|
552
558
|
get()?.shiftOrigin(data.offset[0], data.offset[1], data.offset[2], onCollision);
|
|
553
559
|
});
|
|
554
560
|
}
|
|
555
|
-
function physicsPlugin(dim) {
|
|
561
|
+
function physicsPlugin(dim, options) {
|
|
562
|
+
const deterministic = options?.deterministic === true;
|
|
556
563
|
return {
|
|
557
564
|
name: dim === 3 ? "physics3d" : "physics2d",
|
|
558
|
-
provides: [componentsModule, pluginModule],
|
|
565
|
+
provides: [componentsModule, pluginModule, renderModule],
|
|
559
566
|
dependencies: ["core/transform"],
|
|
560
567
|
build(app) {
|
|
561
568
|
const other = dimensionOf.get(app.world);
|
|
@@ -585,268 +592,26 @@ function physicsPlugin(dim) {
|
|
|
585
592
|
app.addMethod(...physicsMethods);
|
|
586
593
|
},
|
|
587
594
|
async ready(app) {
|
|
588
|
-
const R = await loadRapier(dim);
|
|
589
|
-
|
|
595
|
+
const R = await loadRapier(dim, { deterministic });
|
|
596
|
+
const config = app.world.resource(PhysicsConfig);
|
|
597
|
+
const variant = deterministic ? "deterministic" : "regular";
|
|
598
|
+
app.world.insertResource(Physics, new PhysicsWorld(R, dim, config, variant, rendererMeshes));
|
|
599
|
+
},
|
|
600
|
+
dispose(app) {
|
|
601
|
+
app.world.tryResource(Physics)?.free();
|
|
602
|
+
app.world.removeResource(Physics);
|
|
590
603
|
}
|
|
591
604
|
};
|
|
592
605
|
}
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
const COLORS = [
|
|
596
|
-
[1, 0.55, 0.2, 1],
|
|
597
|
-
// dynamic
|
|
598
|
-
[0.55, 0.55, 0.6, 1],
|
|
599
|
-
// fixed
|
|
600
|
-
[0.3, 0.8, 1, 1],
|
|
601
|
-
// kinematic
|
|
602
|
-
[0.3, 0.8, 1, 1]
|
|
603
|
-
];
|
|
604
|
-
const SLEEPING = [0.5, 0.35, 0.2, 1];
|
|
605
|
-
const SENSOR = [0.3, 1, 0.4, 1];
|
|
606
|
-
const CONTACT = [1, 0.2, 0.3, 1];
|
|
607
|
-
const UP = [1, 0.9, 0.2, 1];
|
|
608
|
-
const pa = new Float64Array(3);
|
|
609
|
-
const pb = new Float64Array(3);
|
|
610
|
-
const q = new Float64Array(4);
|
|
611
|
-
const center = new Float64Array(3);
|
|
612
|
-
const collidersOverlay = defineOverlay({
|
|
613
|
-
name: "colliders",
|
|
614
|
-
description: "Physics collider outlines, colored by body kind (sleeping dimmed, sensors green, characters cyan with their up in yellow), and contact normals.",
|
|
615
|
-
draw(world, g, passes) {
|
|
616
|
-
const p = world.tryResource(Physics);
|
|
617
|
-
if (!p) return;
|
|
618
|
-
for (const [entity, collider] of p.colliders) {
|
|
619
|
-
if (!passes(entity)) continue;
|
|
620
|
-
const owner = p.colliderOwner.get(entity);
|
|
621
|
-
const record = owner === void 0 ? void 0 : p.bodies.get(owner);
|
|
622
|
-
const color = collider.isSensor() ? SENSOR : record?.body.isSleeping() ? SLEEPING : COLORS[record?.kind ?? KIND_FIXED];
|
|
623
|
-
const t = collider.translation(p.v3);
|
|
624
|
-
center[0] = t.x;
|
|
625
|
-
center[1] = t.y;
|
|
626
|
-
center[2] = p.dim === 3 ? t.z : 0;
|
|
627
|
-
if (p.dim === 3) {
|
|
628
|
-
const r = collider.rotation(p.q4);
|
|
629
|
-
q[0] = r.x;
|
|
630
|
-
q[1] = r.y;
|
|
631
|
-
q[2] = r.z;
|
|
632
|
-
q[3] = r.w;
|
|
633
|
-
} else {
|
|
634
|
-
const angle = collider.rotation();
|
|
635
|
-
q[0] = 0;
|
|
636
|
-
q[1] = 0;
|
|
637
|
-
q[2] = Math.sin(angle / 2);
|
|
638
|
-
q[3] = Math.cos(angle / 2);
|
|
639
|
-
}
|
|
640
|
-
drawCollider(p, g, collider, p.colliderShape.get(entity), color);
|
|
641
|
-
}
|
|
642
|
-
for (const [entity, c] of p.characters) {
|
|
643
|
-
if (!passes(entity) || !world.has(entity, CharacterState)) continue;
|
|
644
|
-
const up = world.get(entity, CharacterState).up;
|
|
645
|
-
const t = c.collider.translation(p.v3);
|
|
646
|
-
const tall = p.colliderShape.get(entity) === "capsule" ? c.collider.halfHeight() : 0;
|
|
647
|
-
const reach = c.collider.radius() + tall + 0.5;
|
|
648
|
-
pa[0] = t.x;
|
|
649
|
-
pa[1] = t.y;
|
|
650
|
-
pa[2] = p.dim === 3 ? t.z : 0;
|
|
651
|
-
pb[0] = pa[0] + up[0] * reach;
|
|
652
|
-
pb[1] = pa[1] + up[1] * reach;
|
|
653
|
-
pb[2] = pa[2] + up[2] * reach;
|
|
654
|
-
g.line(pa, pb, UP);
|
|
655
|
-
}
|
|
656
|
-
contactBudget = MAX_CONTACT_PAIRS;
|
|
657
|
-
for (let i = 0; i < p.list.length && contactBudget > 0; i++) {
|
|
658
|
-
const record = p.list[i];
|
|
659
|
-
if (record.kind !== KIND_DYNAMIC || record.body.isSleeping()) continue;
|
|
660
|
-
const n = record.body.numColliders();
|
|
661
|
-
for (let c = 0; c < n; c++) drawContacts(p, g, record.body.collider(c));
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
});
|
|
665
|
-
const MAX_CONTACT_PAIRS = 1e3;
|
|
666
|
-
let contactBudget = 0;
|
|
667
|
-
function visitedFromOtherSide(other) {
|
|
668
|
-
const body = other.parent();
|
|
669
|
-
return body?.isDynamic() === true && !body.isSleeping();
|
|
670
|
-
}
|
|
671
|
-
function drawContacts(p, g, collider) {
|
|
672
|
-
p.raw.contactPairsWith(collider, (other) => {
|
|
673
|
-
if (contactBudget <= 0) return;
|
|
674
|
-
if (other.handle < collider.handle && visitedFromOtherSide(other)) return;
|
|
675
|
-
contactBudget--;
|
|
676
|
-
p.raw.contactPair(collider, other, (manifold) => {
|
|
677
|
-
const count = manifold.numSolverContacts();
|
|
678
|
-
if (count === 0) return;
|
|
679
|
-
const n = manifold.normal();
|
|
680
|
-
for (let i = 0; i < count; i++) {
|
|
681
|
-
const point = manifold.solverContactPoint(i);
|
|
682
|
-
if (!point) continue;
|
|
683
|
-
pa[0] = point.x;
|
|
684
|
-
pa[1] = point.y;
|
|
685
|
-
pa[2] = p.dim === 3 ? point.z : 0;
|
|
686
|
-
pb[0] = pa[0] + n.x * 0.25;
|
|
687
|
-
pb[1] = pa[1] + n.y * 0.25;
|
|
688
|
-
pb[2] = pa[2] + (p.dim === 3 ? n.z : 0) * 0.25;
|
|
689
|
-
g.line(pa, pb, CONTACT);
|
|
690
|
-
}
|
|
691
|
-
});
|
|
692
|
-
});
|
|
693
|
-
}
|
|
694
|
-
function local(out, x, y, z) {
|
|
695
|
-
rotate(out, 0, q, 0, x, y, z);
|
|
696
|
-
out[0] = out[0] + center[0];
|
|
697
|
-
out[1] = out[1] + center[1];
|
|
698
|
-
out[2] = out[2] + center[2];
|
|
699
|
-
return out;
|
|
700
|
-
}
|
|
701
|
-
const SEGMENTS = 24;
|
|
702
|
-
const UNIT = (() => {
|
|
703
|
-
const out = new Float64Array((SEGMENTS + 1) * 2);
|
|
704
|
-
for (let i = 0; i <= SEGMENTS; i++) {
|
|
705
|
-
const t = i / SEGMENTS * Math.PI * 2;
|
|
706
|
-
out[i * 2] = Math.cos(t);
|
|
707
|
-
out[i * 2 + 1] = Math.sin(t);
|
|
708
|
-
}
|
|
709
|
-
return out;
|
|
710
|
-
})();
|
|
711
|
-
function localCircle(g, axis, r, dy, color) {
|
|
712
|
-
for (let i = 0; i <= SEGMENTS; i++) {
|
|
713
|
-
const u = UNIT[i * 2] * r;
|
|
714
|
-
const v = UNIT[i * 2 + 1] * r;
|
|
715
|
-
if (axis === 0) local(pb, 0, u + dy, v);
|
|
716
|
-
else if (axis === 1) local(pb, u, dy, v);
|
|
717
|
-
else local(pb, u, v + dy, 0);
|
|
718
|
-
if (i > 0) g.line(pa, pb, color);
|
|
719
|
-
pa[0] = pb[0];
|
|
720
|
-
pa[1] = pb[1];
|
|
721
|
-
pa[2] = pb[2];
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
function drawCollider(p, g, collider, shape, color) {
|
|
725
|
-
const is2d = p.dim === 2;
|
|
726
|
-
switch (shape) {
|
|
727
|
-
case "ball": {
|
|
728
|
-
const r = collider.radius();
|
|
729
|
-
localCircle(g, 2, r, 0, color);
|
|
730
|
-
if (!is2d) {
|
|
731
|
-
localCircle(g, 0, r, 0, color);
|
|
732
|
-
localCircle(g, 1, r, 0, color);
|
|
733
|
-
}
|
|
734
|
-
return;
|
|
735
|
-
}
|
|
736
|
-
case "cuboid": {
|
|
737
|
-
const he = collider.halfExtents();
|
|
738
|
-
const hz = is2d ? 0 : he.z;
|
|
739
|
-
const size = [he.x * 2, he.y * 2, hz * 2];
|
|
740
|
-
g.box(center, size, q, color);
|
|
741
|
-
return;
|
|
742
|
-
}
|
|
743
|
-
case "capsule":
|
|
744
|
-
case "cylinder":
|
|
745
|
-
case "cone": {
|
|
746
|
-
const r = collider.radius();
|
|
747
|
-
const h = collider.halfHeight();
|
|
748
|
-
if (is2d) {
|
|
749
|
-
local(pa, -r, -h, 0);
|
|
750
|
-
local(pb, -r, h, 0);
|
|
751
|
-
g.line(pa, pb, color);
|
|
752
|
-
local(pa, r, -h, 0);
|
|
753
|
-
local(pb, r, h, 0);
|
|
754
|
-
g.line(pa, pb, color);
|
|
755
|
-
localCircle(g, 2, r, h, color);
|
|
756
|
-
localCircle(g, 2, r, -h, color);
|
|
757
|
-
return;
|
|
758
|
-
}
|
|
759
|
-
const top = shape === "cone" ? 0 : r;
|
|
760
|
-
localCircle(g, 1, r, -h, color);
|
|
761
|
-
if (top > 0) localCircle(g, 1, top, h, color);
|
|
762
|
-
for (let k = 0; k < 4; k++) {
|
|
763
|
-
const a = k / 4 * Math.PI * 2;
|
|
764
|
-
local(pa, Math.cos(a) * r, -h, Math.sin(a) * r);
|
|
765
|
-
local(pb, Math.cos(a) * top, h, Math.sin(a) * top);
|
|
766
|
-
g.line(pa, pb, color);
|
|
767
|
-
}
|
|
768
|
-
if (shape === "capsule") {
|
|
769
|
-
localCircle(g, 0, r, h, color);
|
|
770
|
-
localCircle(g, 0, r, -h, color);
|
|
771
|
-
localCircle(g, 2, r, h, color);
|
|
772
|
-
localCircle(g, 2, r, -h, color);
|
|
773
|
-
}
|
|
774
|
-
return;
|
|
775
|
-
}
|
|
776
|
-
case "heightfield":
|
|
777
|
-
drawHeightfield(p, g, collider, color);
|
|
778
|
-
return;
|
|
779
|
-
default: {
|
|
780
|
-
const vertices = collider.vertices?.();
|
|
781
|
-
const indices = collider.indices?.();
|
|
782
|
-
if (!vertices || vertices.length === 0) return;
|
|
783
|
-
const d = p.dim;
|
|
784
|
-
const edge = (i, j) => {
|
|
785
|
-
local(pa, vertices[i * d], vertices[i * d + 1], d === 3 ? vertices[i * d + 2] : 0);
|
|
786
|
-
local(pb, vertices[j * d], vertices[j * d + 1], d === 3 ? vertices[j * d + 2] : 0);
|
|
787
|
-
g.line(pa, pb, color);
|
|
788
|
-
};
|
|
789
|
-
if (indices && indices.length > 0) {
|
|
790
|
-
const stride = shape === "polyline" || is2d ? 2 : 3;
|
|
791
|
-
const limit = Math.min(indices.length, 3e4);
|
|
792
|
-
for (let i = 0; i + stride - 1 < limit; i += stride) {
|
|
793
|
-
for (let k = 0; k < stride; k++) {
|
|
794
|
-
if (stride === 2 && k === 1) break;
|
|
795
|
-
edge(indices[i + k], indices[i + (k + 1) % stride]);
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
} else {
|
|
799
|
-
const n = vertices.length / d;
|
|
800
|
-
for (let i = 0; i + 1 < n; i++) edge(i, i + 1);
|
|
801
|
-
if (shape === "convex" && n > 2) edge(n - 1, 0);
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
}
|
|
606
|
+
function physics3dPlugin(options) {
|
|
607
|
+
return physicsPlugin(3, options);
|
|
805
608
|
}
|
|
806
|
-
function
|
|
807
|
-
|
|
808
|
-
const heights = hf.heightfieldHeights();
|
|
809
|
-
const scale = hf.heightfieldScale();
|
|
810
|
-
if (p.dim === 2) {
|
|
811
|
-
const n = heights.length;
|
|
812
|
-
for (let i = 0; i < n; i++) {
|
|
813
|
-
local(pb, (i / (n - 1) - 0.5) * scale.x, heights[i] * scale.y, 0);
|
|
814
|
-
if (i > 0) g.line(pa, pb, color);
|
|
815
|
-
pa[0] = pb[0];
|
|
816
|
-
pa[1] = pb[1];
|
|
817
|
-
pa[2] = pb[2];
|
|
818
|
-
}
|
|
819
|
-
return;
|
|
820
|
-
}
|
|
821
|
-
const rows = hf.heightfieldNRows() + 1;
|
|
822
|
-
const cols = hf.heightfieldNCols() + 1;
|
|
823
|
-
const sz = scale.z ?? 1;
|
|
824
|
-
const at = (out, r, c) => local(
|
|
825
|
-
out,
|
|
826
|
-
(c / (cols - 1) - 0.5) * scale.x,
|
|
827
|
-
heights[c * rows + r] * scale.y,
|
|
828
|
-
(r / (rows - 1) - 0.5) * sz
|
|
829
|
-
);
|
|
830
|
-
const step2 = Math.max(1, Math.ceil(Math.max(rows, cols) / 64));
|
|
831
|
-
for (let r = 0; r < rows; r += step2) {
|
|
832
|
-
for (let c = 0; c + step2 < cols; c += step2) {
|
|
833
|
-
at(pa, r, c);
|
|
834
|
-
at(pb, r, c + step2);
|
|
835
|
-
g.line(pa, pb, color);
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
for (let c = 0; c < cols; c += step2) {
|
|
839
|
-
for (let r = 0; r + step2 < rows; r += step2) {
|
|
840
|
-
at(pa, r, c);
|
|
841
|
-
at(pb, r + step2, c);
|
|
842
|
-
g.line(pa, pb, color);
|
|
843
|
-
}
|
|
844
|
-
}
|
|
609
|
+
function physics2dPlugin(options) {
|
|
610
|
+
return physicsPlugin(2, options);
|
|
845
611
|
}
|
|
846
612
|
export {
|
|
847
613
|
Physics,
|
|
848
614
|
PhysicsSystems,
|
|
849
|
-
collidersOverlay,
|
|
850
615
|
physics,
|
|
851
616
|
physics2dPlugin,
|
|
852
617
|
physics3dPlugin
|
package/dist/rapier.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type RAPIER from '@dimforge/rapier3d-compat';
|
|
2
|
+
export type Rapier = typeof RAPIER;
|
|
3
|
+
/**
|
|
4
|
+
* Which Rapier build: `regular` (fastest, deterministic only on one build and platform) or
|
|
5
|
+
* `deterministic` (the same 0.20.0 API, with results that don't depend on the machine).
|
|
6
|
+
*/
|
|
7
|
+
export type RapierVariant = 'regular' | 'deterministic';
|
|
8
|
+
export interface LoadRapierOptions {
|
|
9
|
+
/** Load the deterministic build (default false). */
|
|
10
|
+
deterministic?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Loads and initializes Rapier's WASM for a dimension and variant, once per process. The variants
|
|
14
|
+
* are separate modules, so a page can run both (the game on the regular build, a dice worker on
|
|
15
|
+
* the deterministic one).
|
|
16
|
+
*/
|
|
17
|
+
export declare function loadRapier(dim: 2 | 3, options?: LoadRapierOptions): Promise<Rapier>;
|
|
18
|
+
/**
|
|
19
|
+
* The deterministic 3D build alone. Tracks load it through this, so a track bundle references no
|
|
20
|
+
* other build.
|
|
21
|
+
*/
|
|
22
|
+
export declare function loadDeterministic3d(): Promise<Rapier>;
|
package/dist/rapier.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const modules = /* @__PURE__ */ new Map();
|
|
2
|
+
function cached(key, load) {
|
|
3
|
+
let loading = modules.get(key);
|
|
4
|
+
if (!loading) {
|
|
5
|
+
loading = (async () => {
|
|
6
|
+
const mod = await load();
|
|
7
|
+
const R = mod.default ?? mod;
|
|
8
|
+
await R.init();
|
|
9
|
+
return R;
|
|
10
|
+
})();
|
|
11
|
+
modules.set(key, loading);
|
|
12
|
+
}
|
|
13
|
+
return loading;
|
|
14
|
+
}
|
|
15
|
+
function loadRapier(dim, options) {
|
|
16
|
+
if (options?.deterministic) {
|
|
17
|
+
return dim === 3 ? loadDeterministic3d() : cached("2/deterministic", () => import("@dimforge/rapier2d-deterministic-compat"));
|
|
18
|
+
}
|
|
19
|
+
return dim === 3 ? cached("3/regular", () => import("@dimforge/rapier3d-compat")) : cached("2/regular", () => import("@dimforge/rapier2d-compat"));
|
|
20
|
+
}
|
|
21
|
+
function loadDeterministic3d() {
|
|
22
|
+
return cached("3/deterministic", () => import("@dimforge/rapier3d-deterministic-compat"));
|
|
23
|
+
}
|
|
24
|
+
export {
|
|
25
|
+
loadDeterministic3d,
|
|
26
|
+
loadRapier
|
|
27
|
+
};
|
package/dist/render.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AssetRef, World } from '@aethervtt/shard-core';
|
|
2
|
+
import type { Mesh } from '@aethervtt/shard-mesh';
|
|
3
|
+
/** Collider meshes from the renderer's mesh store. */
|
|
4
|
+
export declare function rendererMeshes(world: World, ref: AssetRef): Mesh | undefined;
|
|
5
|
+
export declare const collidersOverlay: import("@aethervtt/shard-render").OverlayDef;
|