@adatechnology/game-test-room 0.19.0 → 0.19.1
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 +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.global.js +140 -21
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +37 -8
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -211,9 +211,9 @@ Every frame the room puts `root` at the player's feet turned to where the player
|
|
|
211
211
|
|
|
212
212
|
**Pushing furniture.** Against a piece that stands on the floor, with bare hands, a tap on E grabs as ever and holding E fills a ring around the crosshair (longer the heavier). Then W pushes, S pulls, slower with the mass; letting go ends it. Before each step the volume of the piece is swept (`world.sweepBox`) against everything and the arena: at an obstacle the piece and the player stop and the player strains, and a piece too heavy for the player (`RoomOptions.push`, `FurniturePushRules` of game-player) never moves. A piece lower than a table is pushed from above, bent over it. Scripted: `room.push`. Try it: `?scene=push` in the example.
|
|
213
213
|
|
|
214
|
-
**Opening by hand.** A tap of E on a leaf (a part an `open_*` clip of the item moves: furniture doors, drawers and lids, vehicle doors, hood and trunk) opens it, and E again closes it; looking into what an open leaf opened, E closes that leaf. The player steps up to the handle, the hand goes to the free edge of the leaf (a drawer by its front) and follows it, pulling (the arm bends, the body leans back) or pushing; a door that swings into the player makes the player step back. The leaf swings along the item's own clip at a speed set by its mass, its sweep tested against the world (`world.sweepBox`) and the arena: it stops at what is in its way with a knock. A locked leaf (`room.lockLeaf`) only rattles. Latch, hinge creak, the leaf meeting the frame and the rattle play by material. Holding E still pushes the piece. Scripted: `room.useLeaf`, `room.leafOpening`, `room.leaves`, `room.door`; the numbers are `RoomOptions.doors` (`DoorUseRules` of game-player). A module that moves its own leaves (the doors of a house) asks for the same hand and body with `host.reachFor`. Try it: `?scene=doors` in the example.
|
|
214
|
+
**Opening by hand.** A tap of E on a leaf (a part an `open_*` clip of the item moves: furniture doors, drawers and lids, vehicle doors, hood and trunk) opens it, and E again closes it; looking into what an open leaf opened, E closes that leaf. The player steps up to the handle, the body's hand goes to the free edge of the leaf (a drawer by its front) through the same `reach` as a held tool, in both views, and follows it, pulling (the arm bends, the body leans back) or pushing; a door that swings into the player makes the player step back. The leaf swings along the item's own clip at a speed set by its mass, its sweep tested against the world (`world.sweepBox`) and the arena: it stops at what is in its way with a knock. A locked leaf (`room.lockLeaf`) only rattles. Latch, hinge creak, the leaf meeting the frame and the rattle play by material. Holding E still pushes the piece. Scripted: `room.useLeaf`, `room.leafOpening`, `room.leaves`, `room.door`; the numbers are `RoomOptions.doors` (`DoorUseRules` of game-player). A module that moves its own leaves (the doors of a house) asks for the same hand and body with `host.reachFor`. Try it: `?scene=doors` in the example.
|
|
215
215
|
|
|
216
|
-
**
|
|
216
|
+
**Hands and strikes.** The body is the only set of arms, in both views: the room hands its hands where the tool in them asks them to be (`reach`, every frame after the modules' frame hooks) and an avatar may answer `strike(clipId)`. The hand targets come from the module that places the tool (`host.setHandTargets(source)`, `HandTargets` of `@adatechnology/game-contracts`: world-space poses of the right and left hand plus the grip closure and the size of the hands), else from the carried item, else null; the stance is `hold` when there are targets, else `handStances[toolId]` (default `{ fists: 'fists' }`) or `relaxed`. A melee strike (`fists`, `shove`, Shift+V kick) no longer lands at the click: the room calls `avatar.strike(strikeClips[toolId])` (default `{ fists: 'punch_right', shove: 'shove_two_hands', kick: 'front_kick' }`), which plays the clip on the body (in both views) and answers the seconds to its impact, writes a `strike` line to the log, and calls the existing `meleeUse` at that second with the aim read again. The left click with bare hands (`hand`, the default tool) punches too (E or the right button grab). Punches alternate hands, right first (`punchHand`: `alternate`, `left`, `right`; `punchTools`, default `['hand', 'fists']`): the room calls `strike(clip, { hand })` and logs the hand, as the kick does with `kickLeg` and `{ leg }`. A **strike combo** is an ability the page gives (`strikeCombo`, such as `PUNCH_COMBO` of `game-characters-people`: jab, cross, hook, uppercut): while it is on (N, its button, `setStrikeCombo(true)`, `strikeComboOn`) each blow of its tools plays its next step (`{ clip, hand }`) and a pause longer than its `reset` starts it over; off, the tools strike as usual. The strike line carries `combo` and `step`. A tool without a clip, or an avatar that answers null, keeps the instant blow; a strike pending blocks the same tool. `toRoomAvatar(createPlayerAvatar(THREE))` already gives all of it .
|
|
217
217
|
|
|
218
218
|
`room.setCameraMode('first' | 'third')` (option `cameraMode`, property `cameraMode`, event `room.on('camera', fn)`; every change is a `camera` action in the log). V toggles it when a body is set. In `first` the body is hidden; in `third` it is shown, the camera stands over the shoulder, and a carried item rides `avatar.hand('R')` instead of the camera frame. Option `thirdPerson` changes the view; the defaults are the team game's shoulder camera (`zombiada-modo-livre.html`, `cameraUpdate`, line 76546): `back` 3.8 m, `side` 0.9 m to the right, `up` 1.95 m (`crouchUp` 1.4 m), `lift` 0.1 m, three probe rays (`probes` 0 and +-0.2 m) that pull the camera in `margin` 0.3 m short of a wall (never closer than `minDistance` 0.2 m) and let it out at `recover` 4 per second.
|
|
219
219
|
|
package/dist/index.d.ts
CHANGED
|
@@ -430,7 +430,7 @@ interface RoomAvatar {
|
|
|
430
430
|
/** Hides the head and neck from `camera` while the view is `first` (shadows, mirrors and other cameras keep seeing them). */
|
|
431
431
|
setView?(mode: CameraMode, camera: THREE_NS.Object3D | null): void;
|
|
432
432
|
/**
|
|
433
|
-
* Plays the strike `clipId` (on the body
|
|
433
|
+
* Plays the strike `clipId` (on the body, in both views) and answers the seconds until its impact, or null when this avatar has no such clip. The room then waits that long
|
|
434
434
|
* before the blow lands (`strikeClips`); an avatar without `strike`, or one that answers null, gets the blow at the click.
|
|
435
435
|
*/
|
|
436
436
|
strike?(clipId: string, options?: {
|
package/dist/index.global.js
CHANGED
|
@@ -3150,6 +3150,7 @@ var GameTestRoom = (() => {
|
|
|
3150
3150
|
var CHIP_ENERGY = 200;
|
|
3151
3151
|
var CHIP_SPLASH = 0.5;
|
|
3152
3152
|
var CRATER_SPENT = 0.6;
|
|
3153
|
+
var EDGE_REACH = 1.5;
|
|
3153
3154
|
var BAR_BOW = 0.08;
|
|
3154
3155
|
var BULLET_JOINT_SPAN = 0.3;
|
|
3155
3156
|
var CUT_SLICE = 1;
|
|
@@ -4523,6 +4524,9 @@ var GameTestRoom = (() => {
|
|
|
4523
4524
|
const lo = cell.center[a] - cell.size[a] / 2 + w / 2, hi = cell.center[a] + cell.size[a] / 2 - w / 2;
|
|
4524
4525
|
size[a] = w;
|
|
4525
4526
|
center[a] = clamp2(lp[a], lo, hi);
|
|
4527
|
+
const [from, to] = tornToEdge({ p, cell, a, b: a === u ? v : u, at: lp[a], crater: [center[a] - w / 2, center[a] + w / 2], reach: w * EDGE_REACH, gone: (k) => worn[k] === -1 });
|
|
4528
|
+
size[a] = to - from;
|
|
4529
|
+
center[a] = (from + to) / 2;
|
|
4526
4530
|
}
|
|
4527
4531
|
const taken2 = (cut2[i] ?? 0) + size[u] * size[v];
|
|
4528
4532
|
if (taken2 >= cell.size[u] * cell.size[v] * CRATER_SPENT) {
|
|
@@ -4560,6 +4564,19 @@ var GameTestRoom = (() => {
|
|
|
4560
4564
|
collapseCheck(o, src);
|
|
4561
4565
|
}
|
|
4562
4566
|
};
|
|
4567
|
+
const tornToEdge = (o) => {
|
|
4568
|
+
const { p, cell, a, b, at: at3, crater: crater2, reach, gone } = o;
|
|
4569
|
+
const half = p.dims[a] / 2;
|
|
4570
|
+
const lo = cell.center[a] - cell.size[a] / 2, hi = cell.center[a] + cell.size[a] / 2;
|
|
4571
|
+
const free = (side, sign) => {
|
|
4572
|
+
if (sign > 0 ? side >= half - 1e-6 : side <= -half + 1e-6) return sign > 0 || a !== planeAxes(p.thin)[1];
|
|
4573
|
+
const probe = side + sign * 1e-3;
|
|
4574
|
+
return gridOf(p).some((c, k) => gone(k) && Math.abs(probe - c.center[a]) <= c.size[a] / 2 && Math.abs(cell.center[b] - c.center[b]) <= c.size[b] / 2);
|
|
4575
|
+
};
|
|
4576
|
+
if (at3 - lo <= reach && free(lo, -1)) return [lo, Math.max(crater2[1], lo)];
|
|
4577
|
+
if (hi - at3 <= reach && free(hi, 1)) return [Math.min(crater2[0], hi), hi];
|
|
4578
|
+
return crater2;
|
|
4579
|
+
};
|
|
4563
4580
|
const craterAcross = (energy) => clamp2(0.03 + 12e-4 * Math.sqrt(Math.max(0, energy)), 0.03, 0.14);
|
|
4564
4581
|
const craterFragments = (o, p, cell, dir, speed, mass, tag) => {
|
|
4565
4582
|
const { c, q } = partXf(o, p);
|
|
@@ -7524,7 +7541,7 @@ var GameTestRoom = (() => {
|
|
|
7524
7541
|
const registry = createSoundRegistry(options.banks);
|
|
7525
7542
|
const voices = createVoiceManager({ ...options.groups ? { groups: options.groups } : {}, ...options.maxVoices === void 0 ? {} : { maxVoices: options.maxVoices } });
|
|
7526
7543
|
const engineRandom = createRng2(seed);
|
|
7527
|
-
const
|
|
7544
|
+
const shared2 = createNoiseStore(engineRandom);
|
|
7528
7545
|
const busSettings = /* @__PURE__ */ new Map();
|
|
7529
7546
|
const busNodes = /* @__PURE__ */ new Map();
|
|
7530
7547
|
const meters = /* @__PURE__ */ new Map();
|
|
@@ -7563,7 +7580,7 @@ var GameTestRoom = (() => {
|
|
|
7563
7580
|
if (!created) return null;
|
|
7564
7581
|
context = created;
|
|
7565
7582
|
chain = buildChain(created, mix, engineRandom);
|
|
7566
|
-
if (mix.noise.create === "eager") noiseBuffer(
|
|
7583
|
+
if (mix.noise.create === "eager") noiseBuffer(shared2, created, mix.noise.seconds);
|
|
7567
7584
|
for (const [bus, setting] of Object.entries(mix.buses ?? {})) {
|
|
7568
7585
|
busSettings.set(bus, { ...setting, ...busSettings.get(bus) });
|
|
7569
7586
|
}
|
|
@@ -7682,8 +7699,8 @@ var GameTestRoom = (() => {
|
|
|
7682
7699
|
const loopHost = {
|
|
7683
7700
|
ready,
|
|
7684
7701
|
output: outputFor,
|
|
7685
|
-
prepareNoise: () => context && prepareNoise(
|
|
7686
|
-
noise: () => noiseBuffer(
|
|
7702
|
+
prepareNoise: () => context && prepareNoise(shared2, context, mix.noise.seconds),
|
|
7703
|
+
noise: () => noiseBuffer(shared2, context, mix.noise.seconds),
|
|
7687
7704
|
register: (loop) => void loops.add(loop),
|
|
7688
7705
|
unregister: (loop) => void loops.delete(loop)
|
|
7689
7706
|
};
|
|
@@ -7691,7 +7708,7 @@ var GameTestRoom = (() => {
|
|
|
7691
7708
|
registry,
|
|
7692
7709
|
register: (bank) => registry.register(bank),
|
|
7693
7710
|
plan: (id, playOptions = {}) => planWith(id, playOptions, createRng2(playOptions.seed ?? seed)),
|
|
7694
|
-
play: (id, playOptions = {}) => playWith(id, playOptions, randomFor(playOptions),
|
|
7711
|
+
play: (id, playOptions = {}) => playWith(id, playOptions, randomFor(playOptions), shared2),
|
|
7695
7712
|
playPlan(plan, playOptions = {}) {
|
|
7696
7713
|
const audio = ready();
|
|
7697
7714
|
if (!audio) return null;
|
|
@@ -7699,13 +7716,13 @@ var GameTestRoom = (() => {
|
|
|
7699
7716
|
const recipe = { id: plan.id, bus: plan.bus, layers: [], sources: [], priority: plan.priority, ...plan.group ? { group: plan.group } : {} };
|
|
7700
7717
|
const voiceId = plan.silent ? void 0 : admit(recipe, plan.level, plan.distance);
|
|
7701
7718
|
if (voiceId === null) return null;
|
|
7702
|
-
if (planUsesNoise(plan)) prepareNoise(
|
|
7703
|
-
return start(plan,
|
|
7719
|
+
if (planUsesNoise(plan)) prepareNoise(shared2, audio, mix.noise.seconds);
|
|
7720
|
+
return start(plan, shared2, voiceId, playOptions.delay);
|
|
7704
7721
|
},
|
|
7705
7722
|
loop: (id, loopOptions = {}) => createLoopHandle(registry.loop(id), loopHost, loopOptions.volume),
|
|
7706
7723
|
channel(channelOptions) {
|
|
7707
7724
|
const random = channelOptions.random ?? (channelOptions.seed === void 0 ? engineRandom : createRng2(channelOptions.seed));
|
|
7708
|
-
const store = channelOptions.ownNoise ? createNoiseStore(random) :
|
|
7725
|
+
const store = channelOptions.ownNoise ? createNoiseStore(random) : shared2;
|
|
7709
7726
|
return {
|
|
7710
7727
|
random,
|
|
7711
7728
|
play: (id, playOptions = {}) => playWith(id, playOptions, random, store),
|
|
@@ -7727,7 +7744,7 @@ var GameTestRoom = (() => {
|
|
|
7727
7744
|
if (!context || !chain) return;
|
|
7728
7745
|
const old = chain;
|
|
7729
7746
|
chain = buildChain(context, mix, engineRandom);
|
|
7730
|
-
if (mix.noise.seconds !== previous.noise.seconds)
|
|
7747
|
+
if (mix.noise.seconds !== previous.noise.seconds) shared2.reset();
|
|
7731
7748
|
for (const node of busNodes.values()) {
|
|
7732
7749
|
node.disconnect();
|
|
7733
7750
|
node.connect(chain.master);
|
|
@@ -7746,7 +7763,7 @@ var GameTestRoom = (() => {
|
|
|
7746
7763
|
warmUp() {
|
|
7747
7764
|
const audio = ready();
|
|
7748
7765
|
if (!audio) return false;
|
|
7749
|
-
noiseBuffer(
|
|
7766
|
+
noiseBuffer(shared2, audio, mix.noise.seconds);
|
|
7750
7767
|
return true;
|
|
7751
7768
|
},
|
|
7752
7769
|
level(bus) {
|
|
@@ -7781,7 +7798,7 @@ var GameTestRoom = (() => {
|
|
|
7781
7798
|
chain = null;
|
|
7782
7799
|
busNodes.clear();
|
|
7783
7800
|
meters.clear();
|
|
7784
|
-
|
|
7801
|
+
shared2.reset();
|
|
7785
7802
|
}
|
|
7786
7803
|
};
|
|
7787
7804
|
}
|
|
@@ -12588,12 +12605,12 @@ var GameTestRoom = (() => {
|
|
|
12588
12605
|
}
|
|
12589
12606
|
function drawing(entry, action) {
|
|
12590
12607
|
const context = engine.context;
|
|
12591
|
-
const
|
|
12608
|
+
const shared2 = context.random;
|
|
12592
12609
|
if (entry.random) context.random = entry.random;
|
|
12593
12610
|
try {
|
|
12594
12611
|
action();
|
|
12595
12612
|
} finally {
|
|
12596
|
-
context.random =
|
|
12613
|
+
context.random = shared2;
|
|
12597
12614
|
}
|
|
12598
12615
|
}
|
|
12599
12616
|
return {
|
|
@@ -40280,6 +40297,81 @@ void main(){
|
|
|
40280
40297
|
return root;
|
|
40281
40298
|
}
|
|
40282
40299
|
|
|
40300
|
+
// ../game-shapes-three/dist/index.js
|
|
40301
|
+
var isTexture = (v) => !!v && typeof v === "object" && v.isTexture === true;
|
|
40302
|
+
function texturesOf(material, out) {
|
|
40303
|
+
for (const value of Object.values(material)) if (isTexture(value)) out.add(value);
|
|
40304
|
+
const uniforms = material.uniforms;
|
|
40305
|
+
if (uniforms) {
|
|
40306
|
+
for (const u of Object.values(uniforms)) if (isTexture(u?.value)) out.add(u.value);
|
|
40307
|
+
}
|
|
40308
|
+
}
|
|
40309
|
+
function collect(roots) {
|
|
40310
|
+
const geometries = /* @__PURE__ */ new Set();
|
|
40311
|
+
const materials = /* @__PURE__ */ new Set();
|
|
40312
|
+
const textures = /* @__PURE__ */ new Set();
|
|
40313
|
+
const skeletons = /* @__PURE__ */ new Set();
|
|
40314
|
+
for (const root of roots) {
|
|
40315
|
+
root.traverse((object) => {
|
|
40316
|
+
const o = object;
|
|
40317
|
+
if (o.geometry && typeof o.geometry.dispose === "function") geometries.add(o.geometry);
|
|
40318
|
+
if (o.skeleton && typeof o.skeleton.dispose === "function") skeletons.add(o.skeleton);
|
|
40319
|
+
const list = Array.isArray(o.material) ? o.material : o.material ? [o.material] : [];
|
|
40320
|
+
for (const m of list) {
|
|
40321
|
+
if (!m || typeof m.dispose !== "function") continue;
|
|
40322
|
+
materials.add(m);
|
|
40323
|
+
texturesOf(m, textures);
|
|
40324
|
+
}
|
|
40325
|
+
});
|
|
40326
|
+
}
|
|
40327
|
+
return { geometries, materials, textures, skeletons };
|
|
40328
|
+
}
|
|
40329
|
+
var marked = /* @__PURE__ */ new WeakSet();
|
|
40330
|
+
var shared = (r) => r.userData?.shared === true || marked.has(r);
|
|
40331
|
+
function releaseObject3D(roots, options = {}) {
|
|
40332
|
+
const list = Array.isArray(roots) ? roots : [roots];
|
|
40333
|
+
const report = { geometries: 0, materials: 0, textures: 0 };
|
|
40334
|
+
if (list.length === 0) return report;
|
|
40335
|
+
const found = collect(list);
|
|
40336
|
+
const keepRoots = options.keep === void 0 ? [] : Array.isArray(options.keep) ? options.keep : [options.keep];
|
|
40337
|
+
const releasing = new Set(list);
|
|
40338
|
+
for (const keep of keepRoots) {
|
|
40339
|
+
const walk = (o) => {
|
|
40340
|
+
if (releasing.has(o)) return;
|
|
40341
|
+
const owner = o;
|
|
40342
|
+
if (owner.geometry) found.geometries.delete(owner.geometry);
|
|
40343
|
+
if (owner.skeleton) found.skeletons.delete(owner.skeleton);
|
|
40344
|
+
const mats = Array.isArray(owner.material) ? owner.material : owner.material ? [owner.material] : [];
|
|
40345
|
+
for (const m of mats) {
|
|
40346
|
+
if (!m) continue;
|
|
40347
|
+
found.materials.delete(m);
|
|
40348
|
+
const t = /* @__PURE__ */ new Set();
|
|
40349
|
+
texturesOf(m, t);
|
|
40350
|
+
for (const x of t) found.textures.delete(x);
|
|
40351
|
+
}
|
|
40352
|
+
for (const c of o.children) walk(c);
|
|
40353
|
+
};
|
|
40354
|
+
walk(keep);
|
|
40355
|
+
}
|
|
40356
|
+
for (const g of found.geometries) {
|
|
40357
|
+
if (shared(g)) continue;
|
|
40358
|
+
g.dispose();
|
|
40359
|
+
report.geometries++;
|
|
40360
|
+
}
|
|
40361
|
+
for (const m of found.materials) {
|
|
40362
|
+
if (shared(m)) continue;
|
|
40363
|
+
m.dispose();
|
|
40364
|
+
report.materials++;
|
|
40365
|
+
}
|
|
40366
|
+
for (const t of found.textures) {
|
|
40367
|
+
if (shared(t)) continue;
|
|
40368
|
+
t.dispose();
|
|
40369
|
+
report.textures++;
|
|
40370
|
+
}
|
|
40371
|
+
for (const s of found.skeletons) s.dispose();
|
|
40372
|
+
return report;
|
|
40373
|
+
}
|
|
40374
|
+
|
|
40283
40375
|
// src/segment-box.ts
|
|
40284
40376
|
var segmentTouchesBox = (from, to, min2, max2) => {
|
|
40285
40377
|
let near = 0;
|
|
@@ -40320,9 +40412,13 @@ void main(){
|
|
|
40320
40412
|
const projectiles = [];
|
|
40321
40413
|
const meshes = [];
|
|
40322
40414
|
const up = new THREE.Vector3(0, 1, 0);
|
|
40415
|
+
const drop = (objects) => {
|
|
40416
|
+
for (const object of objects) object.removeFromParent();
|
|
40417
|
+
releaseObject3D(objects, { keep: scene2 });
|
|
40418
|
+
};
|
|
40323
40419
|
const clear = () => {
|
|
40324
40420
|
projectiles.length = 0;
|
|
40325
|
-
|
|
40421
|
+
drop(meshes);
|
|
40326
40422
|
meshes.length = 0;
|
|
40327
40423
|
};
|
|
40328
40424
|
const addMesh = (geometry, color, metalness, at3) => {
|
|
@@ -40346,13 +40442,12 @@ void main(){
|
|
|
40346
40442
|
};
|
|
40347
40443
|
const remove = (projectile) => {
|
|
40348
40444
|
for (const extra of projectile.attached ?? []) {
|
|
40349
|
-
extra.removeFromParent();
|
|
40350
40445
|
const extraAt = meshes.indexOf(extra);
|
|
40351
40446
|
if (extraAt >= 0) meshes.splice(extraAt, 1);
|
|
40352
40447
|
}
|
|
40353
|
-
projectile.mesh.removeFromParent();
|
|
40354
40448
|
const meshAt = meshes.indexOf(projectile.mesh);
|
|
40355
40449
|
if (meshAt >= 0) meshes.splice(meshAt, 1);
|
|
40450
|
+
drop([...projectile.attached ?? [], projectile.mesh]);
|
|
40356
40451
|
const at3 = projectiles.indexOf(projectile);
|
|
40357
40452
|
if (at3 >= 0) projectiles.splice(at3, 1);
|
|
40358
40453
|
};
|
|
@@ -47207,6 +47302,23 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
47207
47302
|
}
|
|
47208
47303
|
return m;
|
|
47209
47304
|
};
|
|
47305
|
+
let releaseBatch = null;
|
|
47306
|
+
const dropTree = (root) => {
|
|
47307
|
+
if (!root) return;
|
|
47308
|
+
if (releaseBatch) releaseBatch.push(root);
|
|
47309
|
+
else releaseObject3D(root, { keep: scene2 });
|
|
47310
|
+
};
|
|
47311
|
+
const releasingTogether = (fn) => {
|
|
47312
|
+
if (releaseBatch) return fn();
|
|
47313
|
+
releaseBatch = [];
|
|
47314
|
+
try {
|
|
47315
|
+
fn();
|
|
47316
|
+
} finally {
|
|
47317
|
+
const roots = releaseBatch;
|
|
47318
|
+
releaseBatch = null;
|
|
47319
|
+
releaseObject3D(roots, { keep: scene2 });
|
|
47320
|
+
}
|
|
47321
|
+
};
|
|
47210
47322
|
const removeEntry = (id) => {
|
|
47211
47323
|
const e = entries.get(id);
|
|
47212
47324
|
if (!e) return;
|
|
@@ -47223,7 +47335,10 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
47223
47335
|
e.follower?.dispose?.();
|
|
47224
47336
|
if (world.has(id)) world.remove(id);
|
|
47225
47337
|
e.so.root.removeFromParent();
|
|
47338
|
+
const inner = wrapped.get(e.so.root);
|
|
47226
47339
|
letGo(e.so.root);
|
|
47340
|
+
dropTree(e.so.root);
|
|
47341
|
+
dropTree(inner);
|
|
47227
47342
|
entries.delete(id);
|
|
47228
47343
|
doors.forget(id);
|
|
47229
47344
|
rendererPieces.delete(id);
|
|
@@ -47239,12 +47354,14 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
47239
47354
|
}
|
|
47240
47355
|
if (world.has(id)) world.remove(id);
|
|
47241
47356
|
p?.root.removeFromParent();
|
|
47357
|
+
dropTree(p?.root);
|
|
47242
47358
|
rendererPieces.delete(id);
|
|
47243
47359
|
splitOf.delete(id);
|
|
47244
47360
|
}
|
|
47245
47361
|
loose.length = 0;
|
|
47246
47362
|
};
|
|
47247
|
-
const clearEverything = () =>
|
|
47363
|
+
const clearEverything = () => releasingTogether(clearEverythingNow);
|
|
47364
|
+
const clearEverythingNow = () => {
|
|
47248
47365
|
if (heldEntry || heldPiece) releaseHeld();
|
|
47249
47366
|
useItemPlayer = null;
|
|
47250
47367
|
playing.length = 0;
|
|
@@ -47293,8 +47410,10 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
47293
47410
|
seating.release();
|
|
47294
47411
|
pushByKey = false;
|
|
47295
47412
|
push.end();
|
|
47296
|
-
|
|
47297
|
-
|
|
47413
|
+
releasingTogether(() => {
|
|
47414
|
+
clearEverythingNow();
|
|
47415
|
+
for (const id of [...entries.keys()]) removeEntry(id);
|
|
47416
|
+
});
|
|
47298
47417
|
renderer.reset();
|
|
47299
47418
|
for (const listener of [...resetListeners]) listener();
|
|
47300
47419
|
tools.clear();
|
|
@@ -47447,11 +47566,11 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
47447
47566
|
};
|
|
47448
47567
|
const reachAvatar = () => {
|
|
47449
47568
|
const doorHand = doors.handTargets();
|
|
47450
|
-
const targets = push.active ? null : heldPiece ? twistHand : handSource?.() ?? null;
|
|
47569
|
+
const targets = push.active ? null : doorHand ?? (heldPiece ? twistHand : handSource?.() ?? null);
|
|
47451
47570
|
lastHand = {
|
|
47452
47571
|
stance: push.active || doorHand ? "hold" : handStances[toolId] ?? (targets ? "hold" : "relaxed"),
|
|
47453
47572
|
triggerFinger: targets?.fingers?.index ?? null,
|
|
47454
|
-
targets: push.handTargets() ??
|
|
47573
|
+
targets: push.handTargets() ?? targets
|
|
47455
47574
|
};
|
|
47456
47575
|
if (!avatar?.reach) return;
|
|
47457
47576
|
avatar.reach(targets, { camera: camera2, keepOutside: { contact: (origin, direction, maxDistance) => rayWorld(origin, direction, maxDistance)?.distance ?? null } });
|