@zylem/behaviors 0.4.1 → 0.5.2
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 +13 -1
- package/dist/{behavior-system-y8SGrGWy.d.ts → behavior-system-CldqNUgr.d.ts} +334 -19
- package/dist/{chunk-GFARAJV2.js → chunk-2PAHQZZD.js} +44 -73
- package/dist/chunk-2PAHQZZD.js.map +1 -0
- package/dist/chunk-4CEW64HO.js +210 -0
- package/dist/chunk-4CEW64HO.js.map +1 -0
- package/dist/chunk-4LLK2FJI.js +344 -0
- package/dist/chunk-4LLK2FJI.js.map +1 -0
- package/dist/chunk-4MZ57HPD.js +323 -0
- package/dist/chunk-4MZ57HPD.js.map +1 -0
- package/dist/chunk-52FJIDGL.js +30 -0
- package/dist/chunk-52FJIDGL.js.map +1 -0
- package/dist/{chunk-UYFOLI2X.js → chunk-5A5AYP2C.js} +1 -1
- package/dist/{chunk-UYFOLI2X.js.map → chunk-5A5AYP2C.js.map} +1 -1
- package/dist/chunk-5WRI5ZAA.js +31 -0
- package/dist/chunk-5WRI5ZAA.js.map +1 -0
- package/dist/{chunk-ZRQWSURL.js → chunk-5XPPLTC7.js} +2 -2
- package/dist/chunk-5XPPLTC7.js.map +1 -0
- package/dist/{chunk-VMQHNJJI.js → chunk-7DGXUAPV.js} +17 -23
- package/dist/chunk-7DGXUAPV.js.map +1 -0
- package/dist/{chunk-5SM5SH5O.js → chunk-7JLWZXPA.js} +2 -2
- package/dist/{chunk-QDCJLJUV.js → chunk-7W3KY55G.js} +22 -13
- package/dist/chunk-7W3KY55G.js.map +1 -0
- package/dist/chunk-AS3HR7AS.js +188 -0
- package/dist/chunk-AS3HR7AS.js.map +1 -0
- package/dist/chunk-BAXJ7XHJ.js +155 -0
- package/dist/chunk-BAXJ7XHJ.js.map +1 -0
- package/dist/chunk-DZ4LLQON.js +867 -0
- package/dist/chunk-DZ4LLQON.js.map +1 -0
- package/dist/{chunk-4L36OPY2.js → chunk-G2KUXVU6.js} +81 -135
- package/dist/chunk-G2KUXVU6.js.map +1 -0
- package/dist/{chunk-BXP4K7RF.js → chunk-JVADRLWX.js} +57 -186
- package/dist/chunk-JVADRLWX.js.map +1 -0
- package/dist/{chunk-ZA43LPRM.js → chunk-KIYUUSPK.js} +2 -2
- package/dist/chunk-LZIHSJZR.js +191 -0
- package/dist/chunk-LZIHSJZR.js.map +1 -0
- package/dist/{chunk-WWVD5DR5.js → chunk-M3QDKKDF.js} +2 -8
- package/dist/chunk-M3QDKKDF.js.map +1 -0
- package/dist/{chunk-FTDZAKZW.js → chunk-NQPYMUDF.js} +7 -5
- package/dist/{chunk-FTDZAKZW.js.map → chunk-NQPYMUDF.js.map} +1 -1
- package/dist/{chunk-XP3ASVGJ.js → chunk-NW4SE5XW.js} +2 -2
- package/dist/{chunk-KDY5N6J4.js → chunk-OPZ2LVS2.js} +1 -22
- package/dist/{chunk-KDY5N6J4.js.map → chunk-OPZ2LVS2.js.map} +1 -1
- package/dist/{chunk-5XZWTFGF.js → chunk-PLIXVF7B.js} +3 -3
- package/dist/chunk-PLIXVF7B.js.map +1 -0
- package/dist/{chunk-27UPCP5B.js → chunk-QS3VXWVO.js} +22 -13
- package/dist/chunk-QS3VXWVO.js.map +1 -0
- package/dist/{chunk-Y7YIAWPW.js → chunk-SGHIGTVZ.js} +1 -11
- package/dist/{chunk-Y7YIAWPW.js.map → chunk-SGHIGTVZ.js.map} +1 -1
- package/dist/{chunk-UL6Q5HDP.js → chunk-TBUKJKY6.js} +3 -25
- package/dist/chunk-TBUKJKY6.js.map +1 -0
- package/dist/{chunk-Z72F2ENM.js → chunk-WU6XXL3D.js} +17 -26
- package/dist/chunk-WU6XXL3D.js.map +1 -0
- package/dist/{chunk-A4CA35DQ.js → chunk-Y4PHT2HG.js} +25 -45
- package/dist/chunk-Y4PHT2HG.js.map +1 -0
- package/dist/components-BmievOxF.d.ts +30 -0
- package/dist/cooldown.d.ts +2 -2
- package/dist/cooldown.js +2 -1
- package/dist/coordinators/boundary-ricochet-3d.d.ts +4 -4
- package/dist/coordinators/boundary-ricochet-3d.js +1 -0
- package/dist/coordinators/boundary-ricochet.d.ts +4 -4
- package/dist/coordinators/boundary-ricochet.js +3 -2
- package/dist/coordinators/first-person-shooter.js +1 -0
- package/dist/coordinators/multidirectional-space-shooter.d.ts +3 -3
- package/dist/coordinators/multidirectional-space-shooter.js +5 -3
- package/dist/coordinators/top-down-shooter.d.ts +3 -3
- package/dist/coordinators/top-down-shooter.js +5 -3
- package/dist/core.d.ts +298 -8
- package/dist/core.js +502 -14
- package/dist/core.js.map +1 -1
- package/dist/destructible-3d.d.ts +32 -4
- package/dist/destructible-3d.js +2 -1
- package/dist/destructible-prebake.js +1 -0
- package/dist/{entity-types-CmtQ-IBp.d.ts → entity-types-DhfsZbSK.d.ts} +5 -3
- package/dist/first-person.d.ts +27 -38
- package/dist/first-person.js +8 -8
- package/dist/index.d.ts +14 -15
- package/dist/index.js +38 -53
- package/dist/jumper-2d.d.ts +3 -17
- package/dist/jumper-2d.js +4 -9
- package/dist/jumper-3d.d.ts +5 -39
- package/dist/jumper-3d.js +5 -10
- package/dist/{moveable-Cl9h-_w7.d.ts → moveable-rdIvWiak.d.ts} +21 -4
- package/dist/particle-emitter/presets.js +1 -0
- package/dist/particle-emitter.d.ts +3 -3
- package/dist/particle-emitter.js +3 -2
- package/dist/platformer-2d.d.ts +21 -82
- package/dist/platformer-2d.js +4 -5
- package/dist/platformer-3d.d.ts +21 -78
- package/dist/platformer-3d.js +4 -5
- package/dist/ricochet-2d.d.ts +3 -3
- package/dist/ricochet-2d.js +4 -3
- package/dist/ricochet-3d.d.ts +3 -3
- package/dist/ricochet-3d.js +4 -3
- package/dist/runtime-2d.d.ts +2 -2
- package/dist/runtime-2d.js +1 -0
- package/dist/runtime-2d.js.map +1 -1
- package/dist/screen-visibility.d.ts +2 -2
- package/dist/screen-visibility.js +1 -0
- package/dist/screen-wrap.d.ts +2 -2
- package/dist/screen-wrap.js +4 -3
- package/dist/shooter-2d.d.ts +3 -3
- package/dist/shooter-2d.js +4 -3
- package/dist/thruster.d.ts +5 -34
- package/dist/thruster.js +4 -6
- package/dist/top-down-movement.d.ts +9 -27
- package/dist/top-down-movement.js +6 -6
- package/dist/{vector-Bm65-FOG.d.ts → vector-DjhLUrak.d.ts} +2 -4
- package/dist/world-boundary-2d.d.ts +2 -2
- package/dist/world-boundary-2d.js +5 -4
- package/dist/world-boundary-3d.d.ts +2 -2
- package/dist/world-boundary-3d.js +4 -3
- package/package.json +4 -5
- package/dist/chunk-27UPCP5B.js.map +0 -1
- package/dist/chunk-4L36OPY2.js.map +0 -1
- package/dist/chunk-4URF65BR.js +0 -44
- package/dist/chunk-4URF65BR.js.map +0 -1
- package/dist/chunk-5XZWTFGF.js.map +0 -1
- package/dist/chunk-67XLJ26X.js +0 -536
- package/dist/chunk-67XLJ26X.js.map +0 -1
- package/dist/chunk-75FJIUIG.js +0 -240
- package/dist/chunk-75FJIUIG.js.map +0 -1
- package/dist/chunk-A4CA35DQ.js.map +0 -1
- package/dist/chunk-BXP4K7RF.js.map +0 -1
- package/dist/chunk-F72WX4MH.js +0 -422
- package/dist/chunk-F72WX4MH.js.map +0 -1
- package/dist/chunk-GFARAJV2.js.map +0 -1
- package/dist/chunk-JXMF4NUI.js +0 -309
- package/dist/chunk-JXMF4NUI.js.map +0 -1
- package/dist/chunk-OTLSUYQQ.js +0 -29
- package/dist/chunk-OTLSUYQQ.js.map +0 -1
- package/dist/chunk-Q75LKHDF.js +0 -56
- package/dist/chunk-Q75LKHDF.js.map +0 -1
- package/dist/chunk-QDCJLJUV.js.map +0 -1
- package/dist/chunk-RDHSHEZM.js +0 -479
- package/dist/chunk-RDHSHEZM.js.map +0 -1
- package/dist/chunk-UIG7MWS2.js +0 -518
- package/dist/chunk-UIG7MWS2.js.map +0 -1
- package/dist/chunk-UL6Q5HDP.js.map +0 -1
- package/dist/chunk-VMQHNJJI.js.map +0 -1
- package/dist/chunk-WWVD5DR5.js.map +0 -1
- package/dist/chunk-Z72F2ENM.js.map +0 -1
- package/dist/chunk-ZRQWSURL.js.map +0 -1
- package/dist/components-BWG1GkZA.d.ts +0 -20
- package/dist/use-behavior-B85d5u7-.d.ts +0 -13
- /package/dist/{chunk-5SM5SH5O.js.map → chunk-7JLWZXPA.js.map} +0 -0
- /package/dist/{chunk-ZA43LPRM.js.map → chunk-KIYUUSPK.js.map} +0 -0
- /package/dist/{chunk-XP3ASVGJ.js.map → chunk-NW4SE5XW.js.map} +0 -0
package/dist/core.js
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
createPhysicsBodyComponent,
|
|
3
3
|
createTransformComponent,
|
|
4
4
|
useBehavior
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-5A5AYP2C.js";
|
|
6
6
|
import {
|
|
7
7
|
VEC2_ONE,
|
|
8
8
|
VEC2_ZERO,
|
|
@@ -12,35 +12,40 @@ import {
|
|
|
12
12
|
isVec3Input,
|
|
13
13
|
normalizeVec2,
|
|
14
14
|
normalizeVec3,
|
|
15
|
-
toRapierVector3,
|
|
16
15
|
toThreeVector2,
|
|
17
16
|
toThreeVector3
|
|
18
|
-
} from "./chunk-
|
|
19
|
-
import {
|
|
20
|
-
clearVelocityIntent,
|
|
21
|
-
setVelocityIntent
|
|
22
|
-
} from "./chunk-OTLSUYQQ.js";
|
|
17
|
+
} from "./chunk-M3QDKKDF.js";
|
|
23
18
|
import {
|
|
24
19
|
SyncStateMachine,
|
|
25
|
-
|
|
26
|
-
} from "./chunk-
|
|
20
|
+
import_typescript_fsm
|
|
21
|
+
} from "./chunk-AS3HR7AS.js";
|
|
27
22
|
import {
|
|
23
|
+
STAGE_EVENT_STRIDE,
|
|
28
24
|
STAGE_INPUT_BUTTON_JUMP,
|
|
29
25
|
STAGE_INPUT_BUTTON_RUN,
|
|
26
|
+
STAGE_INPUT_STRIDE,
|
|
27
|
+
STAGE_INVALID_SLOT,
|
|
28
|
+
STAGE_RENDER_STRIDE,
|
|
29
|
+
STAGE_SNAPSHOT_STRIDE,
|
|
30
30
|
StageBodyKind,
|
|
31
31
|
StageBoundaryDim,
|
|
32
32
|
StageEventType,
|
|
33
|
+
StagePlatformerShapeSource,
|
|
33
34
|
StageRicochetDim,
|
|
34
35
|
StageRicochetReflection,
|
|
35
36
|
StageTopDownPlane,
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
WasmStageRuntime,
|
|
38
|
+
createWasmStageRuntime,
|
|
39
|
+
readBehaviorSnapshot,
|
|
40
|
+
readStageRenderSlot
|
|
41
|
+
} from "./chunk-DZ4LLQON.js";
|
|
38
42
|
import {
|
|
39
43
|
defineBehavior
|
|
40
44
|
} from "./chunk-EZNCCO4L.js";
|
|
45
|
+
import "./chunk-5WRI5ZAA.js";
|
|
41
46
|
|
|
42
47
|
// src/lib/capabilities/transform-store.ts
|
|
43
|
-
import { proxy } from "valtio";
|
|
48
|
+
import { proxy } from "valtio/vanilla";
|
|
44
49
|
function createTransformStore(initial) {
|
|
45
50
|
const defaultState = {
|
|
46
51
|
position: { x: 0, y: 0, z: 0 },
|
|
@@ -69,6 +74,30 @@ function createTransformStore(initial) {
|
|
|
69
74
|
});
|
|
70
75
|
}
|
|
71
76
|
|
|
77
|
+
// src/lib/capabilities/velocity-intents.ts
|
|
78
|
+
function setVelocityIntent(store, sourceId, vector, options = {}) {
|
|
79
|
+
const prev = store.velocityChannels[sourceId];
|
|
80
|
+
const mode = options.mode ?? prev?.mode ?? "replace";
|
|
81
|
+
const priority = options.priority ?? prev?.priority ?? 0;
|
|
82
|
+
const isAdditiveMerge = mode === "add" && prev?.mode === "add";
|
|
83
|
+
const x = vector.x == null ? prev?.x : isAdditiveMerge ? (prev?.x ?? 0) + vector.x : vector.x;
|
|
84
|
+
const y = vector.y == null ? prev?.y : isAdditiveMerge ? (prev?.y ?? 0) + vector.y : vector.y;
|
|
85
|
+
const z = vector.z == null ? prev?.z : isAdditiveMerge ? (prev?.z ?? 0) + vector.z : vector.z;
|
|
86
|
+
store.velocityChannels[sourceId] = {
|
|
87
|
+
x,
|
|
88
|
+
y,
|
|
89
|
+
z,
|
|
90
|
+
mode,
|
|
91
|
+
priority
|
|
92
|
+
};
|
|
93
|
+
store.dirty.velocityChannels = true;
|
|
94
|
+
}
|
|
95
|
+
function clearVelocityIntent(store, sourceId) {
|
|
96
|
+
if (!(sourceId in store.velocityChannels)) return;
|
|
97
|
+
delete store.velocityChannels[sourceId];
|
|
98
|
+
store.dirty.velocityChannels = true;
|
|
99
|
+
}
|
|
100
|
+
|
|
72
101
|
// src/lib/capabilities/moveable.ts
|
|
73
102
|
import { Vector3 } from "three";
|
|
74
103
|
function moveX(entity, delta) {
|
|
@@ -192,6 +221,452 @@ function makeMoveable(entity) {
|
|
|
192
221
|
return moveable;
|
|
193
222
|
}
|
|
194
223
|
|
|
224
|
+
// src/lib/runtime/mock-behavior-runtime.ts
|
|
225
|
+
function freshSlot() {
|
|
226
|
+
return {
|
|
227
|
+
pose: { position: [0, 0, 0], rotation: [0, 0, 0, 1] },
|
|
228
|
+
snapshot: null,
|
|
229
|
+
input: { axisA: 0, axisB: 0, yawDelta: 0, pitchDelta: 0, reservedA: 0, reservedB: 0, buttons: 0 },
|
|
230
|
+
attachments: /* @__PURE__ */ new Map(),
|
|
231
|
+
inputs: [],
|
|
232
|
+
screenWrapQuery: null,
|
|
233
|
+
worldBoundaryQuery: null
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
var MockBehaviorRuntime = class {
|
|
237
|
+
slots = /* @__PURE__ */ new Map();
|
|
238
|
+
slot(handle) {
|
|
239
|
+
let state = this.slots.get(handle);
|
|
240
|
+
if (!state) {
|
|
241
|
+
state = freshSlot();
|
|
242
|
+
this.slots.set(handle, state);
|
|
243
|
+
}
|
|
244
|
+
return state;
|
|
245
|
+
}
|
|
246
|
+
// ─── Test seams ─────────────────────────────────────────────────────
|
|
247
|
+
/** Seed the pose returned by {@link getPose} for a handle. */
|
|
248
|
+
setPose(handle, pose) {
|
|
249
|
+
this.slot(handle).pose = pose;
|
|
250
|
+
}
|
|
251
|
+
/** Seed the snapshot returned by {@link readSnapshot} for a handle. */
|
|
252
|
+
setSnapshot(handle, snapshot) {
|
|
253
|
+
this.slot(handle).snapshot = snapshot;
|
|
254
|
+
}
|
|
255
|
+
/** Seed {@link queryScreenWrap} results. */
|
|
256
|
+
setScreenWrapQuery(handle, value) {
|
|
257
|
+
this.slot(handle).screenWrapQuery = value;
|
|
258
|
+
}
|
|
259
|
+
/** Seed {@link queryWorldBoundary} results. */
|
|
260
|
+
setWorldBoundaryQuery(handle, value) {
|
|
261
|
+
this.slot(handle).worldBoundaryQuery = value;
|
|
262
|
+
}
|
|
263
|
+
/** Attachment options recorded for a handle, keyed by behavior name. */
|
|
264
|
+
getAttachment(handle, kind) {
|
|
265
|
+
return this.slots.get(handle)?.attachments.get(kind);
|
|
266
|
+
}
|
|
267
|
+
hasAttachment(handle, kind) {
|
|
268
|
+
return this.slots.get(handle)?.attachments.has(kind) ?? false;
|
|
269
|
+
}
|
|
270
|
+
/** Every per-entity input call recorded for a handle, oldest first. */
|
|
271
|
+
getInputCalls(handle) {
|
|
272
|
+
return this.slots.get(handle)?.inputs ?? [];
|
|
273
|
+
}
|
|
274
|
+
/** Last written slot-indexed input state for a handle. */
|
|
275
|
+
getBatchedInput(handle) {
|
|
276
|
+
return this.slot(handle).input;
|
|
277
|
+
}
|
|
278
|
+
reset() {
|
|
279
|
+
this.slots.clear();
|
|
280
|
+
}
|
|
281
|
+
// ─── BehaviorRuntime contract ───────────────────────────────────────
|
|
282
|
+
setPosition(handle, x, y, z) {
|
|
283
|
+
const pose = this.slot(handle).pose;
|
|
284
|
+
pose.position[0] = x;
|
|
285
|
+
pose.position[1] = y;
|
|
286
|
+
pose.position[2] = z;
|
|
287
|
+
return true;
|
|
288
|
+
}
|
|
289
|
+
setRotation(handle, x, y, z, w) {
|
|
290
|
+
const pose = this.slot(handle).pose;
|
|
291
|
+
pose.rotation[0] = x;
|
|
292
|
+
pose.rotation[1] = y;
|
|
293
|
+
pose.rotation[2] = z;
|
|
294
|
+
pose.rotation[3] = w;
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
getPose(handle, out) {
|
|
298
|
+
const state = this.slots.get(handle);
|
|
299
|
+
if (!state) return null;
|
|
300
|
+
const result = out ?? { position: [0, 0, 0], rotation: [0, 0, 0, 1] };
|
|
301
|
+
result.position[0] = state.pose.position[0];
|
|
302
|
+
result.position[1] = state.pose.position[1];
|
|
303
|
+
result.position[2] = state.pose.position[2];
|
|
304
|
+
result.rotation[0] = state.pose.rotation[0];
|
|
305
|
+
result.rotation[1] = state.pose.rotation[1];
|
|
306
|
+
result.rotation[2] = state.pose.rotation[2];
|
|
307
|
+
result.rotation[3] = state.pose.rotation[3];
|
|
308
|
+
return result;
|
|
309
|
+
}
|
|
310
|
+
writeInputAxes(handle, axisA, axisB) {
|
|
311
|
+
const input = this.slot(handle).input;
|
|
312
|
+
input.axisA = axisA;
|
|
313
|
+
input.axisB = axisB;
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
writeInputLook(handle, yawDelta, pitchDelta) {
|
|
317
|
+
const input = this.slot(handle).input;
|
|
318
|
+
input.yawDelta = yawDelta;
|
|
319
|
+
input.pitchDelta = pitchDelta;
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
writeInputReserved(handle, reservedA, reservedB) {
|
|
323
|
+
const input = this.slot(handle).input;
|
|
324
|
+
input.reservedA = reservedA;
|
|
325
|
+
input.reservedB = reservedB;
|
|
326
|
+
return true;
|
|
327
|
+
}
|
|
328
|
+
writeInputButton(handle, buttonMask, pressed) {
|
|
329
|
+
const input = this.slot(handle).input;
|
|
330
|
+
input.buttons = pressed ? input.buttons | buttonMask : input.buttons & ~buttonMask;
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
readSnapshot(handle, out) {
|
|
334
|
+
const snapshot = this.slots.get(handle)?.snapshot ?? null;
|
|
335
|
+
if (!snapshot) return null;
|
|
336
|
+
if (!out) return { ...snapshot };
|
|
337
|
+
Object.assign(out, snapshot);
|
|
338
|
+
return out;
|
|
339
|
+
}
|
|
340
|
+
attachThruster(handle, opts) {
|
|
341
|
+
this.slot(handle).attachments.set("thruster", opts);
|
|
342
|
+
return true;
|
|
343
|
+
}
|
|
344
|
+
setThrusterInput(handle, thrust, rotate, vectorX = 0, vectorY = 0) {
|
|
345
|
+
this.slot(handle).inputs.push({
|
|
346
|
+
kind: "thruster",
|
|
347
|
+
args: [thrust, rotate, vectorX, vectorY]
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
attachTopDown(handle, opts) {
|
|
351
|
+
this.slot(handle).attachments.set("topDown", opts);
|
|
352
|
+
return true;
|
|
353
|
+
}
|
|
354
|
+
setTopDownInput(handle, moveX2, moveY2) {
|
|
355
|
+
this.slot(handle).inputs.push({ kind: "topDown", args: [moveX2, moveY2] });
|
|
356
|
+
}
|
|
357
|
+
attachShooter2D(handle, opts) {
|
|
358
|
+
this.slot(handle).attachments.set("shooter2d", opts);
|
|
359
|
+
return true;
|
|
360
|
+
}
|
|
361
|
+
attachScreenWrap(handle, opts) {
|
|
362
|
+
this.slot(handle).attachments.set("screenWrap", opts);
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
queryScreenWrap(handle) {
|
|
366
|
+
return this.slots.get(handle)?.screenWrapQuery ?? null;
|
|
367
|
+
}
|
|
368
|
+
attachWorldBoundary(handle, dim, opts) {
|
|
369
|
+
this.slot(handle).attachments.set("worldBoundary", { dim, ...opts });
|
|
370
|
+
return true;
|
|
371
|
+
}
|
|
372
|
+
queryWorldBoundary(handle) {
|
|
373
|
+
return this.slots.get(handle)?.worldBoundaryQuery ?? null;
|
|
374
|
+
}
|
|
375
|
+
attachRicochet(handle, dim, opts) {
|
|
376
|
+
this.slot(handle).attachments.set("ricochet", { dim, ...opts });
|
|
377
|
+
return true;
|
|
378
|
+
}
|
|
379
|
+
attachPlatformer3D(handle, opts) {
|
|
380
|
+
this.slot(handle).attachments.set("platformer3d", opts);
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
setPlatformer3DInputAxes(handle, moveX2, moveZ2) {
|
|
384
|
+
this.slot(handle).inputs.push({ kind: "platformer3dAxes", args: [moveX2, moveZ2] });
|
|
385
|
+
}
|
|
386
|
+
setPlatformer3DInputButtons(handle, jump, run) {
|
|
387
|
+
this.slot(handle).inputs.push({ kind: "platformer3dButtons", args: [jump, run] });
|
|
388
|
+
}
|
|
389
|
+
attachPlatformer2D(handle, opts) {
|
|
390
|
+
this.slot(handle).attachments.set("platformer2d", opts);
|
|
391
|
+
return true;
|
|
392
|
+
}
|
|
393
|
+
setPlatformer2DInputAxes(handle, moveX2) {
|
|
394
|
+
this.slot(handle).inputs.push({ kind: "platformer2dAxes", args: [moveX2] });
|
|
395
|
+
}
|
|
396
|
+
setPlatformer2DInputButtons(handle, jump, run) {
|
|
397
|
+
this.slot(handle).inputs.push({ kind: "platformer2dButtons", args: [jump, run] });
|
|
398
|
+
}
|
|
399
|
+
attachFirstPerson(handle, opts) {
|
|
400
|
+
this.slot(handle).attachments.set("firstPerson", opts);
|
|
401
|
+
return true;
|
|
402
|
+
}
|
|
403
|
+
setFirstPersonInput(handle, input) {
|
|
404
|
+
this.slot(handle).inputs.push({ kind: "firstPerson", args: [input] });
|
|
405
|
+
}
|
|
406
|
+
attachJumper2D(handle, opts) {
|
|
407
|
+
this.slot(handle).attachments.set("jumper2d", opts);
|
|
408
|
+
return true;
|
|
409
|
+
}
|
|
410
|
+
setJumper2DInput(handle, jumpPressed) {
|
|
411
|
+
this.slot(handle).inputs.push({ kind: "jumper2d", args: [jumpPressed] });
|
|
412
|
+
}
|
|
413
|
+
attachJumper3D(handle, opts) {
|
|
414
|
+
this.slot(handle).attachments.set("jumper3d", opts);
|
|
415
|
+
return true;
|
|
416
|
+
}
|
|
417
|
+
setJumper3DInput(handle, jumpPressed) {
|
|
418
|
+
this.slot(handle).inputs.push({ kind: "jumper3d", args: [jumpPressed] });
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
// src/lib/runtime/simulation.ts
|
|
423
|
+
var DEFAULT_FIXED_TIMESTEP = 1 / 60;
|
|
424
|
+
var DEFAULT_MAX_SUB_STEPS = 2;
|
|
425
|
+
var Simulation = class {
|
|
426
|
+
/**
|
|
427
|
+
* The low-level wasm adapter. Behavior systems receive this as their
|
|
428
|
+
* `wasmStage` context so descriptors can attach/query behaviors by slot;
|
|
429
|
+
* hosts should prefer the handle-based methods on the Simulation itself.
|
|
430
|
+
*/
|
|
431
|
+
adapter;
|
|
432
|
+
fixedTimestep;
|
|
433
|
+
maxSubSteps;
|
|
434
|
+
accumulator = 0;
|
|
435
|
+
nextEntityId = 1;
|
|
436
|
+
slotToHandle = /* @__PURE__ */ new Map();
|
|
437
|
+
idToHandle = /* @__PURE__ */ new Map();
|
|
438
|
+
previousRender = new Float32Array(0);
|
|
439
|
+
disposed = false;
|
|
440
|
+
eventsEnabled = true;
|
|
441
|
+
constructor(adapter, options = {}) {
|
|
442
|
+
this.adapter = adapter;
|
|
443
|
+
this.fixedTimestep = options.fixedTimestep ?? DEFAULT_FIXED_TIMESTEP;
|
|
444
|
+
this.maxSubSteps = Math.max(1, options.maxSubSteps ?? DEFAULT_MAX_SUB_STEPS);
|
|
445
|
+
}
|
|
446
|
+
// ─── Entity lifecycle ───────────────────────────────────────────────
|
|
447
|
+
/**
|
|
448
|
+
* Create a runtime entity from a plain definition. Returns `null` when
|
|
449
|
+
* the runtime rejects the allocation.
|
|
450
|
+
*/
|
|
451
|
+
spawn(definition = {}) {
|
|
452
|
+
const slot = this.adapter.createEntity();
|
|
453
|
+
if (slot === 4294967295) return null;
|
|
454
|
+
const body = definition.body;
|
|
455
|
+
const bodyConfig = {
|
|
456
|
+
kind: body?.kind ?? StageBodyKind.Dynamic,
|
|
457
|
+
position: body?.position ?? [0, 0, 0],
|
|
458
|
+
rotation: body?.rotation ?? [0, 0, 0, 1],
|
|
459
|
+
linearDamping: body?.linearDamping ?? 0,
|
|
460
|
+
angularDamping: body?.angularDamping ?? 0,
|
|
461
|
+
gravityScale: body?.gravityScale ?? 1,
|
|
462
|
+
canSleep: body?.canSleep ?? false,
|
|
463
|
+
ccdEnabled: body?.ccdEnabled ?? true,
|
|
464
|
+
lockRotation: body?.lockRotation ?? [false, false, false],
|
|
465
|
+
lockTranslation: body?.lockTranslation ?? [false, false, false]
|
|
466
|
+
};
|
|
467
|
+
this.adapter.attachBody(slot, bodyConfig);
|
|
468
|
+
for (const collider of definition.colliders ?? []) {
|
|
469
|
+
const config = {
|
|
470
|
+
shape: collider.shape,
|
|
471
|
+
offset: collider.offset ?? [0, 0, 0],
|
|
472
|
+
friction: collider.friction ?? 0.5,
|
|
473
|
+
restitution: collider.restitution ?? 0,
|
|
474
|
+
sensor: collider.sensor ?? false,
|
|
475
|
+
collisionGroups: collider.collisionGroups ?? 4294967295
|
|
476
|
+
};
|
|
477
|
+
this.adapter.addCollider(slot, config);
|
|
478
|
+
}
|
|
479
|
+
const handle = { id: this.nextEntityId++, slot };
|
|
480
|
+
this.slotToHandle.set(slot, handle);
|
|
481
|
+
this.idToHandle.set(handle.id, handle);
|
|
482
|
+
return handle;
|
|
483
|
+
}
|
|
484
|
+
despawn(handle) {
|
|
485
|
+
const registered = this.idToHandle.get(handle.id);
|
|
486
|
+
if (!registered) return false;
|
|
487
|
+
this.idToHandle.delete(handle.id);
|
|
488
|
+
if (this.slotToHandle.get(registered.slot) === registered) {
|
|
489
|
+
this.slotToHandle.delete(registered.slot);
|
|
490
|
+
}
|
|
491
|
+
return this.adapter.destroyEntity(registered.slot);
|
|
492
|
+
}
|
|
493
|
+
/** Resolve a raw runtime slot back to its public handle, if alive. */
|
|
494
|
+
handleForSlot(slot) {
|
|
495
|
+
return this.slotToHandle.get(slot) ?? null;
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Toggle collision-event collection. When disabled the wasm stage skips
|
|
499
|
+
* per-step contact-pair hashing and `update()` skips event draining /
|
|
500
|
+
* translation entirely (`frame.events` stays empty). Re-enabling emits
|
|
501
|
+
* `collisionStarted` for every currently overlapping pair on the next
|
|
502
|
+
* step, so late listeners observe current state.
|
|
503
|
+
*/
|
|
504
|
+
setEventsEnabled(enabled) {
|
|
505
|
+
if (this.eventsEnabled === enabled) return;
|
|
506
|
+
this.eventsEnabled = enabled;
|
|
507
|
+
this.adapter.setEventsEnabled(enabled);
|
|
508
|
+
}
|
|
509
|
+
get areEventsEnabled() {
|
|
510
|
+
return this.eventsEnabled;
|
|
511
|
+
}
|
|
512
|
+
get entityCount() {
|
|
513
|
+
return this.idToHandle.size;
|
|
514
|
+
}
|
|
515
|
+
// ─── Per-frame update ───────────────────────────────────────────────
|
|
516
|
+
/**
|
|
517
|
+
* Advance the simulation by `deltaTime` seconds using a fixed-timestep
|
|
518
|
+
* accumulator. Runs zero or more fixed steps and returns a
|
|
519
|
+
* {@link SimulationFrame} with translated events and interpolation data.
|
|
520
|
+
*/
|
|
521
|
+
update(deltaTime) {
|
|
522
|
+
const events = [];
|
|
523
|
+
this.accumulator += Math.max(0, deltaTime);
|
|
524
|
+
let steps = 0;
|
|
525
|
+
while (this.accumulator >= this.fixedTimestep && steps < this.maxSubSteps) {
|
|
526
|
+
this.capturePreviousRender();
|
|
527
|
+
this.adapter.step(this.fixedTimestep);
|
|
528
|
+
if (this.eventsEnabled) {
|
|
529
|
+
this.translateEvents(this.adapter.drainEvents(), events);
|
|
530
|
+
}
|
|
531
|
+
this.accumulator -= this.fixedTimestep;
|
|
532
|
+
steps++;
|
|
533
|
+
}
|
|
534
|
+
if (steps === this.maxSubSteps && this.accumulator >= this.fixedTimestep) {
|
|
535
|
+
this.accumulator = this.accumulator % this.fixedTimestep;
|
|
536
|
+
}
|
|
537
|
+
return {
|
|
538
|
+
deltaTime,
|
|
539
|
+
stepsTaken: steps,
|
|
540
|
+
alpha: this.fixedTimestep > 0 ? this.accumulator / this.fixedTimestep : 0,
|
|
541
|
+
render: this.adapter.render,
|
|
542
|
+
previousRender: this.previousRender,
|
|
543
|
+
renderStride: STAGE_RENDER_STRIDE,
|
|
544
|
+
events
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
capturePreviousRender() {
|
|
548
|
+
this.adapter.refreshViews();
|
|
549
|
+
const current = this.adapter.render;
|
|
550
|
+
if (this.previousRender.length !== current.length) {
|
|
551
|
+
this.previousRender = new Float32Array(current.length);
|
|
552
|
+
}
|
|
553
|
+
this.previousRender.set(current);
|
|
554
|
+
}
|
|
555
|
+
translateEvents(raw, out) {
|
|
556
|
+
for (const event of raw) {
|
|
557
|
+
const primary = event.primarySlot !== null ? this.handleForSlot(event.primarySlot) : null;
|
|
558
|
+
const secondary = event.secondarySlot !== null ? this.handleForSlot(event.secondarySlot) : null;
|
|
559
|
+
switch (event.type) {
|
|
560
|
+
case StageEventType.CollisionStarted:
|
|
561
|
+
case StageEventType.CollisionStopped:
|
|
562
|
+
out.push({
|
|
563
|
+
type: event.type === StageEventType.CollisionStarted ? "collisionStarted" : "collisionStopped",
|
|
564
|
+
a: primary,
|
|
565
|
+
b: secondary,
|
|
566
|
+
sensor: event.payload[0] !== 0,
|
|
567
|
+
normal: [event.payload[1], event.payload[2]]
|
|
568
|
+
});
|
|
569
|
+
break;
|
|
570
|
+
case StageEventType.BoundaryHit:
|
|
571
|
+
out.push({
|
|
572
|
+
type: "boundaryHit",
|
|
573
|
+
entity: primary,
|
|
574
|
+
axes: event.payload[0] | 0,
|
|
575
|
+
signs: event.payload[1] | 0
|
|
576
|
+
});
|
|
577
|
+
break;
|
|
578
|
+
case StageEventType.Ricochet:
|
|
579
|
+
out.push({ type: "ricochet", entity: primary, kind: event.payload[0] | 0 });
|
|
580
|
+
break;
|
|
581
|
+
case StageEventType.RegionEntered:
|
|
582
|
+
out.push({ type: "regionEntered", entity: primary, triggerId: event.payload[0] | 0 });
|
|
583
|
+
break;
|
|
584
|
+
case StageEventType.JumpStarted:
|
|
585
|
+
out.push({ type: "jumpStarted", entity: primary, jumpCount: event.payload[0] | 0 });
|
|
586
|
+
break;
|
|
587
|
+
case StageEventType.Landed:
|
|
588
|
+
out.push({ type: "landed", entity: primary });
|
|
589
|
+
break;
|
|
590
|
+
case StageEventType.Wrapped:
|
|
591
|
+
out.push({ type: "wrapped", entity: primary, axes: event.payload[0] | 0 });
|
|
592
|
+
break;
|
|
593
|
+
case StageEventType.CooldownFired:
|
|
594
|
+
out.push({ type: "cooldownFired", entity: primary, cooldownId: event.payload[0] | 0 });
|
|
595
|
+
break;
|
|
596
|
+
default:
|
|
597
|
+
break;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
// ─── Handle-based reads / writes ────────────────────────────────────
|
|
602
|
+
getPose(handle, out) {
|
|
603
|
+
return this.adapter.getPose(handle.slot, out);
|
|
604
|
+
}
|
|
605
|
+
setPosition(handle, x, y, z) {
|
|
606
|
+
return this.adapter.setPosition(handle.slot, x, y, z);
|
|
607
|
+
}
|
|
608
|
+
setRotation(handle, x, y, z, w) {
|
|
609
|
+
return this.adapter.setRotation(handle.slot, x, y, z, w);
|
|
610
|
+
}
|
|
611
|
+
setLinearVelocity(handle, x, y, z) {
|
|
612
|
+
return this.adapter.setLinearVelocity(handle.slot, x, y, z);
|
|
613
|
+
}
|
|
614
|
+
getLinearVelocity(handle) {
|
|
615
|
+
return this.adapter.getLinearVelocity(handle.slot);
|
|
616
|
+
}
|
|
617
|
+
setAngularVelocity(handle, x, y, z) {
|
|
618
|
+
return this.adapter.setAngularVelocity(handle.slot, x, y, z);
|
|
619
|
+
}
|
|
620
|
+
applyImpulse(handle, x, y, z) {
|
|
621
|
+
return this.adapter.applyImpulse(handle.slot, x, y, z);
|
|
622
|
+
}
|
|
623
|
+
readRenderSlot(handle, out) {
|
|
624
|
+
return readStageRenderSlot(this.adapter.render, handle.slot, out);
|
|
625
|
+
}
|
|
626
|
+
/** Decode a handle's pose from the previous-step render copy. */
|
|
627
|
+
readPreviousRenderSlot(handle, out) {
|
|
628
|
+
return readStageRenderSlot(this.previousRender, handle.slot, out);
|
|
629
|
+
}
|
|
630
|
+
readSnapshot(handle, out) {
|
|
631
|
+
return this.adapter.readSnapshot(handle.slot, out);
|
|
632
|
+
}
|
|
633
|
+
// ─── World-level controls / diagnostics ─────────────────────────────
|
|
634
|
+
setGravity(x, y, z) {
|
|
635
|
+
this.adapter.setGravity(x, y, z);
|
|
636
|
+
}
|
|
637
|
+
/** Physics raycast; the hit's slot is resolved to an entity handle. */
|
|
638
|
+
castRay(origin, dir, maxDistance, solidOnly = true) {
|
|
639
|
+
const hit = this.adapter.castRay(origin, dir, maxDistance, solidOnly);
|
|
640
|
+
if (!hit) return null;
|
|
641
|
+
return {
|
|
642
|
+
distance: hit.distance,
|
|
643
|
+
normal: hit.normal,
|
|
644
|
+
entity: this.handleForSlot(hit.slot)
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
getBodyInfo(handle) {
|
|
648
|
+
return this.adapter.getBodyInfo(handle.slot);
|
|
649
|
+
}
|
|
650
|
+
getDebugRender() {
|
|
651
|
+
return this.adapter.getDebugRender();
|
|
652
|
+
}
|
|
653
|
+
get isDisposed() {
|
|
654
|
+
return this.disposed;
|
|
655
|
+
}
|
|
656
|
+
/** Destroy the wasm stage. The Simulation must not be used afterwards. */
|
|
657
|
+
dispose() {
|
|
658
|
+
if (this.disposed) return;
|
|
659
|
+
this.disposed = true;
|
|
660
|
+
this.slotToHandle.clear();
|
|
661
|
+
this.idToHandle.clear();
|
|
662
|
+
this.adapter.dispose();
|
|
663
|
+
}
|
|
664
|
+
};
|
|
665
|
+
async function createSimulation(options = {}) {
|
|
666
|
+
const adapter = await createWasmStageRuntime(options);
|
|
667
|
+
return new Simulation(adapter, options);
|
|
668
|
+
}
|
|
669
|
+
|
|
195
670
|
// src/lib/entities/entity.ts
|
|
196
671
|
var GameEntity = class {
|
|
197
672
|
uuid;
|
|
@@ -201,6 +676,7 @@ var GameEntity = class {
|
|
|
201
676
|
group = null;
|
|
202
677
|
mesh;
|
|
203
678
|
materials;
|
|
679
|
+
/** Opaque host-owned physics references (never inspected by behaviors). */
|
|
204
680
|
body = null;
|
|
205
681
|
collider = null;
|
|
206
682
|
colliderDesc;
|
|
@@ -253,13 +729,22 @@ var GameEntity = class {
|
|
|
253
729
|
return this.__behaviorRefs;
|
|
254
730
|
}
|
|
255
731
|
};
|
|
732
|
+
var export_t = import_typescript_fsm.t;
|
|
256
733
|
export {
|
|
257
734
|
GameEntity,
|
|
735
|
+
MockBehaviorRuntime,
|
|
736
|
+
STAGE_EVENT_STRIDE,
|
|
258
737
|
STAGE_INPUT_BUTTON_JUMP,
|
|
259
738
|
STAGE_INPUT_BUTTON_RUN,
|
|
739
|
+
STAGE_INPUT_STRIDE,
|
|
740
|
+
STAGE_INVALID_SLOT,
|
|
741
|
+
STAGE_RENDER_STRIDE,
|
|
742
|
+
STAGE_SNAPSHOT_STRIDE,
|
|
743
|
+
Simulation,
|
|
260
744
|
StageBodyKind,
|
|
261
745
|
StageBoundaryDim,
|
|
262
746
|
StageEventType,
|
|
747
|
+
StagePlatformerShapeSource,
|
|
263
748
|
StageRicochetDim,
|
|
264
749
|
StageRicochetReflection,
|
|
265
750
|
StageTopDownPlane,
|
|
@@ -268,10 +753,13 @@ export {
|
|
|
268
753
|
VEC2_ZERO,
|
|
269
754
|
VEC3_ONE,
|
|
270
755
|
VEC3_ZERO,
|
|
756
|
+
WasmStageRuntime,
|
|
271
757
|
clearVelocityIntent,
|
|
272
758
|
createPhysicsBodyComponent,
|
|
759
|
+
createSimulation,
|
|
273
760
|
createTransformComponent,
|
|
274
761
|
createTransformStore,
|
|
762
|
+
createWasmStageRuntime,
|
|
275
763
|
defineBehavior,
|
|
276
764
|
getPosition,
|
|
277
765
|
getVelocity,
|
|
@@ -288,14 +776,14 @@ export {
|
|
|
288
776
|
normalizeVec2,
|
|
289
777
|
normalizeVec3,
|
|
290
778
|
readBehaviorSnapshot,
|
|
779
|
+
readStageRenderSlot,
|
|
291
780
|
resetVelocity,
|
|
292
781
|
setPosition,
|
|
293
782
|
setPositionX,
|
|
294
783
|
setPositionY,
|
|
295
784
|
setPositionZ,
|
|
296
785
|
setVelocityIntent,
|
|
297
|
-
t,
|
|
298
|
-
toRapierVector3,
|
|
786
|
+
export_t as t,
|
|
299
787
|
toThreeVector2,
|
|
300
788
|
toThreeVector3,
|
|
301
789
|
useBehavior,
|