@vworlds/vecs-physics 1.0.53 → 1.0.54
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/adapter/engine.d.ts +12 -3
- package/adapter/engine.js +11 -2
- package/adapter/engine.js.map +1 -1
- package/adapter/queries.d.ts +4 -4
- package/adapter/queries.js +19 -24
- package/adapter/queries.js.map +1 -1
- package/adapter/runtime.d.ts +13 -1
- package/adapter/runtime.js +22 -7
- package/adapter/runtime.js.map +1 -1
- package/body/lifecycle.js +1 -0
- package/body/lifecycle.js.map +1 -1
- package/body/mass.js +1 -1
- package/body/mass.js.map +1 -1
- package/body/pose_in.js +7 -23
- package/body/pose_in.js.map +1 -1
- package/body/pose_out.d.ts +3 -0
- package/body/pose_out.js +59 -55
- package/body/pose_out.js.map +1 -1
- package/core/module.js +4 -2
- package/core/module.js.map +1 -1
- package/core/reaper.js +24 -15
- package/core/reaper.js.map +1 -1
- package/core/step.js +1 -1
- package/core/step.js.map +1 -1
- package/events/publish.d.ts +3 -0
- package/events/publish.js +138 -81
- package/events/publish.js.map +1 -1
- package/forces/gather.js +3 -5
- package/forces/gather.js.map +1 -1
- package/forces/impulses.js +10 -5
- package/forces/impulses.js.map +1 -1
- package/kinematic/targets.js +39 -40
- package/kinematic/targets.js.map +1 -1
- package/materials/sync.js +1 -1
- package/materials/sync.js.map +1 -1
- package/package.json +3 -3
package/body/pose_out.js
CHANGED
|
@@ -1,45 +1,59 @@
|
|
|
1
1
|
import { Module } from "@vworlds/vecs";
|
|
2
|
-
import { getPhysicsEngine, PhysicsSystemTag
|
|
2
|
+
import { getPhysicsEngine, PhysicsSystemTag } from "../adapter/engine.js";
|
|
3
3
|
import { AngularVelocity, Body, BodyType, LinearVelocity, Position, Rotation, } from "./components.js";
|
|
4
4
|
import { PhysicsCoreModule } from "../core/module.js";
|
|
5
|
+
/** Export moved bodies once per post-step tick and write only changed Dynamic-body components.
|
|
6
|
+
* The pinned fast path refreshes heap views; optional components and modification routing remain
|
|
7
|
+
* unchanged, and no per-body Box2D handle, marshalling object or typed-array view is created. */
|
|
5
8
|
export class BodyPoseOutModule extends Module {
|
|
6
9
|
init() {
|
|
7
10
|
const world = this.world;
|
|
8
11
|
world.module(PhysicsCoreModule);
|
|
9
12
|
const engine = getPhysicsEngine(world);
|
|
13
|
+
const fast = engine.fast;
|
|
14
|
+
const move = fast.layout.move;
|
|
15
|
+
const offsets = {
|
|
16
|
+
bodyIndex: move.bodyIndex >> 2,
|
|
17
|
+
x: move.x >> 2,
|
|
18
|
+
y: move.y >> 2,
|
|
19
|
+
angle: move.angle >> 2,
|
|
20
|
+
vx: move.vx >> 2,
|
|
21
|
+
vy: move.vy >> 2,
|
|
22
|
+
w: move.w >> 2,
|
|
23
|
+
};
|
|
24
|
+
const flags = fast.layout.constants.exportVelocity;
|
|
25
|
+
// Numeric ids avoid resolving component classes on every moved body.
|
|
26
|
+
const ids = {
|
|
27
|
+
body: world.entity(Body).eid,
|
|
28
|
+
position: world.entity(Position).eid,
|
|
29
|
+
rotation: world.entity(Rotation).eid,
|
|
30
|
+
linearVelocity: world.entity(LinearVelocity).eid,
|
|
31
|
+
angularVelocity: world.entity(AngularVelocity).eid,
|
|
32
|
+
};
|
|
10
33
|
world
|
|
11
34
|
.system("PhysicsPoseSyncOut")
|
|
12
35
|
.phase(engine.phases.postStep)
|
|
13
36
|
.run(() => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
|
-
const body = entity.get(Body);
|
|
31
|
-
if (body?.type !== BodyType.Dynamic) {
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
writePose(engine, entity, move.transform, bodyId);
|
|
35
|
-
}
|
|
36
|
-
finally {
|
|
37
|
-
move.delete();
|
|
38
|
-
}
|
|
37
|
+
// Export after preceding postStep systems; exportMoves also refreshes memory views.
|
|
38
|
+
const exporter = engine.moveExporter;
|
|
39
|
+
const bodyEntities = engine.bodyEntities;
|
|
40
|
+
const count = exporter.exportMoves(engine.world, flags);
|
|
41
|
+
const i32 = fast.i32;
|
|
42
|
+
const f32 = fast.f32;
|
|
43
|
+
const stride = exporter.stride;
|
|
44
|
+
let base = exporter.base;
|
|
45
|
+
for (let i = 0; i < count; i++, base += stride) {
|
|
46
|
+
// A postStep system may destroy an entity after Box2D produced this event.
|
|
47
|
+
// Keep the reverse slot until the reaper frees the body; lookup is O(1).
|
|
48
|
+
const entity = bodyEntities[i32[base + offsets.bodyIndex]];
|
|
49
|
+
if (entity === undefined || entity.destroyed) {
|
|
50
|
+
continue;
|
|
39
51
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
52
|
+
const body = entity.get(ids.body);
|
|
53
|
+
if (body?.type !== BodyType.Dynamic) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
writePose(entity, f32, base, offsets, ids);
|
|
43
57
|
}
|
|
44
58
|
})
|
|
45
59
|
.add(PhysicsSystemTag);
|
|
@@ -67,45 +81,35 @@ export class BodyPoseOutModule extends Module {
|
|
|
67
81
|
* nothing per body: the new values are read into locals and compared directly, and the `{ x, y }`
|
|
68
82
|
* literals exist only on the write path.
|
|
69
83
|
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* the C++ destructor on an interior pointer of the event, which corrupts the wasm heap. The event's
|
|
74
|
-
* single `move.delete()` releases the memory. The linear velocity is a by-value return, a heap copy
|
|
75
|
-
* this function owns and deletes.
|
|
84
|
+
* Values come from the move record exported after preceding postStep systems. The angle uses
|
|
85
|
+
* Box2D's b2Rot_GetAngle, preserving its exact bits, and velocities use the same Box2D getters
|
|
86
|
+
* in wasm. Reading these f32 records creates no embind handle or allocation.
|
|
76
87
|
*/
|
|
77
|
-
function writePose(
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
const position = entity.get(Position);
|
|
88
|
+
function writePose(entity, f32, base, offsets, ids) {
|
|
89
|
+
const x = f32[base + offsets.x];
|
|
90
|
+
const y = f32[base + offsets.y];
|
|
91
|
+
const position = entity.get(ids.position);
|
|
82
92
|
if (position === undefined || position.x !== x || position.y !== y) {
|
|
83
93
|
entity.set(Position, { x, y });
|
|
84
94
|
}
|
|
85
|
-
const rotation = entity.get(
|
|
95
|
+
const rotation = entity.get(ids.rotation);
|
|
86
96
|
if (rotation !== undefined) {
|
|
87
|
-
const angle =
|
|
97
|
+
const angle = f32[base + offsets.angle];
|
|
88
98
|
if (rotation.angle !== angle) {
|
|
89
99
|
entity.set(Rotation, { angle });
|
|
90
100
|
}
|
|
91
101
|
}
|
|
92
|
-
const linearVelocity = entity.get(
|
|
102
|
+
const linearVelocity = entity.get(ids.linearVelocity);
|
|
93
103
|
if (linearVelocity !== undefined) {
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (linearVelocity.x !== vx || linearVelocity.y !== vy) {
|
|
99
|
-
entity.set(LinearVelocity, { x: vx, y: vy });
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
finally {
|
|
103
|
-
linear.delete();
|
|
104
|
+
const vx = f32[base + offsets.vx];
|
|
105
|
+
const vy = f32[base + offsets.vy];
|
|
106
|
+
if (linearVelocity.x !== vx || linearVelocity.y !== vy) {
|
|
107
|
+
entity.set(LinearVelocity, { x: vx, y: vy });
|
|
104
108
|
}
|
|
105
109
|
}
|
|
106
|
-
const angularVelocity = entity.get(
|
|
110
|
+
const angularVelocity = entity.get(ids.angularVelocity);
|
|
107
111
|
if (angularVelocity !== undefined) {
|
|
108
|
-
const value =
|
|
112
|
+
const value = f32[base + offsets.w];
|
|
109
113
|
if (angularVelocity.value !== value) {
|
|
110
114
|
entity.set(AngularVelocity, { value });
|
|
111
115
|
}
|
package/body/pose_out.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pose_out.js","sourceRoot":"","sources":["../../../../src/body/pose_out.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAe,MAAM,eAAe,CAAC;AAEpD,OAAO,
|
|
1
|
+
{"version":3,"file":"pose_out.js","sourceRoot":"","sources":["../../../../src/body/pose_out.ts"],"names":[],"mappings":"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"}
|
package/core/module.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { insertPhaseAfter, Module, ON_UPDATE, Phase, Singleton, } from "@vworlds/vecs";
|
|
2
2
|
import { hasPhysicsEngine, PhysicsEngine, PhysicsSystemTag, } from "../adapter/engine.js";
|
|
3
3
|
import { withAllocated } from "../adapter/disposal.js";
|
|
4
|
-
import { getBox2D } from "../adapter/runtime.js";
|
|
4
|
+
import { getBox2D, getFastPath } from "../adapter/runtime.js";
|
|
5
5
|
const DEFAULT_PRE_STEP_PHASE = "physics-pre";
|
|
6
6
|
const DEFAULT_STEP_PHASE = "physics-step";
|
|
7
7
|
const DEFAULT_POST_STEP_PHASE = "physics-post";
|
|
@@ -29,8 +29,10 @@ export class PhysicsCoreModule extends Module {
|
|
|
29
29
|
insertPhaseAfter(phases.postStep, phases.step);
|
|
30
30
|
const box2d = getBox2D();
|
|
31
31
|
const resolved = resolveOptions(opts);
|
|
32
|
-
const
|
|
32
|
+
const fast = getFastPath();
|
|
33
|
+
const engine = new PhysicsEngine(box2d, resolved, phases, fast, opts.debugSink);
|
|
33
34
|
engine.worldId = createWorldId(engine, resolved);
|
|
35
|
+
engine.world = fast.world(engine.worldId);
|
|
34
36
|
world.component(PhysicsEngine).add(Singleton);
|
|
35
37
|
world.component(PhysicsEngine).attach(PhysicsEngine, engine);
|
|
36
38
|
}
|
package/core/module.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.js","sourceRoot":"","sources":["../../../../src/core/module.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,MAAM,EACN,SAAS,EACT,KAAK,EACL,SAAS,GAGV,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,gBAAgB,GAEjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"module.js","sourceRoot":"","sources":["../../../../src/core/module.ts"],"names":[],"mappings":"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"}
|
package/core/reaper.js
CHANGED
|
@@ -15,29 +15,38 @@ export class PhysicsReaperModule extends Module {
|
|
|
15
15
|
// with b2Joint_IsValid because a joint queued from a cascaded body entity
|
|
16
16
|
// may already be gone.
|
|
17
17
|
const joints = engine.pendingJointDestroys;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
engine.box2d.
|
|
18
|
+
if (joints.length > 0) {
|
|
19
|
+
for (const jointId of joints) {
|
|
20
|
+
if (engine.box2d.b2Joint_IsValid(jointId)) {
|
|
21
|
+
engine.box2d.b2DestroyJoint(jointId, true);
|
|
22
|
+
}
|
|
21
23
|
}
|
|
24
|
+
joints.length = 0;
|
|
22
25
|
}
|
|
23
|
-
joints.length = 0;
|
|
24
26
|
const shapes = engine.pendingShapeDestroys;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
if (shapes.length > 0) {
|
|
28
|
+
for (const shapeId of shapes) {
|
|
29
|
+
engine.entityByShapeIndex.delete(shapeId.index1);
|
|
30
|
+
engine.box2d.b2DestroyShape(shapeId, true);
|
|
31
|
+
}
|
|
32
|
+
shapes.length = 0;
|
|
28
33
|
}
|
|
29
|
-
shapes.length = 0;
|
|
30
34
|
const chains = engine.pendingChainDestroys;
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
if (chains.length > 0) {
|
|
36
|
+
for (const chainId of chains) {
|
|
37
|
+
engine.box2d.b2DestroyChain(chainId);
|
|
38
|
+
}
|
|
39
|
+
chains.length = 0;
|
|
33
40
|
}
|
|
34
|
-
chains.length = 0;
|
|
35
41
|
const bodies = engine.pendingBodyDestroys;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
if (bodies.length > 0) {
|
|
43
|
+
for (const bodyId of bodies) {
|
|
44
|
+
engine.entityByBodyIndex.delete(bodyId.index1);
|
|
45
|
+
engine.bodyEntities[bodyId.index1] = undefined;
|
|
46
|
+
engine.box2d.b2DestroyBody(bodyId);
|
|
47
|
+
}
|
|
48
|
+
bodies.length = 0;
|
|
39
49
|
}
|
|
40
|
-
bodies.length = 0;
|
|
41
50
|
})
|
|
42
51
|
.add(PhysicsSystemTag);
|
|
43
52
|
}
|
package/core/reaper.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reaper.js","sourceRoot":"","sources":["../../../../src/core/reaper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,OAAO,mBAAoB,SAAQ,MAAM;IACtC,IAAI;QACT,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;QAEhC,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACvC,KAAK;aACF,MAAM,CAAC,eAAe,CAAC;aACvB,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;aAC5B,GAAG,CAAC,GAAG,EAAE;YACR,wEAAwE;YACxE,2EAA2E;YAC3E,0EAA0E;YAC1E,uBAAuB;YACvB,MAAM,MAAM,GAAG,MAAM,CAAC,oBAAoB,CAAC;YAC3C,KAAK,MAAM,OAAO,IAAI,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"reaper.js","sourceRoot":"","sources":["../../../../src/core/reaper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,OAAO,mBAAoB,SAAQ,MAAM;IACtC,IAAI;QACT,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;QAEhC,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACvC,KAAK;aACF,MAAM,CAAC,eAAe,CAAC;aACvB,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;aAC5B,GAAG,CAAC,GAAG,EAAE;YACR,wEAAwE;YACxE,2EAA2E;YAC3E,0EAA0E;YAC1E,uBAAuB;YACvB,MAAM,MAAM,GAAG,MAAM,CAAC,oBAAoB,CAAC;YAC3C,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,KAAK,MAAM,OAAO,IAAI,MAAM,EAAE,CAAC;oBAC7B,IAAI,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;wBAC1C,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;oBAC7C,CAAC;gBACH,CAAC;gBACD,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;YACpB,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,CAAC,oBAAoB,CAAC;YAC3C,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,KAAK,MAAM,OAAO,IAAI,MAAM,EAAE,CAAC;oBAC7B,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;oBACjD,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;gBAC7C,CAAC;gBACD,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;YACpB,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,CAAC,oBAAoB,CAAC;YAC3C,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,KAAK,MAAM,OAAO,IAAI,MAAM,EAAE,CAAC;oBAC7B,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;gBACvC,CAAC;gBACD,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;YACpB,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,CAAC,mBAAmB,CAAC;YAC1C,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,KAAK,MAAM,MAAM,IAAI,MAAM,EAAE,CAAC;oBAC5B,MAAM,CAAC,iBAAiB,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;oBAC/C,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;oBAC/C,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;gBACrC,CAAC;gBACD,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;YACpB,CAAC;QACH,CAAC,CAAC;aACD,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC3B,CAAC;CACF"}
|
package/core/step.js
CHANGED
|
@@ -14,7 +14,7 @@ export class PhysicsStepModule extends Module {
|
|
|
14
14
|
engine.warn.warnOnce(0, "delta-mismatch", `frame delta ${delta}ms does not match fixedTimeStep ${engine.fixedTimeStep * 1000}ms; ` +
|
|
15
15
|
`physics expects a fixed delta.`);
|
|
16
16
|
}
|
|
17
|
-
engine.box2d.
|
|
17
|
+
engine.box2d._b2x_World_Step(engine.world, engine.fixedTimeStep, engine.subSteps);
|
|
18
18
|
})
|
|
19
19
|
.add(PhysicsSystemTag);
|
|
20
20
|
}
|
package/core/step.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"step.js","sourceRoot":"","sources":["../../../../src/core/step.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,OAAO,iBAAkB,SAAQ,MAAM;IACpC,IAAI;QACT,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;QAEhC,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACvC,KAAK;aACF,MAAM,CAAC,aAAa,CAAC;aACrB,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;aACzB,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YACnB,IAAI,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,GAAG,MAAM,CAAC,aAAa,CAAC,GAAG,IAAI,EAAE,CAAC;gBACzE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAClB,CAAC,EACD,gBAAgB,EAChB,eAAe,KAAK,mCAAmC,MAAM,CAAC,aAAa,GAAG,IAAI,MAAM;oBACtF,gCAAgC,CACnC,CAAC;YACJ,CAAC;YACD,MAAM,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"step.js","sourceRoot":"","sources":["../../../../src/core/step.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,OAAO,iBAAkB,SAAQ,MAAM;IACpC,IAAI;QACT,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;QAEhC,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACvC,KAAK;aACF,MAAM,CAAC,aAAa,CAAC;aACrB,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;aACzB,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YACnB,IAAI,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,GAAG,MAAM,CAAC,aAAa,CAAC,GAAG,IAAI,EAAE,CAAC;gBACzE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAClB,CAAC,EACD,gBAAgB,EAChB,eAAe,KAAK,mCAAmC,MAAM,CAAC,aAAa,GAAG,IAAI,MAAM;oBACtF,gCAAgC,CACnC,CAAC;YACJ,CAAC;YACD,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QACpF,CAAC,CAAC;aACD,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC3B,CAAC;CACF"}
|
package/events/publish.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { Module } from "@vworlds/vecs";
|
|
2
|
+
/** Read contact/hit/sensor spans once per tick and publish fresh public event records in order.
|
|
3
|
+
* Native reads allocate no per-event wrappers; event components retain clear-in-place arrays
|
|
4
|
+
* and are marked modified once per receiving entity with new events. */
|
|
2
5
|
export declare class EventPublishModule extends Module {
|
|
3
6
|
init(): void;
|
|
4
7
|
}
|
package/events/publish.js
CHANGED
|
@@ -3,21 +3,34 @@ import { ContactEvents, HitEvents, SensorEvents } from "./components.js";
|
|
|
3
3
|
import { getPhysicsEngine, PhysicsSystemTag } from "../adapter/engine.js";
|
|
4
4
|
import { PhysicsCoreModule } from "../core/module.js";
|
|
5
5
|
import { EventsModule } from "./module.js";
|
|
6
|
+
/** Read contact/hit/sensor spans once per tick and publish fresh public event records in order.
|
|
7
|
+
* Native reads allocate no per-event wrappers; event components retain clear-in-place arrays
|
|
8
|
+
* and are marked modified once per receiving entity with new events. */
|
|
6
9
|
export class EventPublishModule extends Module {
|
|
7
10
|
init() {
|
|
8
11
|
const world = this.world;
|
|
9
12
|
world.module(PhysicsCoreModule);
|
|
10
13
|
world.module(EventsModule);
|
|
11
14
|
const engine = getPhysicsEngine(world);
|
|
15
|
+
const offsets = eventOffsets(engine);
|
|
16
|
+
// Span headers and touched sets are allocated once and reused each step.
|
|
17
|
+
const spans = engine.fast.alloc(engine.fast.layout.contactSpans.size + engine.fast.layout.sensorSpans.size);
|
|
18
|
+
const sensorSpans = spans + engine.fast.layout.contactSpans.size;
|
|
19
|
+
const touchedContact = new Set();
|
|
20
|
+
const touchedSensor = new Set();
|
|
21
|
+
const touchedHit = new Set();
|
|
12
22
|
world
|
|
13
23
|
.system("PhysicsEvents")
|
|
14
24
|
.phase(engine.phases.postStep)
|
|
15
25
|
.run(() => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
26
|
+
clearSet(touchedContact);
|
|
27
|
+
clearSet(touchedSensor);
|
|
28
|
+
clearSet(touchedHit);
|
|
29
|
+
engine.box2d._b2x_World_GetContactSpans(engine.world, spans);
|
|
30
|
+
engine.box2d._b2x_World_GetSensorSpans(engine.world, sensorSpans);
|
|
31
|
+
engine.fast.sync();
|
|
32
|
+
publishContactAndHitEvents(world, engine, spans, offsets, touchedContact, touchedHit);
|
|
33
|
+
publishSensorEvents(world, engine, sensorSpans, offsets, touchedSensor);
|
|
21
34
|
markModified(world, touchedContact, ContactEvents);
|
|
22
35
|
markModified(world, touchedSensor, SensorEvents);
|
|
23
36
|
markModified(world, touchedHit, HitEvents);
|
|
@@ -25,84 +38,104 @@ export class EventPublishModule extends Module {
|
|
|
25
38
|
clearUntouchedSensorEvents(world, engine.prevTouchedSensor, touchedSensor);
|
|
26
39
|
clearUntouchedHitEvents(world, engine.prevTouchedHit, touchedHit);
|
|
27
40
|
// Store touched sets on engine for the next step's clear pass.
|
|
28
|
-
engine.prevTouchedContact
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
engine.prevTouchedSensor.clear();
|
|
33
|
-
for (const eid of touchedSensor) {
|
|
34
|
-
engine.prevTouchedSensor.add(eid);
|
|
35
|
-
}
|
|
36
|
-
engine.prevTouchedHit.clear();
|
|
37
|
-
for (const eid of touchedHit) {
|
|
38
|
-
engine.prevTouchedHit.add(eid);
|
|
39
|
-
}
|
|
41
|
+
copySet(engine.prevTouchedContact, touchedContact);
|
|
42
|
+
copySet(engine.prevTouchedSensor, touchedSensor);
|
|
43
|
+
copySet(engine.prevTouchedHit, touchedHit);
|
|
40
44
|
})
|
|
41
45
|
.add(PhysicsSystemTag);
|
|
42
46
|
}
|
|
43
47
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
48
|
+
function eventOffsets(engine) {
|
|
49
|
+
const L = engine.fast.layout;
|
|
50
|
+
const pair = (s, a, b) => ({
|
|
51
|
+
stride: s.size >> 2,
|
|
52
|
+
a: a >> 2,
|
|
53
|
+
b: b >> 2,
|
|
54
|
+
});
|
|
55
|
+
const words = (o) => Object.fromEntries(Object.entries(o).map(([k, v]) => [k, v >> 2]));
|
|
56
|
+
return {
|
|
57
|
+
contact: words({
|
|
58
|
+
beginPtr: L.contactSpans.beginPtr,
|
|
59
|
+
beginCount: L.contactSpans.beginCount,
|
|
60
|
+
endPtr: L.contactSpans.endPtr,
|
|
61
|
+
endCount: L.contactSpans.endCount,
|
|
62
|
+
hitPtr: L.contactSpans.hitPtr,
|
|
63
|
+
hitCount: L.contactSpans.hitCount,
|
|
64
|
+
}),
|
|
65
|
+
sensor: words({
|
|
66
|
+
beginPtr: L.sensorSpans.beginPtr,
|
|
67
|
+
beginCount: L.sensorSpans.beginCount,
|
|
68
|
+
endPtr: L.sensorSpans.endPtr,
|
|
69
|
+
endCount: L.sensorSpans.endCount,
|
|
70
|
+
}),
|
|
71
|
+
begin: pair(L.contactBegin, L.contactBegin.shapeA, L.contactBegin.shapeB),
|
|
72
|
+
end: pair(L.contactEnd, L.contactEnd.shapeA, L.contactEnd.shapeB),
|
|
73
|
+
hit: {
|
|
74
|
+
...pair(L.contactHit, L.contactHit.shapeA, L.contactHit.shapeB),
|
|
75
|
+
pointX: L.contactHit.pointX >> 2,
|
|
76
|
+
pointY: L.contactHit.pointY >> 2,
|
|
77
|
+
normalX: L.contactHit.normalX >> 2,
|
|
78
|
+
normalY: L.contactHit.normalY >> 2,
|
|
79
|
+
approachSpeed: L.contactHit.approachSpeed >> 2,
|
|
80
|
+
},
|
|
81
|
+
sensorBegin: pair(L.sensorBegin, L.sensorBegin.sensorShape, L.sensorBegin.visitorShape),
|
|
82
|
+
sensorEnd: pair(L.sensorEnd, L.sensorEnd.sensorShape, L.sensorEnd.visitorShape),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
// Poll once per step, reading Box2D's own arrays in begin/end/hit order. Spans are valid
|
|
86
|
+
// until the next step or world mutation; the loop does not call allocating Box2D APIs.
|
|
87
|
+
function publishContactAndHitEvents(world, engine, spans, offsets, touchedContact, touchedHit) {
|
|
88
|
+
const fast = engine.fast;
|
|
89
|
+
const i32 = fast.i32;
|
|
90
|
+
const u32 = fast.u32;
|
|
91
|
+
const f32 = fast.f32;
|
|
92
|
+
const header = spans >> 2;
|
|
93
|
+
const c = offsets.contact;
|
|
94
|
+
const begin = offsets.begin;
|
|
95
|
+
let at = u32[header + c.beginPtr] >> 2;
|
|
96
|
+
for (let i = 0, n = i32[header + c.beginCount]; i < n; i++, at += begin.stride) {
|
|
97
|
+
emitContactEvent(world, engine, touchedContact, i32[at + begin.a], i32[at + begin.b], "begin");
|
|
98
|
+
}
|
|
99
|
+
const end = offsets.end;
|
|
100
|
+
at = u32[header + c.endPtr] >> 2;
|
|
101
|
+
for (let i = 0, n = i32[header + c.endCount]; i < n; i++, at += end.stride) {
|
|
102
|
+
emitContactEvent(world, engine, touchedContact, i32[at + end.a], i32[at + end.b], "end");
|
|
75
103
|
}
|
|
76
|
-
|
|
77
|
-
|
|
104
|
+
const hit = offsets.hit;
|
|
105
|
+
at = u32[header + c.hitPtr] >> 2;
|
|
106
|
+
for (let i = 0, n = i32[header + c.hitCount]; i < n; i++, at += hit.stride) {
|
|
107
|
+
emitHitEvent(world, engine, touchedHit, i32, f32, at, hit);
|
|
78
108
|
}
|
|
79
109
|
}
|
|
80
|
-
function publishSensorEvents(world, engine, touched) {
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
110
|
+
function publishSensorEvents(world, engine, spans, offsets, touched) {
|
|
111
|
+
const fast = engine.fast;
|
|
112
|
+
const i32 = fast.i32;
|
|
113
|
+
const u32 = fast.u32;
|
|
114
|
+
const header = spans >> 2;
|
|
115
|
+
const s = offsets.sensor;
|
|
116
|
+
const begin = offsets.sensorBegin;
|
|
117
|
+
let at = u32[header + s.beginPtr] >> 2;
|
|
118
|
+
for (let i = 0, n = i32[header + s.beginCount]; i < n; i++, at += begin.stride) {
|
|
119
|
+
emitSensorEvent(world, engine, touched, i32[at + begin.a], i32[at + begin.b], "begin");
|
|
89
120
|
}
|
|
90
|
-
|
|
91
|
-
|
|
121
|
+
const end = offsets.sensorEnd;
|
|
122
|
+
at = u32[header + s.endPtr] >> 2;
|
|
123
|
+
for (let i = 0, n = i32[header + s.endCount]; i < n; i++, at += end.stride) {
|
|
124
|
+
emitSensorEvent(world, engine, touched, i32[at + end.a], i32[at + end.b], "end");
|
|
92
125
|
}
|
|
93
126
|
}
|
|
94
|
-
function emitContactEvent(world, engine, touched,
|
|
95
|
-
const entityA = getLiveEntity(world, engine.entityByShapeIndex.get(
|
|
96
|
-
const entityB = getLiveEntity(world, engine.entityByShapeIndex.get(
|
|
127
|
+
function emitContactEvent(world, engine, touched, shapeA, shapeB, kind) {
|
|
128
|
+
const entityA = getLiveEntity(world, engine.entityByShapeIndex.get(shapeA));
|
|
129
|
+
const entityB = getLiveEntity(world, engine.entityByShapeIndex.get(shapeB));
|
|
97
130
|
if (entityA === undefined || entityB === undefined) {
|
|
98
131
|
return;
|
|
99
132
|
}
|
|
100
133
|
emitContactToEntity(touched, entityA, entityB, kind);
|
|
101
134
|
emitContactToEntity(touched, entityB, entityA, kind);
|
|
102
135
|
}
|
|
103
|
-
function emitSensorEvent(world, engine, touched,
|
|
104
|
-
const sensor = getLiveEntity(world, engine.entityByShapeIndex.get(
|
|
105
|
-
const visitor = getLiveEntity(world, engine.entityByShapeIndex.get(
|
|
136
|
+
function emitSensorEvent(world, engine, touched, sensorShape, visitorShape, kind) {
|
|
137
|
+
const sensor = getLiveEntity(world, engine.entityByShapeIndex.get(sensorShape));
|
|
138
|
+
const visitor = getLiveEntity(world, engine.entityByShapeIndex.get(visitorShape));
|
|
106
139
|
if (sensor === undefined || visitor === undefined) {
|
|
107
140
|
return;
|
|
108
141
|
}
|
|
@@ -122,14 +155,29 @@ function emitSensorEvent(world, engine, touched, event, kind) {
|
|
|
122
155
|
events.end.push({ other: visitor });
|
|
123
156
|
}
|
|
124
157
|
}
|
|
125
|
-
function emitHitEvent(world, engine, touched,
|
|
126
|
-
const entityA = getLiveEntity(world, engine.entityByShapeIndex.get(
|
|
127
|
-
const entityB = getLiveEntity(world, engine.entityByShapeIndex.get(
|
|
158
|
+
function emitHitEvent(world, engine, touched, i32, f32, at, hit) {
|
|
159
|
+
const entityA = getLiveEntity(world, engine.entityByShapeIndex.get(i32[at + hit.a]));
|
|
160
|
+
const entityB = getLiveEntity(world, engine.entityByShapeIndex.get(i32[at + hit.b]));
|
|
128
161
|
if (entityA === undefined || entityB === undefined) {
|
|
129
162
|
return;
|
|
130
163
|
}
|
|
131
|
-
emitHitToEntity(touched, entityA, entityB,
|
|
132
|
-
emitHitToEntity(touched, entityB, entityA,
|
|
164
|
+
emitHitToEntity(touched, entityA, entityB, f32, at, hit);
|
|
165
|
+
emitHitToEntity(touched, entityB, entityA, f32, at, hit);
|
|
166
|
+
}
|
|
167
|
+
/** Avoid replacing V8's Set backing table when there is nothing to clear. */
|
|
168
|
+
function clearSet(set) {
|
|
169
|
+
if (set.size > 0) {
|
|
170
|
+
set.clear();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function copySet(target, source) {
|
|
174
|
+
clearSet(target);
|
|
175
|
+
if (source.size === 0) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
for (const eid of source) {
|
|
179
|
+
target.add(eid);
|
|
180
|
+
}
|
|
133
181
|
}
|
|
134
182
|
function emitContactToEntity(touched, entity, other, kind) {
|
|
135
183
|
const events = entity.get(ContactEvents);
|
|
@@ -148,7 +196,7 @@ function emitContactToEntity(touched, entity, other, kind) {
|
|
|
148
196
|
events.end.push({ other });
|
|
149
197
|
}
|
|
150
198
|
}
|
|
151
|
-
function emitHitToEntity(touched, entity, other,
|
|
199
|
+
function emitHitToEntity(touched, entity, other, f32, at, hit) {
|
|
152
200
|
const events = entity.get(HitEvents);
|
|
153
201
|
if (events === undefined) {
|
|
154
202
|
return;
|
|
@@ -159,11 +207,11 @@ function emitHitToEntity(touched, entity, other, event) {
|
|
|
159
207
|
}
|
|
160
208
|
events.hits.push({
|
|
161
209
|
other,
|
|
162
|
-
x:
|
|
163
|
-
y:
|
|
164
|
-
normalX:
|
|
165
|
-
normalY:
|
|
166
|
-
speed:
|
|
210
|
+
x: f32[at + hit.pointX],
|
|
211
|
+
y: f32[at + hit.pointY],
|
|
212
|
+
normalX: f32[at + hit.normalX],
|
|
213
|
+
normalY: f32[at + hit.normalY],
|
|
214
|
+
speed: f32[at + hit.approachSpeed],
|
|
167
215
|
});
|
|
168
216
|
}
|
|
169
217
|
function getLiveEntity(world, entityId) {
|
|
@@ -177,11 +225,17 @@ function getLiveEntity(world, entityId) {
|
|
|
177
225
|
return entity;
|
|
178
226
|
}
|
|
179
227
|
function markModified(world, touched, component) {
|
|
228
|
+
if (touched.size === 0) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
180
231
|
for (const entityId of touched) {
|
|
181
232
|
world.getEntity(entityId)?.modified(component);
|
|
182
233
|
}
|
|
183
234
|
}
|
|
184
235
|
function clearUntouchedContactEvents(world, previouslyTouched, touched) {
|
|
236
|
+
if (previouslyTouched.size === 0) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
185
239
|
for (const entityId of previouslyTouched) {
|
|
186
240
|
if (touched.has(entityId)) {
|
|
187
241
|
continue;
|
|
@@ -194,6 +248,9 @@ function clearUntouchedContactEvents(world, previouslyTouched, touched) {
|
|
|
194
248
|
}
|
|
195
249
|
}
|
|
196
250
|
function clearUntouchedSensorEvents(world, previouslyTouched, touched) {
|
|
251
|
+
if (previouslyTouched.size === 0) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
197
254
|
for (const entityId of previouslyTouched) {
|
|
198
255
|
if (touched.has(entityId)) {
|
|
199
256
|
continue;
|
|
@@ -206,6 +263,9 @@ function clearUntouchedSensorEvents(world, previouslyTouched, touched) {
|
|
|
206
263
|
}
|
|
207
264
|
}
|
|
208
265
|
function clearUntouchedHitEvents(world, previouslyTouched, touched) {
|
|
266
|
+
if (previouslyTouched.size === 0) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
209
269
|
for (const entityId of previouslyTouched) {
|
|
210
270
|
if (touched.has(entityId)) {
|
|
211
271
|
continue;
|
|
@@ -216,9 +276,6 @@ function clearUntouchedHitEvents(world, previouslyTouched, touched) {
|
|
|
216
276
|
}
|
|
217
277
|
}
|
|
218
278
|
}
|
|
219
|
-
function deleteIfPresent(value) {
|
|
220
|
-
value.delete?.();
|
|
221
|
-
}
|
|
222
279
|
function isDestroyed(entity) {
|
|
223
280
|
return entity.destroyed;
|
|
224
281
|
}
|