@flighthq/physics2d 0.5.1-next.3302.76ece6b → 0.5.1-next.4304.322dc96
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/README.md
CHANGED
|
@@ -13,5 +13,5 @@ Import the supported application-facing API from `@flighthq/physics2d`. The `@fl
|
|
|
13
13
|
This package is part of the locked-version Flight SDK graph. Applications may instead install and import `@flighthq/sdk` when package-level tree shaking is sufficient.
|
|
14
14
|
|
|
15
15
|
- [Flight project](https://github.com/flighthq/flight)
|
|
16
|
-
- [Source for @flighthq/physics2d@0.5.1-next.
|
|
17
|
-
- [License](https://github.com/flighthq/flight/blob/
|
|
16
|
+
- [Source for @flighthq/physics2d@0.5.1-next.4304.322dc96](https://github.com/flighthq/flight/tree/322dc963fc5a404a31bc0cc612e906de504ea024/packages/physics2d)
|
|
17
|
+
- [License](https://github.com/flighthq/flight/blob/322dc963fc5a404a31bc0cc612e906de504ea024/LICENSE.md)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
+
import type { LogState } from '@flighthq/log/contract';
|
|
1
2
|
export declare function arePhysics2DGuardsEnabled(): boolean;
|
|
2
3
|
export declare function disablePhysics2DGuards(): void;
|
|
3
|
-
export declare function enablePhysics2DGuards(): void;
|
|
4
|
+
export declare function enablePhysics2DGuards(logState: LogState, clock: () => number): void;
|
|
4
5
|
//# sourceMappingURL=enablePhysics2DGuards.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enablePhysics2DGuards.d.ts","sourceRoot":"","sources":["../src/enablePhysics2DGuards.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"enablePhysics2DGuards.d.ts","sourceRoot":"","sources":["../src/enablePhysics2DGuards.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAavD,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAK7C;AAyBD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,MAAM,GAAG,IAAI,CAKnF"}
|
|
@@ -36,10 +36,10 @@ export function disablePhysics2DGuards() {
|
|
|
36
36
|
// through the floor with nothing failing anywhere.
|
|
37
37
|
//
|
|
38
38
|
// Applications that never import this module shed both the message text and `@flighthq/log`.
|
|
39
|
-
export function enablePhysics2DGuards() {
|
|
40
|
-
setPhysics2DStepGuard(warnOnUnsteppablePhysics2DWorld);
|
|
41
|
-
setPhysics2DJointResolutionGuard(warnOnUnresolvedPhysics2DJoints);
|
|
42
|
-
setPhysics2DContactIntakeGuard(warnOnUndetectablePhysics2DColliders);
|
|
39
|
+
export function enablePhysics2DGuards(logState, clock) {
|
|
40
|
+
setPhysics2DStepGuard((world, dt) => warnOnUnsteppablePhysics2DWorld(logState, clock(), world, dt));
|
|
41
|
+
setPhysics2DJointResolutionGuard((world) => warnOnUnresolvedPhysics2DJoints(logState, clock(), world));
|
|
42
|
+
setPhysics2DContactIntakeGuard((world) => warnOnUndetectablePhysics2DColliders(logState, clock(), world));
|
|
43
43
|
physics2DGuardsEnabled = true;
|
|
44
44
|
}
|
|
45
45
|
// The names of the flags that are false, in the explanation's own field order so the key is stable for a
|
|
@@ -70,12 +70,12 @@ function getUnresolvedPhysics2DJointFaults(explanation) {
|
|
|
70
70
|
//
|
|
71
71
|
// Keyed on the kinds rather than logged per step, so a 60Hz loop says this once — and a world that later
|
|
72
72
|
// gains a second undetectable kind still says so.
|
|
73
|
-
function warnOnUndetectablePhysics2DColliders(world) {
|
|
73
|
+
function warnOnUndetectablePhysics2DColliders(logState, nowMs, world) {
|
|
74
74
|
const explanation = explainPhysics2DCollision(world);
|
|
75
75
|
if (explanation.status === 'ready')
|
|
76
76
|
return;
|
|
77
77
|
const kinds = explanation.unsupportedKinds;
|
|
78
|
-
logOnce(`physics2d:${explanation.status}:${kinds.join(',')}`, LogLevel.Warn, {
|
|
78
|
+
logOnce(logState, nowMs, `physics2d:${explanation.status}:${kinds.join(',')}`, LogLevel.Warn, {
|
|
79
79
|
kinds,
|
|
80
80
|
message: `stepPhysics2D: collider kind${kinds.length === 1 ? '' : 's'} ${kinds.join(', ')} enclose${kinds.length === 1 ? 's' : ''} no area and so generate${kinds.length === 1 ? 's' : ''} no contacts, and the bodies carrying ${kinds.length === 1 ? 'it' : 'them'} pass through everything — give the body a shape with area. Call explainPhysics2DCollision(world) for the same finding as data.`,
|
|
81
81
|
status: explanation.status,
|
|
@@ -86,7 +86,7 @@ function warnOnUndetectablePhysics2DColliders(world) {
|
|
|
86
86
|
// The two fault families need different advice, so the message names whichever applies rather than
|
|
87
87
|
// reciting a generic one: an unregistered solver is repaired by registering it, while a missing endpoint
|
|
88
88
|
// means the joint outlived a body and should have been removed with it.
|
|
89
|
-
function warnOnUnresolvedPhysics2DJoints(world) {
|
|
89
|
+
function warnOnUnresolvedPhysics2DJoints(logState, nowMs, world) {
|
|
90
90
|
const explanation = explainPhysics2DJoints(world);
|
|
91
91
|
if (explanation.status === 'complete')
|
|
92
92
|
return;
|
|
@@ -100,7 +100,7 @@ function warnOnUnresolvedPhysics2DJoints(world) {
|
|
|
100
100
|
const endpointAdvice = missing
|
|
101
101
|
? " — a joint whose endpoint body is gone is skipped for the rest of the world's life and should be removed with the body"
|
|
102
102
|
: '';
|
|
103
|
-
logOnce(`physics2d:${explanation.status}:${faults.join(',')}`, LogLevel.Warn, {
|
|
103
|
+
logOnce(logState, nowMs, `physics2d:${explanation.status}:${faults.join(',')}`, LogLevel.Warn, {
|
|
104
104
|
faults,
|
|
105
105
|
message: `stepPhysics2D: ${String(unresolvedCount)} of ${String(explanation.joints.length)} joint${explanation.joints.length === 1 ? '' : 's'} ${unresolvedCount === 1 ? 'is' : 'are'} never solved (${faults.join(', ')}), and the rest of the world simulates normally around ${unresolvedCount === 1 ? 'it' : 'them'}${advice}${endpointAdvice}. Call explainPhysics2DJoints(world) for the same findings as data, per joint.`,
|
|
106
106
|
status: explanation.status,
|
|
@@ -115,12 +115,12 @@ function warnOnUnresolvedPhysics2DJoints(world) {
|
|
|
115
115
|
//
|
|
116
116
|
// Keyed on the failing set, so a loop calling this at 60Hz logs once and not once per frame, while a world
|
|
117
117
|
// that develops a SECOND fault after the first is repaired still says so.
|
|
118
|
-
function warnOnUnsteppablePhysics2DWorld(world, dt) {
|
|
118
|
+
function warnOnUnsteppablePhysics2DWorld(logState, nowMs, world, dt) {
|
|
119
119
|
const explanation = explainPhysics2DStep(world, dt);
|
|
120
120
|
const failing = getFailingPhysics2DPreconditions(explanation);
|
|
121
121
|
if (failing.length === 0)
|
|
122
122
|
return;
|
|
123
|
-
logOnce(`physics2d:${explanation.status}:${failing.join(',')}`, LogLevel.Warn, {
|
|
123
|
+
logOnce(logState, nowMs, `physics2d:${explanation.status}:${failing.join(',')}`, LogLevel.Warn, {
|
|
124
124
|
failing,
|
|
125
125
|
message: `stepPhysics2D: the world advanced nothing because ${failing.length === 1 ? 'a precondition' : 'several preconditions'} failed (${failing.join(', ')}) — call explainPhysics2DStep(world, dt) for the same flags as data, and repair the reported fields.`,
|
|
126
126
|
status: explanation.status,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enablePhysics2DGuards.js","sourceRoot":"","sources":["../src/enablePhysics2DGuards.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"enablePhysics2DGuards.js","sourceRoot":"","sources":["../src/enablePhysics2DGuards.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/physics2d",
|
|
3
|
-
"version": "0.5.1-next.
|
|
3
|
+
"version": "0.5.1-next.4304.322dc96",
|
|
4
4
|
"author": "Joshua Granick and other contributors",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,13 +38,13 @@
|
|
|
38
38
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@flighthq/collision": "0.5.1-next.
|
|
42
|
-
"@flighthq/entity": "0.5.1-next.
|
|
43
|
-
"@flighthq/log": "0.5.1-next.
|
|
44
|
-
"@flighthq/math": "0.5.1-next.
|
|
45
|
-
"@flighthq/node": "0.5.1-next.
|
|
46
|
-
"@flighthq/spatial": "0.5.1-next.
|
|
47
|
-
"@flighthq/types": "0.5.1-next.
|
|
41
|
+
"@flighthq/collision": "0.5.1-next.4304.322dc96",
|
|
42
|
+
"@flighthq/entity": "0.5.1-next.4304.322dc96",
|
|
43
|
+
"@flighthq/log": "0.5.1-next.4304.322dc96",
|
|
44
|
+
"@flighthq/math": "0.5.1-next.4304.322dc96",
|
|
45
|
+
"@flighthq/node": "0.5.1-next.4304.322dc96",
|
|
46
|
+
"@flighthq/spatial": "0.5.1-next.4304.322dc96",
|
|
47
|
+
"@flighthq/types": "0.5.1-next.4304.322dc96"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@flighthq/scene2d": "*",
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { allocateEntity, finishEntity } from '@flighthq/entity/contract';
|
|
2
2
|
import {
|
|
3
3
|
addLogSink,
|
|
4
|
-
|
|
4
|
+
createLogState,
|
|
5
5
|
createMemoryLogSink,
|
|
6
6
|
getMemoryLogSinkEntries,
|
|
7
7
|
removeLogSink,
|
|
8
8
|
} from '@flighthq/log/contract';
|
|
9
|
-
import type {
|
|
9
|
+
import type { LogState } from '@flighthq/log/contract';
|
|
10
|
+
import type {
|
|
11
|
+
Entity,
|
|
12
|
+
LogEntry,
|
|
13
|
+
MemoryLogSink,
|
|
14
|
+
Physics2DDistanceJoint,
|
|
15
|
+
Physics2DWorld,
|
|
16
|
+
RigidBody2D,
|
|
17
|
+
} from '@flighthq/types/contract';
|
|
10
18
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
11
19
|
|
|
12
20
|
import { arePhysics2DGuardsEnabled, disablePhysics2DGuards, enablePhysics2DGuards } from './enablePhysics2DGuards.ts';
|
|
@@ -16,16 +24,23 @@ import { registerBuiltInPhysics2DJointSolvers } from './registerBuiltInPhysics2D
|
|
|
16
24
|
import { stepPhysics2D } from './step.ts';
|
|
17
25
|
import { addPhysics2DBody, createPhysics2DCollider, createPhysics2DWorld, createRigidBody2D } from './world.ts';
|
|
18
26
|
|
|
27
|
+
// Each test logs into a fresh caller-owned state, so logOnce keys never leak between tests.
|
|
28
|
+
let logState: LogState;
|
|
29
|
+
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
logState = createLogState();
|
|
32
|
+
});
|
|
33
|
+
|
|
19
34
|
const STONE = { density: 1, friction: 0.3, restitution: 0 };
|
|
20
35
|
|
|
21
36
|
function captureLog(run: () => void): readonly LogEntry[] {
|
|
22
37
|
const sink = createMemoryLogSink(8);
|
|
23
|
-
addLogSink(sink.sink);
|
|
38
|
+
addLogSink(logState, sink.sink);
|
|
24
39
|
try {
|
|
25
40
|
run();
|
|
26
|
-
return
|
|
41
|
+
return readMemoryLogEntries(sink);
|
|
27
42
|
} finally {
|
|
28
|
-
removeLogSink(sink.sink);
|
|
43
|
+
removeLogSink(logState, sink.sink);
|
|
29
44
|
}
|
|
30
45
|
}
|
|
31
46
|
|
|
@@ -67,11 +82,6 @@ function unregisteredJointWorld(): Physics2DWorld {
|
|
|
67
82
|
return world;
|
|
68
83
|
}
|
|
69
84
|
|
|
70
|
-
beforeEach(() => {
|
|
71
|
-
// `logOnce` keys are process-global and this file deliberately provokes the same faults repeatedly.
|
|
72
|
-
clearLogOnceKeys();
|
|
73
|
-
});
|
|
74
|
-
|
|
75
85
|
afterEach(() => {
|
|
76
86
|
disablePhysics2DGuards();
|
|
77
87
|
});
|
|
@@ -79,7 +89,7 @@ afterEach(() => {
|
|
|
79
89
|
describe('arePhysics2DGuardsEnabled', () => {
|
|
80
90
|
it('reports the current module guard state', () => {
|
|
81
91
|
expect(arePhysics2DGuardsEnabled()).toBe(false);
|
|
82
|
-
enablePhysics2DGuards();
|
|
92
|
+
enablePhysics2DGuards(logState, () => 0);
|
|
83
93
|
expect(arePhysics2DGuardsEnabled()).toBe(true);
|
|
84
94
|
disablePhysics2DGuards();
|
|
85
95
|
expect(arePhysics2DGuardsEnabled()).toBe(false);
|
|
@@ -88,7 +98,7 @@ describe('arePhysics2DGuardsEnabled', () => {
|
|
|
88
98
|
|
|
89
99
|
describe('disablePhysics2DGuards', () => {
|
|
90
100
|
it('removes both seams so a declined step and an unsolved joint are silent again', () => {
|
|
91
|
-
enablePhysics2DGuards();
|
|
101
|
+
enablePhysics2DGuards(logState, () => 0);
|
|
92
102
|
disablePhysics2DGuards();
|
|
93
103
|
const declining = createPhysics2DWorld(0, -10);
|
|
94
104
|
declining.config.positionIterations = -3;
|
|
@@ -106,7 +116,7 @@ describe('enablePhysics2DGuards', () => {
|
|
|
106
116
|
it('reports an area-less collider used as a body shape', () => {
|
|
107
117
|
// The third seam. A segment on a rigid body is a modelling mistake the simulation cannot show you:
|
|
108
118
|
// nothing fails, nothing is slow, the body simply never collides with anything.
|
|
109
|
-
enablePhysics2DGuards();
|
|
119
|
+
enablePhysics2DGuards(logState, () => 0);
|
|
110
120
|
const world = createPhysics2DWorld(0, -10);
|
|
111
121
|
const body = createRigidBody2D('dynamic', 0, 0);
|
|
112
122
|
body.colliders.push(createPhysics2DCollider({ kind: 'segment', x0: 0, y0: 0, x1: 1, y1: 0 }, STONE));
|
|
@@ -129,7 +139,7 @@ describe('enablePhysics2DGuards', () => {
|
|
|
129
139
|
// This test is the inverse of one that used to assert the opposite. The capsule was named by this
|
|
130
140
|
// guard while its pair functions were missing and stopped being named when they landed, which is the
|
|
131
141
|
// seam working in both directions rather than a list someone edits by hand.
|
|
132
|
-
enablePhysics2DGuards();
|
|
142
|
+
enablePhysics2DGuards(logState, () => 0);
|
|
133
143
|
const world = createPhysics2DWorld(0, -10);
|
|
134
144
|
const body = createRigidBody2D('dynamic', 0, 0);
|
|
135
145
|
body.colliders.push(createPhysics2DCollider({ kind: 'capsule', x0: 0, y0: 0, x1: 1, y1: 0, radius: 0.4 }, STONE));
|
|
@@ -139,7 +149,7 @@ describe('enablePhysics2DGuards', () => {
|
|
|
139
149
|
});
|
|
140
150
|
|
|
141
151
|
it('says nothing about colliders the dispatcher does answer for', () => {
|
|
142
|
-
enablePhysics2DGuards();
|
|
152
|
+
enablePhysics2DGuards(logState, () => 0);
|
|
143
153
|
const world = createPhysics2DWorld(0, -10);
|
|
144
154
|
const body = createRigidBody2D('dynamic', 0, 0);
|
|
145
155
|
body.colliders.push(createPhysics2DCollider({ kind: 'circle', x: 0, y: 0, radius: 0.5 }, STONE));
|
|
@@ -149,7 +159,7 @@ describe('enablePhysics2DGuards', () => {
|
|
|
149
159
|
});
|
|
150
160
|
|
|
151
161
|
it('says nothing while a healthy world steps', () => {
|
|
152
|
-
enablePhysics2DGuards();
|
|
162
|
+
enablePhysics2DGuards(logState, () => 0);
|
|
153
163
|
const world = createPhysics2DWorld(0, -10);
|
|
154
164
|
ball(world, 'static', 0, 0);
|
|
155
165
|
ball(world, 'dynamic', 0, 2);
|
|
@@ -162,7 +172,7 @@ describe('enablePhysics2DGuards', () => {
|
|
|
162
172
|
});
|
|
163
173
|
|
|
164
174
|
it('says nothing about joints once their solvers are registered', () => {
|
|
165
|
-
enablePhysics2DGuards();
|
|
175
|
+
enablePhysics2DGuards(logState, () => 0);
|
|
166
176
|
const world = unregisteredJointWorld();
|
|
167
177
|
registerBuiltInPhysics2DJointSolvers(world);
|
|
168
178
|
|
|
@@ -174,7 +184,7 @@ describe('enablePhysics2DGuards', () => {
|
|
|
174
184
|
it('names every failing precondition at once, not only the first', () => {
|
|
175
185
|
// The step's own condition short-circuits, so surfacing one fault per frame would cost a round trip
|
|
176
186
|
// per fault. The explain seam exists to avoid exactly that and the guard must not reintroduce it.
|
|
177
|
-
enablePhysics2DGuards();
|
|
187
|
+
enablePhysics2DGuards(logState, () => 0);
|
|
178
188
|
const world = createPhysics2DWorld(Number.NaN, -10);
|
|
179
189
|
world.config.positionIterations = -3;
|
|
180
190
|
|
|
@@ -190,7 +200,7 @@ describe('enablePhysics2DGuards', () => {
|
|
|
190
200
|
it('reports a joint whose kind has no registered solver, on a step that otherwise succeeds', () => {
|
|
191
201
|
// The case the whole second seam is for. The world steps, the bob falls, nothing fails — and the
|
|
192
202
|
// rope it is supposed to be hanging from is simply not there.
|
|
193
|
-
enablePhysics2DGuards();
|
|
203
|
+
enablePhysics2DGuards(logState, () => 0);
|
|
194
204
|
const world = unregisteredJointWorld();
|
|
195
205
|
|
|
196
206
|
const entries = captureLog(() => stepPhysics2D(world, 1 / 60));
|
|
@@ -208,7 +218,7 @@ describe('enablePhysics2DGuards', () => {
|
|
|
208
218
|
});
|
|
209
219
|
|
|
210
220
|
it('reports a joint whose endpoint body is gone with endpoint advice, not registration advice', () => {
|
|
211
|
-
enablePhysics2DGuards();
|
|
221
|
+
enablePhysics2DGuards(logState, () => 0);
|
|
212
222
|
const world = unregisteredJointWorld();
|
|
213
223
|
registerBuiltInPhysics2DJointSolvers(world);
|
|
214
224
|
world.joints[0].bodyB = 9999;
|
|
@@ -225,7 +235,7 @@ describe('enablePhysics2DGuards', () => {
|
|
|
225
235
|
it('collapses many identically broken joints into one report', () => {
|
|
226
236
|
// A ragdoll with a dozen unregistered joints of the same kind is ONE mistake. Listing twelve indices
|
|
227
237
|
// would read as twelve, and re-keying per index would defeat logOnce entirely.
|
|
228
|
-
enablePhysics2DGuards();
|
|
238
|
+
enablePhysics2DGuards(logState, () => 0);
|
|
229
239
|
const world = unregisteredJointWorld();
|
|
230
240
|
for (let extra = 0; extra < 11; extra++) {
|
|
231
241
|
addPhysics2DJoint(world, { ...world.joints[0], impulse0: 0 });
|
|
@@ -240,7 +250,7 @@ describe('enablePhysics2DGuards', () => {
|
|
|
240
250
|
});
|
|
241
251
|
|
|
242
252
|
it('warns once for a repeated fault rather than once per frame', () => {
|
|
243
|
-
enablePhysics2DGuards();
|
|
253
|
+
enablePhysics2DGuards(logState, () => 0);
|
|
244
254
|
const world = unregisteredJointWorld();
|
|
245
255
|
|
|
246
256
|
const entries = captureLog(() => {
|
|
@@ -253,7 +263,7 @@ describe('enablePhysics2DGuards', () => {
|
|
|
253
263
|
it('still speaks when a second, different fault appears after the first', () => {
|
|
254
264
|
// The counterpart risk of keying on the fault set: a world that develops a new problem must not be
|
|
255
265
|
// silenced by having already reported the old one.
|
|
256
|
-
enablePhysics2DGuards();
|
|
266
|
+
enablePhysics2DGuards(logState, () => 0);
|
|
257
267
|
const world = unregisteredJointWorld();
|
|
258
268
|
|
|
259
269
|
const entries = captureLog(() => {
|
|
@@ -270,7 +280,7 @@ describe('enablePhysics2DGuards', () => {
|
|
|
270
280
|
it('does not add the joint complaint on top of a declined step', () => {
|
|
271
281
|
// A declined step advanced nothing at all, so its own message is the whole story. Repeating the joint
|
|
272
282
|
// finding underneath it would bury the reason the world is frozen.
|
|
273
|
-
enablePhysics2DGuards();
|
|
283
|
+
enablePhysics2DGuards(logState, () => 0);
|
|
274
284
|
const world = unregisteredJointWorld();
|
|
275
285
|
world.config.velocityIterations = -1;
|
|
276
286
|
|
|
@@ -280,3 +290,9 @@ describe('enablePhysics2DGuards', () => {
|
|
|
280
290
|
expect((entries[0].data as { status: string }).status).toBe('invalid-step');
|
|
281
291
|
});
|
|
282
292
|
});
|
|
293
|
+
|
|
294
|
+
function readMemoryLogEntries(handle: Readonly<MemoryLogSink>): LogEntry[] {
|
|
295
|
+
const entries: LogEntry[] = [];
|
|
296
|
+
getMemoryLogSinkEntries(entries, handle);
|
|
297
|
+
return entries;
|
|
298
|
+
}
|