@adatechnology/game-test-room 0.19.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/index.d.ts +16 -1
- package/dist/index.global.js +743 -134
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +78 -9
- package/dist/index.js.map +1 -1
- package/package.json +14 -13
package/dist/index.global.js
CHANGED
|
@@ -605,9 +605,9 @@ var GameTestRoom = (() => {
|
|
|
605
605
|
const tz = 2 * (qx * v[1] - qy * v[0]);
|
|
606
606
|
return [v[0] + qw * tx + (qy * tz - qz * ty), v[1] + qw * ty + (qz * tx - qx * tz), v[2] + qw * tz + (qx * ty - qy * tx)];
|
|
607
607
|
};
|
|
608
|
-
var toLocal = (position,
|
|
609
|
-
var toWorld = (position,
|
|
610
|
-
const r = rotateVec(
|
|
608
|
+
var toLocal = (position, rotation2, p) => rotateVec([-rotation2[0], -rotation2[1], -rotation2[2], rotation2[3]], [p[0] - position[0], p[1] - position[1], p[2] - position[2]]);
|
|
609
|
+
var toWorld = (position, rotation2, p) => {
|
|
610
|
+
const r = rotateVec(rotation2, p);
|
|
611
611
|
return [r[0] + position[0], r[1] + position[1], r[2] + position[2]];
|
|
612
612
|
};
|
|
613
613
|
var shapeDims = (s) => {
|
|
@@ -1012,8 +1012,8 @@ var GameTestRoom = (() => {
|
|
|
1012
1012
|
};
|
|
1013
1013
|
var cellsOutside = (cells, thin, point, radius) => cells.filter((c) => planeDistance(c, thin, point) > radius);
|
|
1014
1014
|
var MAX_MARKS_PER_FRAGMENT = 12;
|
|
1015
|
-
var marksInBox = (center, size,
|
|
1016
|
-
const inverse =
|
|
1015
|
+
var marksInBox = (center, size, rotation2, holes) => {
|
|
1016
|
+
const inverse = rotation2 ? quat.conjugate(rotation2) : void 0;
|
|
1017
1017
|
const marks = [];
|
|
1018
1018
|
for (const hole of holes) {
|
|
1019
1019
|
const offset = [hole.point[0] - center[0], hole.point[1] - center[1], hole.point[2] - center[2]];
|
|
@@ -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;
|
|
@@ -3601,8 +3602,8 @@ var GameTestRoom = (() => {
|
|
|
3601
3602
|
}
|
|
3602
3603
|
solveStructure(o);
|
|
3603
3604
|
if (peak <= sec.steel) return;
|
|
3604
|
-
const
|
|
3605
|
-
p.rt.hinge = (p.rt.hinge ?? 0) +
|
|
3605
|
+
const rotation2 = (elasticEnergy(peak, L, EI, flexure.loadFactor) - elasticEnergy(sec.steel, L, EI, flexure.loadFactor)) / (2 * sec.steel);
|
|
3606
|
+
p.rt.hinge = (p.rt.hinge ?? 0) + rotation2;
|
|
3606
3607
|
markDamaged(p);
|
|
3607
3608
|
if (p.rt.hinge >= flexure.failRotationDeg * Math.PI / 180) hingeDrop(o, p, src);
|
|
3608
3609
|
};
|
|
@@ -4304,8 +4305,8 @@ var GameTestRoom = (() => {
|
|
|
4304
4305
|
const detachEvents = (o, opened, by, src) => {
|
|
4305
4306
|
for (const j of opened) emit2({ ...base(o, src), type: "detach", joint: j.spec.id, parts: [j.spec.a, j.spec.b], by, groups: o.st.groups.map((g) => [...g]) });
|
|
4306
4307
|
};
|
|
4307
|
-
const slideOffResting = (o,
|
|
4308
|
-
const upY = 1 - 2 * (
|
|
4308
|
+
const slideOffResting = (o, rotation2) => {
|
|
4309
|
+
const upY = 1 - 2 * (rotation2[0] * rotation2[0] + rotation2[2] * rotation2[2]);
|
|
4309
4310
|
if (upY >= RESTING_HOLD_COS) return;
|
|
4310
4311
|
const opened = o.joints.filter((j) => j.spec.kind === "resting" && !j.st.open);
|
|
4311
4312
|
if (opened.length === 0) return;
|
|
@@ -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);
|
|
@@ -5712,11 +5729,11 @@ var GameTestRoom = (() => {
|
|
|
5712
5729
|
impls.set(id, { impl, position: opts.position ?? [0, 0, 0], rotation: opts.rotation ?? [0, 0, 0, 1], poses: /* @__PURE__ */ new Map() });
|
|
5713
5730
|
return id;
|
|
5714
5731
|
},
|
|
5715
|
-
setPartPose(objectId, partId, position,
|
|
5716
|
-
const q = quatFromEuler(...
|
|
5732
|
+
setPartPose(objectId, partId, position, rotation2) {
|
|
5733
|
+
const q = quatFromEuler(...rotation2 ?? [0, 0, 0]);
|
|
5717
5734
|
const im = impls.get(objectId);
|
|
5718
5735
|
if (im) {
|
|
5719
|
-
im.impl.setPartPose?.(partId, position,
|
|
5736
|
+
im.impl.setPartPose?.(partId, position, rotation2);
|
|
5720
5737
|
im.poses.set(partId, { pos: [position[0], position[1], position[2]], q });
|
|
5721
5738
|
return;
|
|
5722
5739
|
}
|
|
@@ -5733,17 +5750,17 @@ var GameTestRoom = (() => {
|
|
|
5733
5750
|
},
|
|
5734
5751
|
has: (id) => taken(id),
|
|
5735
5752
|
ids: () => [...objects.keys(), ...impls.keys()],
|
|
5736
|
-
setTransform(id, position,
|
|
5753
|
+
setTransform(id, position, rotation2) {
|
|
5737
5754
|
const im = impls.get(id);
|
|
5738
5755
|
if (im) {
|
|
5739
5756
|
im.position = [position[0], position[1], position[2]];
|
|
5740
|
-
im.rotation = [
|
|
5757
|
+
im.rotation = [rotation2[0], rotation2[1], rotation2[2], rotation2[3]];
|
|
5741
5758
|
return;
|
|
5742
5759
|
}
|
|
5743
5760
|
const o = getObj(id);
|
|
5744
|
-
o.base = { pos: [position[0], position[1], position[2]], rot: [
|
|
5761
|
+
o.base = { pos: [position[0], position[1], position[2]], rot: [rotation2[0], rotation2[1], rotation2[2], rotation2[3]] };
|
|
5745
5762
|
applySoilPose(o);
|
|
5746
|
-
slideOffResting(o,
|
|
5763
|
+
slideOffResting(o, rotation2);
|
|
5747
5764
|
},
|
|
5748
5765
|
splitGroup(id, group, newId) {
|
|
5749
5766
|
if (impls.has(id)) throw new Error(`object "${id}" is a registered DestructibleImpl and cannot be split; its module owns its pieces`);
|
|
@@ -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
|
}
|
|
@@ -9149,11 +9166,231 @@ var GameTestRoom = (() => {
|
|
|
9149
9166
|
glow.outIntensity = glow.i * Math.pow(1 - age, glow.curve) * flicker;
|
|
9150
9167
|
}
|
|
9151
9168
|
}
|
|
9169
|
+
var LEHMER_MULTIPLIER = 16807;
|
|
9170
|
+
var LEHMER_MODULUS = 2147483647;
|
|
9171
|
+
var HASH_MIX = 2654435761;
|
|
9172
|
+
function normalizeLehmerSeed(seed) {
|
|
9173
|
+
const whole = Math.floor(Math.abs(seed)) % (LEHMER_MODULUS - 1);
|
|
9174
|
+
return whole === 0 ? 1 : whole;
|
|
9175
|
+
}
|
|
9176
|
+
function lehmer(seed) {
|
|
9177
|
+
let state = normalizeLehmerSeed(seed);
|
|
9178
|
+
const next = () => {
|
|
9179
|
+
state = state * LEHMER_MULTIPLIER % LEHMER_MODULUS;
|
|
9180
|
+
return (state - 1) / (LEHMER_MODULUS - 1);
|
|
9181
|
+
};
|
|
9182
|
+
return {
|
|
9183
|
+
next,
|
|
9184
|
+
between: (min2, max2) => min2 + (max2 - min2) * next(),
|
|
9185
|
+
direction(out) {
|
|
9186
|
+
const up = next() * 2 - 1;
|
|
9187
|
+
const angle = next() * Math.PI * 2;
|
|
9188
|
+
const ring2 = Math.sqrt(1 - up * up);
|
|
9189
|
+
out.x = ring2 * Math.cos(angle);
|
|
9190
|
+
out.y = up;
|
|
9191
|
+
out.z = ring2 * Math.sin(angle);
|
|
9192
|
+
return out;
|
|
9193
|
+
},
|
|
9194
|
+
get state() {
|
|
9195
|
+
return state;
|
|
9196
|
+
}
|
|
9197
|
+
};
|
|
9198
|
+
}
|
|
9199
|
+
function mixEventSeed(eventSeed) {
|
|
9200
|
+
let mixed = Math.imul((eventSeed | 0) ^ HASH_MIX, 2246822507);
|
|
9201
|
+
mixed ^= mixed >>> 13;
|
|
9202
|
+
mixed = Math.imul(mixed, 3266489909);
|
|
9203
|
+
mixed ^= mixed >>> 16;
|
|
9204
|
+
return (mixed >>> 0) % (LEHMER_MODULUS - 1) + 1;
|
|
9205
|
+
}
|
|
9206
|
+
function streamFor2(eventSeed) {
|
|
9207
|
+
return lehmer(mixEventSeed(eventSeed));
|
|
9208
|
+
}
|
|
9209
|
+
var SKIN = 5e-3;
|
|
9210
|
+
var MAX_PAD = 0.45;
|
|
9211
|
+
function rotation(q) {
|
|
9212
|
+
const [x, y, z, w] = q ?? [0, 0, 0, 1];
|
|
9213
|
+
const n = Math.hypot(x, y, z, w) || 1;
|
|
9214
|
+
const qx = x / n;
|
|
9215
|
+
const qy = y / n;
|
|
9216
|
+
const qz = z / n;
|
|
9217
|
+
const qw = w / n;
|
|
9218
|
+
return new Float64Array([
|
|
9219
|
+
1 - 2 * (qy * qy + qz * qz),
|
|
9220
|
+
2 * (qx * qy - qz * qw),
|
|
9221
|
+
2 * (qx * qz + qy * qw),
|
|
9222
|
+
2 * (qx * qy + qz * qw),
|
|
9223
|
+
1 - 2 * (qx * qx + qz * qz),
|
|
9224
|
+
2 * (qy * qz - qx * qw),
|
|
9225
|
+
2 * (qx * qz - qy * qw),
|
|
9226
|
+
2 * (qy * qz + qx * qw),
|
|
9227
|
+
1 - 2 * (qx * qx + qy * qy)
|
|
9228
|
+
]);
|
|
9229
|
+
}
|
|
9230
|
+
var Enclosures = class {
|
|
9231
|
+
constructor(seed = 20973) {
|
|
9232
|
+
__publicField(this, "spaces", /* @__PURE__ */ new Map());
|
|
9233
|
+
__publicField(this, "list", []);
|
|
9234
|
+
__publicField(this, "random");
|
|
9235
|
+
__publicField(this, "out", { x: 0, y: 0, z: 0, nx: 0, ny: 0, nz: 0 });
|
|
9236
|
+
__publicField(this, "l0", new Float64Array(3));
|
|
9237
|
+
__publicField(this, "l1", new Float64Array(3));
|
|
9238
|
+
__publicField(this, "q", new Float64Array(3));
|
|
9239
|
+
this.random = lehmer(seed);
|
|
9240
|
+
}
|
|
9241
|
+
get empty() {
|
|
9242
|
+
return this.list.length === 0;
|
|
9243
|
+
}
|
|
9244
|
+
get size() {
|
|
9245
|
+
return this.list.length;
|
|
9246
|
+
}
|
|
9247
|
+
/** Declares, moves or (with `null`) ends the space `id`. */
|
|
9248
|
+
set(id, enclosure) {
|
|
9249
|
+
if (!enclosure) {
|
|
9250
|
+
if (this.spaces.delete(id)) this.list = [...this.spaces.values()];
|
|
9251
|
+
return;
|
|
9252
|
+
}
|
|
9253
|
+
const [hx, hy, hz] = enclosure.halfSize;
|
|
9254
|
+
const space = {
|
|
9255
|
+
cx: enclosure.center[0],
|
|
9256
|
+
cy: enclosure.center[1],
|
|
9257
|
+
cz: enclosure.center[2],
|
|
9258
|
+
hx: Math.abs(hx),
|
|
9259
|
+
hy: Math.abs(hy),
|
|
9260
|
+
hz: Math.abs(hz),
|
|
9261
|
+
r: rotation(enclosure.orientation),
|
|
9262
|
+
radius: Math.hypot(hx, hy, hz),
|
|
9263
|
+
openings: enclosure.openings ?? [],
|
|
9264
|
+
leak: Math.max(0, enclosure.leak ?? 0)
|
|
9265
|
+
};
|
|
9266
|
+
const old = this.spaces.get(id);
|
|
9267
|
+
this.spaces.set(id, space);
|
|
9268
|
+
const at3 = old ? this.list.indexOf(old) : -1;
|
|
9269
|
+
if (at3 >= 0) this.list[at3] = space;
|
|
9270
|
+
else this.list.push(space);
|
|
9271
|
+
}
|
|
9272
|
+
get(id) {
|
|
9273
|
+
const s = this.spaces.get(id);
|
|
9274
|
+
if (!s) return void 0;
|
|
9275
|
+
return { center: [s.cx, s.cy, s.cz], halfSize: [s.hx, s.hy, s.hz], openings: s.openings, leak: s.leak };
|
|
9276
|
+
}
|
|
9277
|
+
ids() {
|
|
9278
|
+
return [...this.spaces.keys()];
|
|
9279
|
+
}
|
|
9280
|
+
clear() {
|
|
9281
|
+
this.spaces.clear();
|
|
9282
|
+
this.list = [];
|
|
9283
|
+
}
|
|
9284
|
+
/** Whether a point is inside any space (on the inside of its walls). */
|
|
9285
|
+
inside(x, y, z) {
|
|
9286
|
+
for (const s of this.list) {
|
|
9287
|
+
this.toLocal(s, x, y, z, this.l0);
|
|
9288
|
+
if (Math.abs(this.l0[0]) <= s.hx && Math.abs(this.l0[1]) <= s.hy && Math.abs(this.l0[2]) <= s.hz) return true;
|
|
9289
|
+
}
|
|
9290
|
+
return false;
|
|
9291
|
+
}
|
|
9292
|
+
toLocal(s, x, y, z, out) {
|
|
9293
|
+
const dx = x - s.cx;
|
|
9294
|
+
const dy = y - s.cy;
|
|
9295
|
+
const dz = z - s.cz;
|
|
9296
|
+
const r = s.r;
|
|
9297
|
+
out[0] = r[0] * dx + r[3] * dy + r[6] * dz;
|
|
9298
|
+
out[1] = r[1] * dx + r[4] * dy + r[7] * dz;
|
|
9299
|
+
out[2] = r[2] * dx + r[5] * dy + r[8] * dz;
|
|
9300
|
+
}
|
|
9301
|
+
/** Passes at `rate` per second. */
|
|
9302
|
+
chance(rate, dt) {
|
|
9303
|
+
return rate > 0 && this.random.next() < 1 - Math.exp(-rate * dt);
|
|
9304
|
+
}
|
|
9305
|
+
/** The opening the wall point `q` (local) is in lets it through now. */
|
|
9306
|
+
through(s, q, dt) {
|
|
9307
|
+
for (const o of s.openings) {
|
|
9308
|
+
if (Math.abs(q[0] - o.center[0]) > o.halfSize[0] || Math.abs(q[1] - o.center[1]) > o.halfSize[1] || Math.abs(q[2] - o.center[2]) > o.halfSize[2]) continue;
|
|
9309
|
+
if (o.rate === void 0 || this.chance(o.rate, dt)) return true;
|
|
9310
|
+
}
|
|
9311
|
+
return this.chance(s.leak, dt);
|
|
9312
|
+
}
|
|
9313
|
+
confine(x0, y0, z0, x1, y1, z1, pad2, dt) {
|
|
9314
|
+
const list = this.list;
|
|
9315
|
+
if (list.length === 0) return false;
|
|
9316
|
+
const p = Math.min(Math.max(0, pad2), MAX_PAD);
|
|
9317
|
+
const l0 = this.l0;
|
|
9318
|
+
const l1 = this.l1;
|
|
9319
|
+
const q = this.q;
|
|
9320
|
+
for (const s of list) {
|
|
9321
|
+
const reach = s.radius + p + 0.05;
|
|
9322
|
+
const dx = x1 - s.cx;
|
|
9323
|
+
const dy = y1 - s.cy;
|
|
9324
|
+
const dz = z1 - s.cz;
|
|
9325
|
+
if (dx * dx + dy * dy + dz * dz > reach * reach) {
|
|
9326
|
+
const ex = x0 - s.cx;
|
|
9327
|
+
const ey = y0 - s.cy;
|
|
9328
|
+
const ez = z0 - s.cz;
|
|
9329
|
+
if (ex * ex + ey * ey + ez * ez > reach * reach) continue;
|
|
9330
|
+
}
|
|
9331
|
+
this.toLocal(s, x0, y0, z0, l0);
|
|
9332
|
+
this.toLocal(s, x1, y1, z1, l1);
|
|
9333
|
+
const h = [s.hx, s.hy, s.hz];
|
|
9334
|
+
const in0 = Math.abs(l0[0]) <= s.hx && Math.abs(l0[1]) <= s.hy && Math.abs(l0[2]) <= s.hz;
|
|
9335
|
+
let axis2 = 0;
|
|
9336
|
+
let sign = 1;
|
|
9337
|
+
if (in0) {
|
|
9338
|
+
if (Math.abs(l1[0]) <= s.hx && Math.abs(l1[1]) <= s.hy && Math.abs(l1[2]) <= s.hz) continue;
|
|
9339
|
+
for (let a = 0; a < 3; a++) q[a] = Math.min(h[a], Math.max(-h[a], l1[a]));
|
|
9340
|
+
if (this.through(s, q, dt)) continue;
|
|
9341
|
+
let worst = -Infinity;
|
|
9342
|
+
for (let a = 0; a < 3; a++) {
|
|
9343
|
+
const over = Math.abs(l1[a]) - h[a];
|
|
9344
|
+
if (over > worst) {
|
|
9345
|
+
worst = over;
|
|
9346
|
+
axis2 = a;
|
|
9347
|
+
}
|
|
9348
|
+
}
|
|
9349
|
+
sign = l1[axis2] < 0 ? -1 : 1;
|
|
9350
|
+
for (let a = 0; a < 3; a++) l1[a] = Math.min(h[a] - SKIN, Math.max(-(h[a] - SKIN), l1[a]));
|
|
9351
|
+
sign = -sign;
|
|
9352
|
+
} else {
|
|
9353
|
+
const padded0 = Math.abs(l0[0]) <= s.hx + p && Math.abs(l0[1]) <= s.hy + p && Math.abs(l0[2]) <= s.hz + p;
|
|
9354
|
+
const bound = padded0 ? 0 : p;
|
|
9355
|
+
if (!(Math.abs(l1[0]) <= s.hx + bound && Math.abs(l1[1]) <= s.hy + bound && Math.abs(l1[2]) <= s.hz + bound)) continue;
|
|
9356
|
+
for (let a = 0; a < 3; a++) q[a] = Math.min(h[a], Math.max(-h[a], l1[a]));
|
|
9357
|
+
if (this.through(s, q, dt)) continue;
|
|
9358
|
+
let worst = -Infinity;
|
|
9359
|
+
for (let a = 0; a < 3; a++) {
|
|
9360
|
+
const over = Math.abs(l0[a]) - (h[a] + bound);
|
|
9361
|
+
if (over > worst) {
|
|
9362
|
+
worst = over;
|
|
9363
|
+
axis2 = a;
|
|
9364
|
+
}
|
|
9365
|
+
}
|
|
9366
|
+
sign = l0[axis2] < 0 ? -1 : 1;
|
|
9367
|
+
l1[axis2] = sign * (h[axis2] + bound + SKIN);
|
|
9368
|
+
}
|
|
9369
|
+
const r = s.r;
|
|
9370
|
+
const out = this.out;
|
|
9371
|
+
out.x = s.cx + r[0] * l1[0] + r[1] * l1[1] + r[2] * l1[2];
|
|
9372
|
+
out.y = s.cy + r[3] * l1[0] + r[4] * l1[1] + r[5] * l1[2];
|
|
9373
|
+
out.z = s.cz + r[6] * l1[0] + r[7] * l1[1] + r[8] * l1[2];
|
|
9374
|
+
out.nx = r[axis2] * sign;
|
|
9375
|
+
out.ny = r[3 + axis2] * sign;
|
|
9376
|
+
out.nz = r[6 + axis2] * sign;
|
|
9377
|
+
return true;
|
|
9378
|
+
}
|
|
9379
|
+
return false;
|
|
9380
|
+
}
|
|
9381
|
+
};
|
|
9382
|
+
function slideAlong(out, vx2, vy2, vz2) {
|
|
9383
|
+
const into = vx2 * out.nx + vy2 * out.ny + vz2 * out.nz;
|
|
9384
|
+
if (into >= 0) return [vx2, vy2, vz2];
|
|
9385
|
+
return [vx2 - into * out.nx, vy2 - into * out.ny, vz2 - into * out.nz];
|
|
9386
|
+
}
|
|
9152
9387
|
var FLOOR_FRACTION = 0.4;
|
|
9153
9388
|
var FLOOR_BOUNCE = -0.2;
|
|
9154
9389
|
var ARRIVAL_FRAME = 30;
|
|
9155
9390
|
var ARRIVAL_BASE = 0.3;
|
|
9156
9391
|
var GROWTH_CAP_SECONDS = 3.5;
|
|
9392
|
+
var CARRIED_KINDS = [true, true, false, true, false];
|
|
9393
|
+
var PAD_OF_SIZE = 0.35;
|
|
9157
9394
|
function createPuffPool(capacity) {
|
|
9158
9395
|
const placeholder = { next: () => 0, between: (min2) => min2, direction: (out) => out, state: 0 };
|
|
9159
9396
|
return new OrderedPool(capacity, () => ({
|
|
@@ -9248,13 +9485,24 @@ var GameTestRoom = (() => {
|
|
|
9248
9485
|
if (puff3.vy < 0) puff3.vy *= FLOOR_BOUNCE;
|
|
9249
9486
|
}
|
|
9250
9487
|
}
|
|
9251
|
-
function updatePuffs(pool, dt, wind) {
|
|
9488
|
+
function updatePuffs(pool, dt, wind, confiner) {
|
|
9252
9489
|
pool.compact(ageOrKeep2, dt);
|
|
9490
|
+
const confining = confiner !== void 0 && !confiner.empty;
|
|
9253
9491
|
for (const puff3 of pool.items) {
|
|
9254
9492
|
const age = puff3.t / puff3.life;
|
|
9255
9493
|
const heat = puff3.h0 > 0 ? puff3.h0 * Math.pow(Math.max(0, 1 - puff3.t / puff3.hl), 1.25) : 0;
|
|
9494
|
+
const x0 = puff3.x;
|
|
9495
|
+
const y0 = puff3.y;
|
|
9496
|
+
const z0 = puff3.z;
|
|
9256
9497
|
if (puff3.ring) moveOnRing(puff3, puff3.ring, wind);
|
|
9257
9498
|
else moveFree(puff3, dt, age, heat, wind);
|
|
9499
|
+
if (confining && CARRIED_KINDS[puff3.kind] && confiner.confine(x0, y0, z0, puff3.x, puff3.y, puff3.z, puff3.size * PAD_OF_SIZE, dt)) {
|
|
9500
|
+
const out = confiner.out;
|
|
9501
|
+
puff3.x = out.x;
|
|
9502
|
+
puff3.y = out.y;
|
|
9503
|
+
puff3.z = out.z;
|
|
9504
|
+
[puff3.vx, puff3.vy, puff3.vz] = slideAlong(out, puff3.vx, puff3.vy, puff3.vz);
|
|
9505
|
+
}
|
|
9258
9506
|
const size = puff3.s0 + (puff3.s1 - puff3.s0) * (1 - Math.exp(-puff3.t * puff3.gk)) + puff3.sg * Math.min(puff3.t, GROWTH_CAP_SECONDS);
|
|
9259
9507
|
puff3.size = size * Math.min(1, puff3.t * ARRIVAL_FRAME + ARRIVAL_BASE);
|
|
9260
9508
|
puff3.age = age;
|
|
@@ -9780,10 +10028,10 @@ var GameTestRoom = (() => {
|
|
|
9780
10028
|
])
|
|
9781
10029
|
]
|
|
9782
10030
|
};
|
|
9783
|
-
function localToWorld(translation,
|
|
10031
|
+
function localToWorld(translation, rotation2, local2) {
|
|
9784
10032
|
const [x, y, z] = local2;
|
|
9785
|
-
const [a, c, e] = [Math.cos(
|
|
9786
|
-
const [b, d, f] = [Math.sin(
|
|
10033
|
+
const [a, c, e] = [Math.cos(rotation2[0]), Math.cos(rotation2[1]), Math.cos(rotation2[2])];
|
|
10034
|
+
const [b, d, f] = [Math.sin(rotation2[0]), Math.sin(rotation2[1]), Math.sin(rotation2[2])];
|
|
9787
10035
|
const [ae, af, be, bf] = [a * e, a * f, b * e, b * f];
|
|
9788
10036
|
return [
|
|
9789
10037
|
c * e * x + -c * f * y + d * z + translation[0],
|
|
@@ -11446,46 +11694,6 @@ var GameTestRoom = (() => {
|
|
|
11446
11694
|
var ALL_EFFECTS = [BLOOD_HIT, HEADSHOT, DISMEMBER, BLOATER_CLOUD, SCREAMER_SHRIEK, CORPSE_DECAY, REANIMATION, EYES_IN_FOG, MUZZLE_FLASH, IMPACT_BY_MATERIAL, PENETRATION, CASINGS_AND_MAGAZINE, MOLOTOV, GRENADE, EXPLOSIVE_BARREL, SHOPFRONT_GLASS, DOOR_STAGES, BUILDING_COLLAPSE, BLOCK_WALL, METAL_DOOR_EFFECT, IRON_RAILING, WOODEN_FENCE, HIT_POINT_BREAKAGE, PRESSURE_CYLINDERS, BUILDING_FIRE, RAIN_AND_PUDDLES, FOG_AND_ASH, SCRAPING_SPARKS, ENGINE_SMOKE, FUEL_LEAK, CAR_EXPLOSION, WINDSHIELD, HEADLIGHTS_IN_RAIN, DAMAGE_AND_BITE, INFECTION_PHASES, PANIC, BLOATER_BLINDNESS, CAMPFIRE, COUGH_AND_BREATH];
|
|
11447
11695
|
var WORKSHOP_EFFECTS = Object.fromEntries(ALL_EFFECTS.map((effect) => [effect.id, effect]));
|
|
11448
11696
|
var GAME_EFFECTS = { ...WORKSHOP_EFFECTS, ...Object.fromEntries([...EVENT_EFFECTS, ...VIEWMODEL_EFFECTS, ...VEHICLE_EFFECTS].map((effect) => [effect.id, effect])) };
|
|
11449
|
-
var LEHMER_MULTIPLIER = 16807;
|
|
11450
|
-
var LEHMER_MODULUS = 2147483647;
|
|
11451
|
-
var HASH_MIX = 2654435761;
|
|
11452
|
-
function normalizeLehmerSeed(seed) {
|
|
11453
|
-
const whole = Math.floor(Math.abs(seed)) % (LEHMER_MODULUS - 1);
|
|
11454
|
-
return whole === 0 ? 1 : whole;
|
|
11455
|
-
}
|
|
11456
|
-
function lehmer(seed) {
|
|
11457
|
-
let state = normalizeLehmerSeed(seed);
|
|
11458
|
-
const next = () => {
|
|
11459
|
-
state = state * LEHMER_MULTIPLIER % LEHMER_MODULUS;
|
|
11460
|
-
return (state - 1) / (LEHMER_MODULUS - 1);
|
|
11461
|
-
};
|
|
11462
|
-
return {
|
|
11463
|
-
next,
|
|
11464
|
-
between: (min2, max2) => min2 + (max2 - min2) * next(),
|
|
11465
|
-
direction(out) {
|
|
11466
|
-
const up = next() * 2 - 1;
|
|
11467
|
-
const angle = next() * Math.PI * 2;
|
|
11468
|
-
const ring2 = Math.sqrt(1 - up * up);
|
|
11469
|
-
out.x = ring2 * Math.cos(angle);
|
|
11470
|
-
out.y = up;
|
|
11471
|
-
out.z = ring2 * Math.sin(angle);
|
|
11472
|
-
return out;
|
|
11473
|
-
},
|
|
11474
|
-
get state() {
|
|
11475
|
-
return state;
|
|
11476
|
-
}
|
|
11477
|
-
};
|
|
11478
|
-
}
|
|
11479
|
-
function mixEventSeed(eventSeed) {
|
|
11480
|
-
let mixed = Math.imul((eventSeed | 0) ^ HASH_MIX, 2246822507);
|
|
11481
|
-
mixed ^= mixed >>> 13;
|
|
11482
|
-
mixed = Math.imul(mixed, 3266489909);
|
|
11483
|
-
mixed ^= mixed >>> 16;
|
|
11484
|
-
return (mixed >>> 0) % (LEHMER_MODULUS - 1) + 1;
|
|
11485
|
-
}
|
|
11486
|
-
function streamFor2(eventSeed) {
|
|
11487
|
-
return lehmer(mixEventSeed(eventSeed));
|
|
11488
|
-
}
|
|
11489
11697
|
var TABLE = {
|
|
11490
11698
|
concrete: { dust: 9078138, chip: 7236195, spark: 2 },
|
|
11491
11699
|
metal: { dust: 0, chip: 0, spark: 18 },
|
|
@@ -12588,12 +12796,12 @@ var GameTestRoom = (() => {
|
|
|
12588
12796
|
}
|
|
12589
12797
|
function drawing(entry, action) {
|
|
12590
12798
|
const context = engine.context;
|
|
12591
|
-
const
|
|
12799
|
+
const shared2 = context.random;
|
|
12592
12800
|
if (entry.random) context.random = entry.random;
|
|
12593
12801
|
try {
|
|
12594
12802
|
action();
|
|
12595
12803
|
} finally {
|
|
12596
|
-
context.random =
|
|
12804
|
+
context.random = shared2;
|
|
12597
12805
|
}
|
|
12598
12806
|
}
|
|
12599
12807
|
return {
|
|
@@ -12789,8 +12997,8 @@ var GameTestRoom = (() => {
|
|
|
12789
12997
|
function addScorch(store, random, x, z, radius) {
|
|
12790
12998
|
const variant = Math.floor(random.next() * SCORCH_VARIANTS);
|
|
12791
12999
|
const lift = 0.03 + nextLift(store) * 1e-3;
|
|
12792
|
-
const
|
|
12793
|
-
store.add({ kind: "scorch", x, z, radius, variant, lift, rotation });
|
|
13000
|
+
const rotation2 = random.next() * 6;
|
|
13001
|
+
store.add({ kind: "scorch", x, z, radius, variant, lift, rotation: rotation2 });
|
|
12794
13002
|
}
|
|
12795
13003
|
function addRimRocks(store, ground, random, x, z, radius) {
|
|
12796
13004
|
const count = Math.round(6 + radius * 7);
|
|
@@ -12819,8 +13027,8 @@ var GameTestRoom = (() => {
|
|
|
12819
13027
|
function addCrater(store, ground, random, spec) {
|
|
12820
13028
|
ground?.dent(random, spec.x, spec.z, spec.radius, spec.depth);
|
|
12821
13029
|
if (!spec.marks) return;
|
|
12822
|
-
const
|
|
12823
|
-
store.add({ kind: "dirt", x: spec.x, z: spec.z, radius: spec.radius * 1.02, lift: 0.045, rotation });
|
|
13030
|
+
const rotation2 = random.next() * 6;
|
|
13031
|
+
store.add({ kind: "dirt", x: spec.x, z: spec.z, radius: spec.radius * 1.02, lift: 0.045, rotation: rotation2 });
|
|
12824
13032
|
addRimRocks(store, ground, random, spec.x, spec.z, spec.radius);
|
|
12825
13033
|
}
|
|
12826
13034
|
function addBloodSplat(store, ground, random, spec) {
|
|
@@ -13376,6 +13584,7 @@ var GameTestRoom = (() => {
|
|
|
13376
13584
|
state.gas = Math.max(0, state.gas - dt / DECAY.gasSeconds);
|
|
13377
13585
|
state.beat *= Math.exp(-DECAY.beat * dt);
|
|
13378
13586
|
}
|
|
13587
|
+
var PAD_OF_SIZE2 = 0.35;
|
|
13379
13588
|
var clamp4 = (v, lo, hi) => v < lo ? lo : v > hi ? hi : v;
|
|
13380
13589
|
var lerp4 = (a, b, t) => a + (b - a) * t;
|
|
13381
13590
|
function rgb(hex) {
|
|
@@ -13535,9 +13744,20 @@ var GameTestRoom = (() => {
|
|
|
13535
13744
|
vy2 *= k;
|
|
13536
13745
|
vz2 *= k;
|
|
13537
13746
|
}
|
|
13538
|
-
|
|
13747
|
+
let x = this.position[i3] + vx2 * dt;
|
|
13539
13748
|
let y = this.position[i3 + 1] + vy2 * dt;
|
|
13540
|
-
|
|
13749
|
+
let z = this.position[i3 + 2] + vz2 * dt;
|
|
13750
|
+
const confiner = host.confiner;
|
|
13751
|
+
if (def.carried && confiner && !confiner.empty) {
|
|
13752
|
+
const pad2 = this.size0[i] * lerp4(1, def.grow, t) * PAD_OF_SIZE2;
|
|
13753
|
+
if (confiner.confine(this.position[i3], this.position[i3 + 1], this.position[i3 + 2], x, y, z, pad2, dt)) {
|
|
13754
|
+
const out = confiner.out;
|
|
13755
|
+
x = out.x;
|
|
13756
|
+
y = out.y;
|
|
13757
|
+
z = out.z;
|
|
13758
|
+
[vx2, vy2, vz2] = slideAlong(out, vx2, vy2, vz2);
|
|
13759
|
+
}
|
|
13760
|
+
}
|
|
13541
13761
|
if (def.ground !== "none") {
|
|
13542
13762
|
const own = this.floor[i];
|
|
13543
13763
|
const gy = Number.isNaN(own) ? host.groundAt(x, z) + 5e-3 : own;
|
|
@@ -13623,7 +13843,8 @@ var GameTestRoom = (() => {
|
|
|
13623
13843
|
alpha: 0.35,
|
|
13624
13844
|
fadeIn: 0.15,
|
|
13625
13845
|
cone: 0.6,
|
|
13626
|
-
ground: "none"
|
|
13846
|
+
ground: "none",
|
|
13847
|
+
carried: true
|
|
13627
13848
|
},
|
|
13628
13849
|
sparks: {
|
|
13629
13850
|
id: "sparks",
|
|
@@ -13667,7 +13888,8 @@ var GameTestRoom = (() => {
|
|
|
13667
13888
|
alpha: 0.4,
|
|
13668
13889
|
fadeIn: 0.1,
|
|
13669
13890
|
cone: 0.4,
|
|
13670
|
-
ground: "none"
|
|
13891
|
+
ground: "none",
|
|
13892
|
+
carried: true
|
|
13671
13893
|
},
|
|
13672
13894
|
shards: {
|
|
13673
13895
|
id: "shards",
|
|
@@ -13825,7 +14047,8 @@ var GameTestRoom = (() => {
|
|
|
13825
14047
|
fadeIn: 0.1,
|
|
13826
14048
|
cone: 0.5,
|
|
13827
14049
|
ground: "stop",
|
|
13828
|
-
flutter: 0.6
|
|
14050
|
+
flutter: 0.6,
|
|
14051
|
+
carried: true
|
|
13829
14052
|
},
|
|
13830
14053
|
steam: {
|
|
13831
14054
|
id: "steam",
|
|
@@ -13847,7 +14070,8 @@ var GameTestRoom = (() => {
|
|
|
13847
14070
|
alpha: 0.35,
|
|
13848
14071
|
fadeIn: 0.15,
|
|
13849
14072
|
cone: 0.6,
|
|
13850
|
-
ground: "none"
|
|
14073
|
+
ground: "none",
|
|
14074
|
+
carried: true
|
|
13851
14075
|
},
|
|
13852
14076
|
flash: {
|
|
13853
14077
|
id: "flash",
|
|
@@ -13988,7 +14212,8 @@ var GameTestRoom = (() => {
|
|
|
13988
14212
|
const host = {
|
|
13989
14213
|
groundAt: this.options.groundAt,
|
|
13990
14214
|
gravity: this.options.gravity,
|
|
13991
|
-
land: (owner, x, y, z, color, tag) => this.listeners.get(owner)?.(x, y, z, color, tag)
|
|
14215
|
+
land: (owner, x, y, z, color, tag) => this.listeners.get(owner)?.(x, y, z, color, tag),
|
|
14216
|
+
...this.options.confiner ? { confiner: this.options.confiner } : {}
|
|
13992
14217
|
};
|
|
13993
14218
|
if (this.additive.live > 0 || this.additive.drawCount > 0) this.additive.update(dt, host);
|
|
13994
14219
|
if (this.normal.live > 0 || this.normal.drawCount > 0) this.normal.update(dt, host);
|
|
@@ -14194,8 +14419,8 @@ var GameTestRoom = (() => {
|
|
|
14194
14419
|
* Takes away the marks inside a box: world `center`, `half` extents along the axes of the world `rotation` (a quaternion, x y z w; none means the
|
|
14195
14420
|
* world axes). The surface they were on is gone (a brick came out of a wall with its bullet holes). Returns how many went.
|
|
14196
14421
|
*/
|
|
14197
|
-
clearInside(center, half,
|
|
14198
|
-
const qx = -
|
|
14422
|
+
clearInside(center, half, rotation2 = [0, 0, 0, 1]) {
|
|
14423
|
+
const qx = -rotation2[0], qy = -rotation2[1], qz = -rotation2[2], qw = rotation2[3];
|
|
14199
14424
|
let gone = 0;
|
|
14200
14425
|
for (const decal2 of this.decals) {
|
|
14201
14426
|
if (!decal2.on) continue;
|
|
@@ -14316,10 +14541,14 @@ var GameTestRoom = (() => {
|
|
|
14316
14541
|
var DEFAULT_FADE_IN = 0.1;
|
|
14317
14542
|
var FLOATS_PER_VECTOR = 3;
|
|
14318
14543
|
var BYTE_MAX2 = 255;
|
|
14544
|
+
var CARRIED_GRAVITY = 3;
|
|
14545
|
+
var PAD_OF_SIZE3 = 0.35;
|
|
14319
14546
|
var SpritePool = class {
|
|
14320
|
-
|
|
14547
|
+
/** `carried`: the normal-blend pool (smoke, dust, steam), whose light sprites go round the closed spaces; the additive one (flames, sparks) does not. */
|
|
14548
|
+
constructor(capacity, context, carried = false) {
|
|
14321
14549
|
__publicField(this, "capacity", capacity);
|
|
14322
14550
|
__publicField(this, "context", context);
|
|
14551
|
+
__publicField(this, "carried", carried);
|
|
14323
14552
|
__publicField(this, "count", 0);
|
|
14324
14553
|
__publicField(this, "position");
|
|
14325
14554
|
__publicField(this, "velocity");
|
|
@@ -14419,6 +14648,7 @@ var GameTestRoom = (() => {
|
|
|
14419
14648
|
}
|
|
14420
14649
|
update(dt, leaveDecal) {
|
|
14421
14650
|
const { position, velocity } = this;
|
|
14651
|
+
const confiner = this.context.confiner;
|
|
14422
14652
|
for (let index = this.count - 1; index >= 0; index--) {
|
|
14423
14653
|
this.life[index] -= dt;
|
|
14424
14654
|
if (this.life[index] <= 0) {
|
|
@@ -14432,9 +14662,25 @@ var GameTestRoom = (() => {
|
|
|
14432
14662
|
velocity[offset] *= factor;
|
|
14433
14663
|
velocity[offset + 1] *= factor;
|
|
14434
14664
|
velocity[offset + 2] *= factor;
|
|
14665
|
+
const x0 = position[offset];
|
|
14666
|
+
const y0 = position[offset + 1];
|
|
14667
|
+
const z0 = position[offset + 2];
|
|
14435
14668
|
position[offset] += velocity[offset] * dt;
|
|
14436
14669
|
position[offset + 1] += velocity[offset + 1] * dt;
|
|
14437
14670
|
position[offset + 2] += velocity[offset + 2] * dt;
|
|
14671
|
+
if (this.carried && confiner && !confiner.empty && Math.abs(this.gravity[index]) < CARRIED_GRAVITY) {
|
|
14672
|
+
const size = this.startSize[index] * (1 + (this.growth[index] - 1) * age);
|
|
14673
|
+
if (confiner.confine(x0, y0, z0, position[offset], position[offset + 1], position[offset + 2], size * PAD_OF_SIZE3, dt)) {
|
|
14674
|
+
const out = confiner.out;
|
|
14675
|
+
position[offset] = out.x;
|
|
14676
|
+
position[offset + 1] = out.y;
|
|
14677
|
+
position[offset + 2] = out.z;
|
|
14678
|
+
const [vx2, vy2, vz2] = slideAlong(out, velocity[offset], velocity[offset + 1], velocity[offset + 2]);
|
|
14679
|
+
velocity[offset] = vx2;
|
|
14680
|
+
velocity[offset + 1] = vy2;
|
|
14681
|
+
velocity[offset + 2] = vz2;
|
|
14682
|
+
}
|
|
14683
|
+
}
|
|
14438
14684
|
const mode = this.groundMode[index];
|
|
14439
14685
|
if (mode) {
|
|
14440
14686
|
const groundHeight = this.context.groundAt(position[offset], position[offset + 2]);
|
|
@@ -14711,9 +14957,9 @@ var GameTestRoom = (() => {
|
|
|
14711
14957
|
__publicField(this, "placement");
|
|
14712
14958
|
__publicField(this, "accumulators", /* @__PURE__ */ new Map());
|
|
14713
14959
|
const profile = options.profile ?? PROFILES.high;
|
|
14714
|
-
this.context = { random: options.random, groundAt: options.groundAt ?? workshopGround, quality: { level: 0, mult: 1 }, trace: options.trace };
|
|
14960
|
+
this.context = { random: options.random, groundAt: options.groundAt ?? workshopGround, quality: { level: 0, mult: 1 }, trace: options.trace, ...options.confiner ? { confiner: options.confiner } : {} };
|
|
14715
14961
|
this.add = new SpritePool(profile.sprites.add, this.context);
|
|
14716
|
-
this.normal = new SpritePool(profile.sprites.normal, this.context);
|
|
14962
|
+
this.normal = new SpritePool(profile.sprites.normal, this.context, true);
|
|
14717
14963
|
this.streaks = new StreakPool(profile.streaks, this.context);
|
|
14718
14964
|
this.debris = new DebrisPool(this.context);
|
|
14719
14965
|
this.decals = new DecalPool(this.context);
|
|
@@ -14901,12 +15147,14 @@ var GameTestRoom = (() => {
|
|
|
14901
15147
|
const groundAt = options.groundAt ?? (ground ? (x, z) => ground.heightAt(x, z) : () => 0);
|
|
14902
15148
|
const handles = { next: 0, events: 0 };
|
|
14903
15149
|
const low = options.profile === "low";
|
|
15150
|
+
const enclosures = new Enclosures(20973 + (options.seed ?? 0));
|
|
14904
15151
|
const spriteSystem = new SpriteKindSystem({
|
|
14905
15152
|
capacity: options.sprites?.capacity ?? (low ? 1250 : 2500),
|
|
14906
15153
|
density: options.sprites?.density ?? (low ? 0.6 : 1),
|
|
14907
15154
|
seed: 2654435761 + (options.seed ?? 0),
|
|
14908
15155
|
groundAt,
|
|
14909
15156
|
gravity: options.gravity ?? DEFAULT_GRAVITY,
|
|
15157
|
+
confiner: enclosures,
|
|
14910
15158
|
...options.sprites?.kinds ? { kinds: options.sprites.kinds } : {}
|
|
14911
15159
|
});
|
|
14912
15160
|
const core = {
|
|
@@ -14956,7 +15204,7 @@ var GameTestRoom = (() => {
|
|
|
14956
15204
|
return [camera2.x, camera2.y, camera2.z];
|
|
14957
15205
|
}, forward: (local2) => [local2[0] ?? 0, local2[1] ?? 0, local2[2] ?? 0] };
|
|
14958
15206
|
function workshop() {
|
|
14959
|
-
return engine ?? (engine = new WorkshopEngine({ random: sharedRandom, profile, groundAt }));
|
|
15207
|
+
return engine ?? (engine = new WorkshopEngine({ random: sharedRandom, profile, groundAt, confiner: enclosures }));
|
|
14960
15208
|
}
|
|
14961
15209
|
function effectPlayer() {
|
|
14962
15210
|
return player ?? (player = createEffectPlayer({ engine: workshop(), effects, view }));
|
|
@@ -15015,6 +15263,10 @@ var GameTestRoom = (() => {
|
|
|
15015
15263
|
puff3.vz += dz * strength;
|
|
15016
15264
|
}
|
|
15017
15265
|
},
|
|
15266
|
+
enclose(id, enclosure) {
|
|
15267
|
+
enclosures.set(id, enclosure);
|
|
15268
|
+
},
|
|
15269
|
+
enclosures: () => enclosures,
|
|
15018
15270
|
stop(handle) {
|
|
15019
15271
|
player?.stop(handle);
|
|
15020
15272
|
const fires = core.fires;
|
|
@@ -15042,7 +15294,7 @@ var GameTestRoom = (() => {
|
|
|
15042
15294
|
core.clock.time += dt;
|
|
15043
15295
|
core.schedule.update(core.clock.time);
|
|
15044
15296
|
updateRings(core.rings, dt);
|
|
15045
|
-
updatePuffs(core.puffs, dt, wind);
|
|
15297
|
+
updatePuffs(core.puffs, dt, wind, enclosures);
|
|
15046
15298
|
updateSparks(core.sparks, { dt, groundAt });
|
|
15047
15299
|
updateGlows(core.glows, dt);
|
|
15048
15300
|
updateShocks(core.shocks, core.puffs.items, dt);
|
|
@@ -16442,6 +16694,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
16442
16694
|
});
|
|
16443
16695
|
},
|
|
16444
16696
|
stop: (handle) => world.stop(handle),
|
|
16697
|
+
// a module's closed space (a shut car's cabin): the world's smoke, dust and steam go round it
|
|
16698
|
+
enclose: (id, enclosure) => world.enclose(id, enclosure),
|
|
16445
16699
|
configure(settings) {
|
|
16446
16700
|
const band = settings.lod_band;
|
|
16447
16701
|
if (typeof band === "string" && band in LOD_BANDS) world.forceLod(LOD_BANDS[band] ?? null);
|
|
@@ -18372,8 +18626,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
18372
18626
|
* Takes away the decals of a mesh that sit inside a box (world `center`, `half` extents along the axes of the world `rotation`): the surface they
|
|
18373
18627
|
* marked is gone (a unit came out of the wall with its bullet holes and spalls).
|
|
18374
18628
|
*/
|
|
18375
|
-
clearDecals(mv, center, half,
|
|
18376
|
-
const inv =
|
|
18629
|
+
clearDecals(mv, center, half, rotation2) {
|
|
18630
|
+
const inv = rotation2.clone().invert();
|
|
18377
18631
|
const p = new this.THREE.Vector3();
|
|
18378
18632
|
for (let i = mv.decals.length - 1; i >= 0; i--) {
|
|
18379
18633
|
const d = mv.decals[i];
|
|
@@ -19803,8 +20057,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
19803
20057
|
const T = this.THREE;
|
|
19804
20058
|
const center = new T.Vector3(ev.center[0], ev.center[1], ev.center[2]);
|
|
19805
20059
|
const half = new T.Vector3(ev.size[0] / 2 + CHIP_DECAL_EDGE, ev.size[1] / 2 + CHIP_DECAL_EDGE, ev.size[2] / 2 + CHIP_DECAL_EDGE);
|
|
19806
|
-
const
|
|
19807
|
-
for (const part of this.bounds.get(ev.object)?.parts.values() ?? []) for (const mv of part.meshes) this.visuals.clearDecals(mv, center, half,
|
|
20060
|
+
const rotation2 = new T.Quaternion(ev.rotation[0], ev.rotation[1], ev.rotation[2], ev.rotation[3]);
|
|
20061
|
+
for (const part of this.bounds.get(ev.object)?.parts.values() ?? []) for (const mv of part.meshes) this.visuals.clearDecals(mv, center, half, rotation2);
|
|
19808
20062
|
this.vfx.peekWorkshop()?.decals.clearInside(ev.center, [half.x, half.y, half.z], ev.rotation);
|
|
19809
20063
|
this.vfx.burst("dust", ev.center, [0, 1, 0], 8, 0.8, { color });
|
|
19810
20064
|
this.sound(impactKey(def), ev.center, 0.7);
|
|
@@ -36122,11 +36376,11 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
36122
36376
|
for (const key2 of Object.keys(c.streams)) endStreamKey(c, key2);
|
|
36123
36377
|
containers.delete(id);
|
|
36124
36378
|
},
|
|
36125
|
-
setTransform(id, position,
|
|
36379
|
+
setTransform(id, position, rotation2, velocity) {
|
|
36126
36380
|
const c = containers.get(id);
|
|
36127
36381
|
if (!c) return;
|
|
36128
36382
|
c.position = copy3(position);
|
|
36129
|
-
c.rotation = [...
|
|
36383
|
+
c.rotation = [...rotation2];
|
|
36130
36384
|
if (velocity) c.velocity = copy3(velocity);
|
|
36131
36385
|
refreshLevel(c);
|
|
36132
36386
|
},
|
|
@@ -37048,10 +37302,10 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
37048
37302
|
const hand = getHandTransform();
|
|
37049
37303
|
const p = pose();
|
|
37050
37304
|
const position = add2(hand.position, quatRotate(hand.rotation, p.position));
|
|
37051
|
-
const
|
|
37305
|
+
const rotation2 = quatMultiply(hand.rotation, quatFromEuler2(p.rotation[0], p.rotation[1], p.rotation[2]));
|
|
37052
37306
|
const velocity = lastPos && dt > 0 ? [(position[0] - lastPos[0]) / dt, (position[1] - lastPos[1]) / dt, (position[2] - lastPos[2]) / dt] : void 0;
|
|
37053
37307
|
lastPos = position;
|
|
37054
|
-
world.setTransform(containerId, position,
|
|
37308
|
+
world.setTransform(containerId, position, rotation2, velocity);
|
|
37055
37309
|
};
|
|
37056
37310
|
const player = {
|
|
37057
37311
|
def,
|
|
@@ -39080,7 +39334,7 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
39080
39334
|
const direction = new THREE.Vector3();
|
|
39081
39335
|
const location = new THREE.Vector3();
|
|
39082
39336
|
const scale2 = new THREE.Vector3();
|
|
39083
|
-
const
|
|
39337
|
+
const rotation2 = new THREE.Quaternion();
|
|
39084
39338
|
const matrix = new THREE.Matrix4();
|
|
39085
39339
|
return {
|
|
39086
39340
|
drops,
|
|
@@ -39100,9 +39354,9 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
39100
39354
|
const o = i * 3;
|
|
39101
39355
|
const speed = Math.hypot(velocity[o], velocity[o + 1], velocity[o + 2]);
|
|
39102
39356
|
direction.set(velocity[o], velocity[o + 1], velocity[o + 2]).normalize();
|
|
39103
|
-
|
|
39357
|
+
rotation2.setFromUnitVectors(up, direction);
|
|
39104
39358
|
const size = radius[i] * METRES_PER_MM;
|
|
39105
|
-
matrix.compose(location.set(position[o], position[o + 1], position[o + 2]),
|
|
39359
|
+
matrix.compose(location.set(position[o], position[o + 1], position[o + 2]), rotation2, scale2.set(size, size * (1 + Math.min(MAX_STRETCH, speed * STRETCH_PER_SPEED)), size));
|
|
39106
39360
|
drops.setMatrixAt(i, matrix);
|
|
39107
39361
|
drawn++;
|
|
39108
39362
|
}
|
|
@@ -40280,6 +40534,81 @@ void main(){
|
|
|
40280
40534
|
return root;
|
|
40281
40535
|
}
|
|
40282
40536
|
|
|
40537
|
+
// ../game-shapes-three/dist/index.js
|
|
40538
|
+
var isTexture = (v) => !!v && typeof v === "object" && v.isTexture === true;
|
|
40539
|
+
function texturesOf(material, out) {
|
|
40540
|
+
for (const value of Object.values(material)) if (isTexture(value)) out.add(value);
|
|
40541
|
+
const uniforms = material.uniforms;
|
|
40542
|
+
if (uniforms) {
|
|
40543
|
+
for (const u of Object.values(uniforms)) if (isTexture(u?.value)) out.add(u.value);
|
|
40544
|
+
}
|
|
40545
|
+
}
|
|
40546
|
+
function collect(roots) {
|
|
40547
|
+
const geometries = /* @__PURE__ */ new Set();
|
|
40548
|
+
const materials = /* @__PURE__ */ new Set();
|
|
40549
|
+
const textures = /* @__PURE__ */ new Set();
|
|
40550
|
+
const skeletons = /* @__PURE__ */ new Set();
|
|
40551
|
+
for (const root of roots) {
|
|
40552
|
+
root.traverse((object) => {
|
|
40553
|
+
const o = object;
|
|
40554
|
+
if (o.geometry && typeof o.geometry.dispose === "function") geometries.add(o.geometry);
|
|
40555
|
+
if (o.skeleton && typeof o.skeleton.dispose === "function") skeletons.add(o.skeleton);
|
|
40556
|
+
const list = Array.isArray(o.material) ? o.material : o.material ? [o.material] : [];
|
|
40557
|
+
for (const m of list) {
|
|
40558
|
+
if (!m || typeof m.dispose !== "function") continue;
|
|
40559
|
+
materials.add(m);
|
|
40560
|
+
texturesOf(m, textures);
|
|
40561
|
+
}
|
|
40562
|
+
});
|
|
40563
|
+
}
|
|
40564
|
+
return { geometries, materials, textures, skeletons };
|
|
40565
|
+
}
|
|
40566
|
+
var marked = /* @__PURE__ */ new WeakSet();
|
|
40567
|
+
var shared = (r) => r.userData?.shared === true || marked.has(r);
|
|
40568
|
+
function releaseObject3D(roots, options = {}) {
|
|
40569
|
+
const list = Array.isArray(roots) ? roots : [roots];
|
|
40570
|
+
const report = { geometries: 0, materials: 0, textures: 0 };
|
|
40571
|
+
if (list.length === 0) return report;
|
|
40572
|
+
const found = collect(list);
|
|
40573
|
+
const keepRoots = options.keep === void 0 ? [] : Array.isArray(options.keep) ? options.keep : [options.keep];
|
|
40574
|
+
const releasing = new Set(list);
|
|
40575
|
+
for (const keep of keepRoots) {
|
|
40576
|
+
const walk = (o) => {
|
|
40577
|
+
if (releasing.has(o)) return;
|
|
40578
|
+
const owner = o;
|
|
40579
|
+
if (owner.geometry) found.geometries.delete(owner.geometry);
|
|
40580
|
+
if (owner.skeleton) found.skeletons.delete(owner.skeleton);
|
|
40581
|
+
const mats = Array.isArray(owner.material) ? owner.material : owner.material ? [owner.material] : [];
|
|
40582
|
+
for (const m of mats) {
|
|
40583
|
+
if (!m) continue;
|
|
40584
|
+
found.materials.delete(m);
|
|
40585
|
+
const t = /* @__PURE__ */ new Set();
|
|
40586
|
+
texturesOf(m, t);
|
|
40587
|
+
for (const x of t) found.textures.delete(x);
|
|
40588
|
+
}
|
|
40589
|
+
for (const c of o.children) walk(c);
|
|
40590
|
+
};
|
|
40591
|
+
walk(keep);
|
|
40592
|
+
}
|
|
40593
|
+
for (const g of found.geometries) {
|
|
40594
|
+
if (shared(g)) continue;
|
|
40595
|
+
g.dispose();
|
|
40596
|
+
report.geometries++;
|
|
40597
|
+
}
|
|
40598
|
+
for (const m of found.materials) {
|
|
40599
|
+
if (shared(m)) continue;
|
|
40600
|
+
m.dispose();
|
|
40601
|
+
report.materials++;
|
|
40602
|
+
}
|
|
40603
|
+
for (const t of found.textures) {
|
|
40604
|
+
if (shared(t)) continue;
|
|
40605
|
+
t.dispose();
|
|
40606
|
+
report.textures++;
|
|
40607
|
+
}
|
|
40608
|
+
for (const s of found.skeletons) s.dispose();
|
|
40609
|
+
return report;
|
|
40610
|
+
}
|
|
40611
|
+
|
|
40283
40612
|
// src/segment-box.ts
|
|
40284
40613
|
var segmentTouchesBox = (from, to, min2, max2) => {
|
|
40285
40614
|
let near = 0;
|
|
@@ -40320,9 +40649,13 @@ void main(){
|
|
|
40320
40649
|
const projectiles = [];
|
|
40321
40650
|
const meshes = [];
|
|
40322
40651
|
const up = new THREE.Vector3(0, 1, 0);
|
|
40652
|
+
const drop = (objects) => {
|
|
40653
|
+
for (const object of objects) object.removeFromParent();
|
|
40654
|
+
releaseObject3D(objects, { keep: scene2 });
|
|
40655
|
+
};
|
|
40323
40656
|
const clear = () => {
|
|
40324
40657
|
projectiles.length = 0;
|
|
40325
|
-
|
|
40658
|
+
drop(meshes);
|
|
40326
40659
|
meshes.length = 0;
|
|
40327
40660
|
};
|
|
40328
40661
|
const addMesh = (geometry, color, metalness, at3) => {
|
|
@@ -40346,13 +40679,12 @@ void main(){
|
|
|
40346
40679
|
};
|
|
40347
40680
|
const remove = (projectile) => {
|
|
40348
40681
|
for (const extra of projectile.attached ?? []) {
|
|
40349
|
-
extra.removeFromParent();
|
|
40350
40682
|
const extraAt = meshes.indexOf(extra);
|
|
40351
40683
|
if (extraAt >= 0) meshes.splice(extraAt, 1);
|
|
40352
40684
|
}
|
|
40353
|
-
projectile.mesh.removeFromParent();
|
|
40354
40685
|
const meshAt = meshes.indexOf(projectile.mesh);
|
|
40355
40686
|
if (meshAt >= 0) meshes.splice(meshAt, 1);
|
|
40687
|
+
drop([...projectile.attached ?? [], projectile.mesh]);
|
|
40356
40688
|
const at3 = projectiles.indexOf(projectile);
|
|
40357
40689
|
if (at3 >= 0) projectiles.splice(at3, 1);
|
|
40358
40690
|
};
|
|
@@ -42566,7 +42898,7 @@ void main(){
|
|
|
42566
42898
|
var NEAR_OPEN_LEAF = 0.9;
|
|
42567
42899
|
var BODY_HEIGHT = 1.8;
|
|
42568
42900
|
var HAND_REST = [0.22, -0.42, -0.32];
|
|
42569
|
-
var
|
|
42901
|
+
var SKIN2 = 0.01;
|
|
42570
42902
|
var HANDLE_INSET = 0.06;
|
|
42571
42903
|
var STANDOFF2 = 0.55;
|
|
42572
42904
|
var DRAWER_TRAVEL = 0.3;
|
|
@@ -42710,7 +43042,7 @@ void main(){
|
|
|
42710
43042
|
const o = outs[0];
|
|
42711
43043
|
return [o[1] * (o[0] + PLAYER_RADIUS), o[2] * (o[0] + PLAYER_RADIUS)];
|
|
42712
43044
|
}
|
|
42713
|
-
const push = PLAYER_RADIUS - d +
|
|
43045
|
+
const push = PLAYER_RADIUS - d + SKIN2;
|
|
42714
43046
|
return [dx / d * push, dz / d * push];
|
|
42715
43047
|
};
|
|
42716
43048
|
const isFree = (u, from, to) => {
|
|
@@ -42720,7 +43052,7 @@ void main(){
|
|
|
42720
43052
|
options.pose(objectId, leaf2.part, leaf2.clip, to);
|
|
42721
43053
|
obj.updateMatrixWorld(true);
|
|
42722
43054
|
box2.setFromObject(obj);
|
|
42723
|
-
box2.expandByScalar(-
|
|
43055
|
+
box2.expandByScalar(-SKIN2);
|
|
42724
43056
|
let by = null;
|
|
42725
43057
|
if (Math.max(Math.abs(box2.min.x), Math.abs(box2.max.x), Math.abs(box2.min.z), Math.abs(box2.max.z)) > arena.limit) by = "wall";
|
|
42726
43058
|
else
|
|
@@ -42738,7 +43070,7 @@ void main(){
|
|
|
42738
43070
|
const dir = [tmp.x - centre.x, tmp.y - centre.y, tmp.z - centre.z];
|
|
42739
43071
|
const len = Math.hypot(dir[0], dir[1], dir[2]);
|
|
42740
43072
|
if (len > 1e-5) {
|
|
42741
|
-
const hit = world.sweepBox({ min: [before.min.x +
|
|
43073
|
+
const hit = world.sweepBox({ min: [before.min.x + SKIN2, before.min.y + FLOOR_GAP, before.min.z + SKIN2], max: [before.max.x - SKIN2, before.max.y - SKIN2, before.max.z - SKIN2] }, dir, len * 2, { ignore: objectId, spacing: 0.12 });
|
|
42742
43074
|
if (hit && hit.normal[1] < 0.7) by = hit.object;
|
|
42743
43075
|
}
|
|
42744
43076
|
}
|
|
@@ -43026,6 +43358,7 @@ void main(){
|
|
|
43026
43358
|
debris: "chips",
|
|
43027
43359
|
color: [0.05, 0.05, 0.055],
|
|
43028
43360
|
pattern: "asphalt",
|
|
43361
|
+
crack: { reach: 0.6, width: 8e-3, thresholdJoules: 800 },
|
|
43029
43362
|
hits: {
|
|
43030
43363
|
ballistic: { specificEnergy: 3e7, aspect: 0.2, minRadius: 0.03 },
|
|
43031
43364
|
blunt: { specificEnergy: 1e8, aspect: 0.1, thresholdJoules: 400 },
|
|
@@ -43039,6 +43372,8 @@ void main(){
|
|
|
43039
43372
|
debris: "chips",
|
|
43040
43373
|
color: [0.33, 0.33, 0.31],
|
|
43041
43374
|
pattern: "concrete",
|
|
43375
|
+
crack: { reach: 1, width: 6e-3, thresholdJoules: 300 },
|
|
43376
|
+
breach: { joulesPerCubedThickness: 24e8, radiusOverThickness: 1.5 },
|
|
43042
43377
|
hits: {
|
|
43043
43378
|
ballistic: { specificEnergy: 15e7, aspect: 0.14, minRadius: 0.018 },
|
|
43044
43379
|
blunt: { specificEnergy: 3e8, aspect: 0.08, thresholdJoules: 800 },
|
|
@@ -43065,6 +43400,7 @@ void main(){
|
|
|
43065
43400
|
debris: "shards",
|
|
43066
43401
|
color: [0.72, 0.7, 0.66],
|
|
43067
43402
|
pattern: "tile",
|
|
43403
|
+
crack: { reach: 0.5, width: 2e-3, thresholdJoules: 40 },
|
|
43068
43404
|
hits: {
|
|
43069
43405
|
ballistic: { specificEnergy: 8e6, aspect: 0.1, minRadius: 0.05 },
|
|
43070
43406
|
blunt: { specificEnergy: 1e7, aspect: 0.08, thresholdJoules: 80, minRadius: 0.06 },
|
|
@@ -43091,6 +43427,7 @@ void main(){
|
|
|
43091
43427
|
debris: "chips",
|
|
43092
43428
|
color: [0.23, 0.22, 0.2],
|
|
43093
43429
|
pattern: "stone",
|
|
43430
|
+
crack: { reach: 0.5, width: 4e-3, thresholdJoules: 1e3 },
|
|
43094
43431
|
hits: {
|
|
43095
43432
|
ballistic: { specificEnergy: 25e7, aspect: 0.12, minRadius: 0.015 },
|
|
43096
43433
|
blunt: { specificEnergy: 5e8, aspect: 0.08, thresholdJoules: 1500 },
|
|
@@ -43113,6 +43450,91 @@ void main(){
|
|
|
43113
43450
|
];
|
|
43114
43451
|
var DEFAULT_BAR_YIELD_JOULES = 24e5;
|
|
43115
43452
|
var DEFAULT_PROFILE = "concrete_slab";
|
|
43453
|
+
function createRandom(seed) {
|
|
43454
|
+
let state = seed | 0;
|
|
43455
|
+
return () => {
|
|
43456
|
+
state = state + 1831565813 | 0;
|
|
43457
|
+
let mixed = Math.imul(state ^ state >>> 15, 1 | state);
|
|
43458
|
+
mixed = mixed + Math.imul(mixed ^ mixed >>> 7, 61 | mixed) ^ mixed;
|
|
43459
|
+
return ((mixed ^ mixed >>> 14) >>> 0) / 4294967296;
|
|
43460
|
+
};
|
|
43461
|
+
}
|
|
43462
|
+
var CRACK_REFERENCE_JOULES = 1e6;
|
|
43463
|
+
var MERGE_SHARE = 0.35;
|
|
43464
|
+
var HAIRLINE = 15e-4;
|
|
43465
|
+
var MIN_RAYS = 4;
|
|
43466
|
+
var MAX_RAYS = 11;
|
|
43467
|
+
var SEGMENTS2 = 4;
|
|
43468
|
+
var BRANCH_CHANCE = 0.45;
|
|
43469
|
+
function createCrackStore() {
|
|
43470
|
+
const list = [];
|
|
43471
|
+
let version = 0;
|
|
43472
|
+
let nextId = 1;
|
|
43473
|
+
let born = 0;
|
|
43474
|
+
return {
|
|
43475
|
+
list,
|
|
43476
|
+
get version() {
|
|
43477
|
+
return version;
|
|
43478
|
+
},
|
|
43479
|
+
add(spec, max2) {
|
|
43480
|
+
version++;
|
|
43481
|
+
const near = list.find((crack2) => Math.hypot(crack2.x - spec.x, crack2.z - spec.z) < crack2.reach * MERGE_SHARE);
|
|
43482
|
+
if (near) {
|
|
43483
|
+
near.reach = Math.max(near.reach, spec.reach) + Math.min(near.reach, spec.reach) * 0.25;
|
|
43484
|
+
near.width = Math.max(near.width, spec.width) * 1.1;
|
|
43485
|
+
near.rays = Math.min(MAX_RAYS, near.rays + 1);
|
|
43486
|
+
return near;
|
|
43487
|
+
}
|
|
43488
|
+
if (list.length >= max2) list.shift();
|
|
43489
|
+
const rays = MIN_RAYS + Math.floor(createRandom(spec.seed)() * (MAX_RAYS - MIN_RAYS - 2));
|
|
43490
|
+
const crack = { id: nextId++, x: spec.x, z: spec.z, reach: spec.reach, width: Math.max(HAIRLINE, spec.width), rays, seed: spec.seed, material: spec.material, born: born++ };
|
|
43491
|
+
list.push(crack);
|
|
43492
|
+
return crack;
|
|
43493
|
+
},
|
|
43494
|
+
clear() {
|
|
43495
|
+
list.length = 0;
|
|
43496
|
+
version++;
|
|
43497
|
+
},
|
|
43498
|
+
load(cracks) {
|
|
43499
|
+
list.length = 0;
|
|
43500
|
+
for (const crack of cracks) {
|
|
43501
|
+
list.push({ ...crack });
|
|
43502
|
+
nextId = Math.max(nextId, crack.id + 1);
|
|
43503
|
+
born = Math.max(born, crack.born + 1);
|
|
43504
|
+
}
|
|
43505
|
+
version++;
|
|
43506
|
+
}
|
|
43507
|
+
};
|
|
43508
|
+
}
|
|
43509
|
+
function crackLines(crack) {
|
|
43510
|
+
const random = createRandom(crack.seed);
|
|
43511
|
+
const segments = [];
|
|
43512
|
+
const widthAt = (distance4) => Math.max(HAIRLINE, crack.width * (1 - distance4 / crack.reach));
|
|
43513
|
+
for (let ray = 0; ray < crack.rays; ray++) {
|
|
43514
|
+
let angle = ray / crack.rays * Math.PI * 2 + (random() - 0.5) * 0.6;
|
|
43515
|
+
const length3 = crack.reach * (0.45 + 0.55 * random());
|
|
43516
|
+
let x = crack.x;
|
|
43517
|
+
let z = crack.z;
|
|
43518
|
+
let run = 0;
|
|
43519
|
+
for (let segment = 0; segment < SEGMENTS2; segment++) {
|
|
43520
|
+
const step = length3 / SEGMENTS2 * (0.75 + 0.5 * random());
|
|
43521
|
+
angle += (random() - 0.5) * 0.5;
|
|
43522
|
+
const nx = x + Math.cos(angle) * step;
|
|
43523
|
+
const nz = z + Math.sin(angle) * step;
|
|
43524
|
+
segments.push({ x0: x, z0: z, x1: nx, z1: nz, w0: widthAt(run), w1: widthAt(run + step) });
|
|
43525
|
+
if (segment > 0 && random() < BRANCH_CHANCE) {
|
|
43526
|
+
const side = angle + (random() < 0.5 ? -1 : 1) * (0.45 + random() * 0.5);
|
|
43527
|
+
const branch = step * (0.5 + 0.6 * random());
|
|
43528
|
+
const w = widthAt(run + step) * 0.6;
|
|
43529
|
+
segments.push({ x0: nx, z0: nz, x1: nx + Math.cos(side) * branch, z1: nz + Math.sin(side) * branch, w0: Math.max(HAIRLINE, w), w1: HAIRLINE });
|
|
43530
|
+
}
|
|
43531
|
+
run += step;
|
|
43532
|
+
x = nx;
|
|
43533
|
+
z = nz;
|
|
43534
|
+
}
|
|
43535
|
+
}
|
|
43536
|
+
return segments;
|
|
43537
|
+
}
|
|
43116
43538
|
var REST_SPEED2 = 0.6;
|
|
43117
43539
|
var RESTITUTION2 = 0.25;
|
|
43118
43540
|
var FRICTION = 0.55;
|
|
@@ -43290,15 +43712,6 @@ void main(){
|
|
|
43290
43712
|
}
|
|
43291
43713
|
};
|
|
43292
43714
|
}
|
|
43293
|
-
function createRandom(seed) {
|
|
43294
|
-
let state = seed | 0;
|
|
43295
|
-
return () => {
|
|
43296
|
-
state = state + 1831565813 | 0;
|
|
43297
|
-
let mixed = Math.imul(state ^ state >>> 15, 1 | state);
|
|
43298
|
-
mixed = mixed + Math.imul(mixed ^ mixed >>> 7, 61 | mixed) ^ mixed;
|
|
43299
|
-
return ((mixed ^ mixed >>> 14) >>> 0) / 4294967296;
|
|
43300
|
-
};
|
|
43301
|
-
}
|
|
43302
43715
|
var DEFAULT_TERRAIN_BUDGET = {
|
|
43303
43716
|
markAreaSize: 2,
|
|
43304
43717
|
maxMarksPerArea: 24,
|
|
@@ -43307,7 +43720,8 @@ void main(){
|
|
|
43307
43720
|
maxDebris: 400,
|
|
43308
43721
|
maxDebrisPerBlow: 36,
|
|
43309
43722
|
maxSlideCellsPerFrame: 2500,
|
|
43310
|
-
maxBurningCells: 300
|
|
43723
|
+
maxBurningCells: 300,
|
|
43724
|
+
maxCracks: 120
|
|
43311
43725
|
};
|
|
43312
43726
|
var GRAVITY5 = 9.81;
|
|
43313
43727
|
var FINE_CELLS = 1.5;
|
|
@@ -43384,6 +43798,7 @@ void main(){
|
|
|
43384
43798
|
const mixed = new Uint8Array(chunksX * chunksZ);
|
|
43385
43799
|
const dirty = /* @__PURE__ */ new Set();
|
|
43386
43800
|
const marks = createMarkStore2(budget);
|
|
43801
|
+
const cracks = createCrackStore();
|
|
43387
43802
|
const debrisStore = createDebrisStore(() => budget.maxDebris);
|
|
43388
43803
|
const sliding = /* @__PURE__ */ new Set();
|
|
43389
43804
|
const burning = /* @__PURE__ */ new Map();
|
|
@@ -43560,6 +43975,7 @@ void main(){
|
|
|
43560
43975
|
let depth = start.depth;
|
|
43561
43976
|
let radius = 0;
|
|
43562
43977
|
let carved = 0;
|
|
43978
|
+
let breached = false;
|
|
43563
43979
|
const firstMaterial = materials.get(start.material);
|
|
43564
43980
|
if (start.loose <= 0) {
|
|
43565
43981
|
for (; ; ) {
|
|
@@ -43571,6 +43987,19 @@ void main(){
|
|
|
43571
43987
|
const response = material.hits[blow3];
|
|
43572
43988
|
if (!response || energy < (response.thresholdJoules ?? 0)) break;
|
|
43573
43989
|
const bars = layer2.stratum.reinforcement;
|
|
43990
|
+
const breach = blow3 === "explosive" ? material.breach : void 0;
|
|
43991
|
+
const breachJoules = breach ? breach.joulesPerCubedThickness * layer2.stratum.thickness ** 3 : Infinity;
|
|
43992
|
+
if (breach && depth <= layer2.top + 1e-6 && energy >= breachJoules) {
|
|
43993
|
+
const takenRadius2 = layer2.stratum.thickness * breach.radiusOverThickness * Math.cbrt(energy / breachJoules);
|
|
43994
|
+
const takenVolume2 = Math.PI * takenRadius2 * takenRadius2 * room / 2;
|
|
43995
|
+
energy -= breachJoules;
|
|
43996
|
+
depth += room;
|
|
43997
|
+
carved += room;
|
|
43998
|
+
breached = true;
|
|
43999
|
+
radius = Math.max(radius, takenRadius2);
|
|
44000
|
+
removed.push({ material: material.id, volume: takenVolume2 });
|
|
44001
|
+
continue;
|
|
44002
|
+
}
|
|
43574
44003
|
const pastCover = bars !== void 0 && depth - layer2.top >= bars.cover - 1e-6;
|
|
43575
44004
|
const specificEnergy = response.specificEnergy * (pastCover ? bars.resistance : 1);
|
|
43576
44005
|
const limit = bars && !pastCover ? Math.min(room, layer2.top + bars.cover - depth) : room;
|
|
@@ -43598,8 +44027,10 @@ void main(){
|
|
|
43598
44027
|
removed.push({ material: firstMaterial.id, volume });
|
|
43599
44028
|
}
|
|
43600
44029
|
}
|
|
43601
|
-
|
|
43602
|
-
|
|
44030
|
+
let collapsed = loadBars(blow3, spec.energy, x, z, profile);
|
|
44031
|
+
const crack = crackAround(blow3, spec.energy, x, z, start.loose > 0 ? void 0 : firstMaterial);
|
|
44032
|
+
const extra = { ...crack ? { crack } : {}, ...breached ? { breached } : {} };
|
|
44033
|
+
if (radius <= 0) return { point, radius: 0, depth: 0, totalDepth: columnAt(x, z).depth, removed: [], exposed: start.material, atLimit: start.remaining <= 1e-6, rebarExposed: rebarShowing(profile, start.depth), collapsed, fine: true, ...extra };
|
|
43603
44034
|
if (firstMaterial.reposeDegrees === void 0 && start.loose <= 0) radius *= 1 + RIGID_WIDENING * (start.depth / maxDepthOfProfile(profile));
|
|
43604
44035
|
const volumeTotal = removed.reduce((sum2, entry) => sum2 + entry.volume, 0);
|
|
43605
44036
|
const fine = radius < cellSize * FINE_CELLS;
|
|
@@ -43617,8 +44048,16 @@ void main(){
|
|
|
43617
44048
|
throwPieces({ x, y: point[1], z, volume: thrown, material, energy: spec.energy * (entry.volume / volumeTotal), direction: spec.direction, quota: share, bowlRadius: radius, blow: blow3 });
|
|
43618
44049
|
quota -= share;
|
|
43619
44050
|
}
|
|
44051
|
+
if (breached) collapsed = loadBars(blow3, spec.energy, x, z, profile) || collapsed;
|
|
43620
44052
|
const after2 = columnAt(x, z);
|
|
43621
|
-
return { point, radius, depth: carved, totalDepth: after2.depth, removed, exposed: after2.material, atLimit: after2.remaining <= 1e-4, rebarExposed: rebarShowing(profile, after2.depth), collapsed, fine };
|
|
44053
|
+
return { point, radius, depth: carved, totalDepth: after2.depth, removed, exposed: after2.material, atLimit: after2.remaining <= 1e-4, rebarExposed: rebarShowing(profile, after2.depth), collapsed, fine, ...extra };
|
|
44054
|
+
}
|
|
44055
|
+
function crackAround(blow3, energy, x, z, material) {
|
|
44056
|
+
const response = material?.crack;
|
|
44057
|
+
if (!material || !response || energy < response.thresholdJoules) return void 0;
|
|
44058
|
+
if (blow3 === "slash") return void 0;
|
|
44059
|
+
const scale2 = Math.cbrt(energy / CRACK_REFERENCE_JOULES);
|
|
44060
|
+
return cracks.add({ x, z, reach: response.reach * scale2, width: response.width * scale2, material: material.id, seed: Math.floor(random() * 2 ** 31) }, budget.maxCracks);
|
|
43622
44061
|
}
|
|
43623
44062
|
function loadBars(blow3, energy, x, z, profile) {
|
|
43624
44063
|
const bars = profile.strata.find((stratum) => stratum.reinforcement);
|
|
@@ -43859,6 +44298,7 @@ void main(){
|
|
|
43859
44298
|
barBend.fill(0);
|
|
43860
44299
|
touched.fill(0);
|
|
43861
44300
|
marks.clear();
|
|
44301
|
+
cracks.clear();
|
|
43862
44302
|
debrisStore.clear();
|
|
43863
44303
|
sliding.clear();
|
|
43864
44304
|
burning.clear();
|
|
@@ -43910,6 +44350,9 @@ void main(){
|
|
|
43910
44350
|
updateSlides();
|
|
43911
44351
|
updateFire(dt);
|
|
43912
44352
|
},
|
|
44353
|
+
get dirtyChunkCount() {
|
|
44354
|
+
return dirty.size;
|
|
44355
|
+
},
|
|
43913
44356
|
drainDirtyChunks(max2 = budget.maxDirtyChunksPerFrame) {
|
|
43914
44357
|
const taken = [];
|
|
43915
44358
|
for (const index of dirty) {
|
|
@@ -43921,6 +44364,10 @@ void main(){
|
|
|
43921
44364
|
},
|
|
43922
44365
|
chunk,
|
|
43923
44366
|
marks: () => marks.list,
|
|
44367
|
+
cracks: () => cracks.list,
|
|
44368
|
+
get cracksVersion() {
|
|
44369
|
+
return cracks.version;
|
|
44370
|
+
},
|
|
43924
44371
|
debris: () => debrisStore.list,
|
|
43925
44372
|
burningPoints: () => [...burning.keys()].map((key2) => {
|
|
43926
44373
|
const cellRow = Math.floor(key2 / 65536);
|
|
@@ -43933,7 +44380,7 @@ void main(){
|
|
|
43933
44380
|
stats: () => ({ marks: marks.list.length, debris: debrisStore.list.length, debrisMoving: debrisStore.list.filter((piece) => !piece.atRest).length, dirtyChunks: dirty.size, burning: burning.size }),
|
|
43934
44381
|
reset,
|
|
43935
44382
|
serialize() {
|
|
43936
|
-
return { layout: currentLayout, dug: sparse(dug), loose: sparse(loose), scorch: sparse(scorch), barBend: sparse(barBend), marks: marks.list.map((mark) => ({ ...mark })) };
|
|
44383
|
+
return { layout: currentLayout, dug: sparse(dug), loose: sparse(loose), scorch: sparse(scorch), barBend: sparse(barBend), marks: marks.list.map((mark) => ({ ...mark })), cracks: cracks.list.map((crack) => ({ ...crack })) };
|
|
43937
44384
|
},
|
|
43938
44385
|
load(snapshot) {
|
|
43939
44386
|
currentLayout = snapshot.layout;
|
|
@@ -43943,6 +44390,7 @@ void main(){
|
|
|
43943
44390
|
fillSparse(scorch, snapshot.scorch);
|
|
43944
44391
|
fillSparse(barBend, snapshot.barBend ?? []);
|
|
43945
44392
|
marks.load(snapshot.marks);
|
|
44393
|
+
cracks.load(snapshot.cracks ?? []);
|
|
43946
44394
|
for (let chunkIndex = 0; chunkIndex < touched.length; chunkIndex++) markChunk(chunkIndex);
|
|
43947
44395
|
}
|
|
43948
44396
|
};
|
|
@@ -44287,7 +44735,7 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
44287
44735
|
mesh2.renderOrder = 1;
|
|
44288
44736
|
mesh2.setColorAt(0, new THREE.Color(1, 1, 1));
|
|
44289
44737
|
const matrix = new THREE.Matrix4();
|
|
44290
|
-
const
|
|
44738
|
+
const rotation2 = new THREE.Matrix4();
|
|
44291
44739
|
const scale2 = new THREE.Matrix4();
|
|
44292
44740
|
const colour = new THREE.Color();
|
|
44293
44741
|
let seen = "";
|
|
@@ -44308,9 +44756,9 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
44308
44756
|
for (const mark of marks) {
|
|
44309
44757
|
if (Math.hypot(mark.x - camera2.x, mark.z - camera2.z) > drawDistance) continue;
|
|
44310
44758
|
const size = mark.radius * 2 * MARK_REACH;
|
|
44311
|
-
|
|
44759
|
+
rotation2.makeRotationY(mark.id * 2.399);
|
|
44312
44760
|
scale2.makeScale(size, 1, size);
|
|
44313
|
-
matrix.multiplyMatrices(
|
|
44761
|
+
matrix.multiplyMatrices(rotation2, scale2);
|
|
44314
44762
|
matrix.setPosition(mark.x, terrain.heightAt(mark.x, mark.z) + MARK_LIFT, mark.z);
|
|
44315
44763
|
mesh2.setMatrixAt(count, matrix);
|
|
44316
44764
|
const [r, g, b] = terrain.material(mark.material).color;
|
|
@@ -44374,6 +44822,92 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
44374
44822
|
}
|
|
44375
44823
|
};
|
|
44376
44824
|
}
|
|
44825
|
+
var CRACK_LIFT = 4e-3;
|
|
44826
|
+
var MAX_CRACK_QUADS = 8192;
|
|
44827
|
+
var CRACK_SHADE = 0.22;
|
|
44828
|
+
var DARK_SURFACE = 0.1;
|
|
44829
|
+
var DUST_LIFT = 2;
|
|
44830
|
+
var DUST_GREY = 0.12;
|
|
44831
|
+
function createCrackLayer(THREE, terrain) {
|
|
44832
|
+
const positions = new Float32Array(MAX_CRACK_QUADS * 4 * 3);
|
|
44833
|
+
const colours = new Float32Array(MAX_CRACK_QUADS * 4 * 3);
|
|
44834
|
+
const indices = new Uint32Array(MAX_CRACK_QUADS * 6);
|
|
44835
|
+
for (let quad = 0; quad < MAX_CRACK_QUADS; quad++) {
|
|
44836
|
+
const first = quad * 4;
|
|
44837
|
+
indices.set([first, first + 2, first + 1, first + 1, first + 2, first + 3], quad * 6);
|
|
44838
|
+
}
|
|
44839
|
+
const geometry = new THREE.BufferGeometry();
|
|
44840
|
+
const position = new THREE.BufferAttribute(positions, 3);
|
|
44841
|
+
const colour = new THREE.BufferAttribute(colours, 3);
|
|
44842
|
+
position.setUsage(THREE.DynamicDrawUsage);
|
|
44843
|
+
colour.setUsage(THREE.DynamicDrawUsage);
|
|
44844
|
+
geometry.setAttribute("position", position);
|
|
44845
|
+
geometry.setAttribute("color", colour);
|
|
44846
|
+
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
|
|
44847
|
+
geometry.setDrawRange(0, 0);
|
|
44848
|
+
const material = new THREE.MeshBasicMaterial({ vertexColors: true, transparent: true, opacity: 0.9, depthWrite: false, polygonOffset: true, polygonOffsetFactor: -3, polygonOffsetUnits: -3 });
|
|
44849
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
44850
|
+
mesh2.name = "terrain-cracks";
|
|
44851
|
+
mesh2.frustumCulled = false;
|
|
44852
|
+
mesh2.renderOrder = 2;
|
|
44853
|
+
let seen = -1;
|
|
44854
|
+
let groundMoved = false;
|
|
44855
|
+
const stopListening = terrain.onDeform(() => {
|
|
44856
|
+
groundMoved = true;
|
|
44857
|
+
});
|
|
44858
|
+
const lift = (x, z) => terrain.heightAt(x, z) + CRACK_LIFT;
|
|
44859
|
+
return {
|
|
44860
|
+
mesh: mesh2,
|
|
44861
|
+
sync() {
|
|
44862
|
+
const cracks = terrain.cracks();
|
|
44863
|
+
if (seen === terrain.cracksVersion && !(groundMoved && cracks.length > 0)) return;
|
|
44864
|
+
seen = terrain.cracksVersion;
|
|
44865
|
+
groundMoved = false;
|
|
44866
|
+
let quad = 0;
|
|
44867
|
+
for (let n = cracks.length - 1; n >= 0 && quad < MAX_CRACK_QUADS; n--) {
|
|
44868
|
+
const crack = cracks[n];
|
|
44869
|
+
const tone = terrain.material(crack.material).color;
|
|
44870
|
+
const dark = tone[0] * 0.3 + tone[1] * 0.59 + tone[2] * 0.11 < DARK_SURFACE;
|
|
44871
|
+
const k = dark ? DUST_LIFT : CRACK_SHADE;
|
|
44872
|
+
const r = dark ? Math.min(1, tone[0] * k + DUST_GREY) : tone[0] * k;
|
|
44873
|
+
const g = dark ? Math.min(1, tone[1] * k + DUST_GREY) : tone[1] * k;
|
|
44874
|
+
const b = dark ? Math.min(1, tone[2] * k + DUST_GREY) : tone[2] * k;
|
|
44875
|
+
for (const s of crackLines(crack)) {
|
|
44876
|
+
if (quad >= MAX_CRACK_QUADS) break;
|
|
44877
|
+
if (!terrain.contains(s.x0, s.z0) || !terrain.contains(s.x1, s.z1)) continue;
|
|
44878
|
+
const length3 = Math.hypot(s.x1 - s.x0, s.z1 - s.z0);
|
|
44879
|
+
if (length3 < 1e-5) continue;
|
|
44880
|
+
const ax = -(s.z1 - s.z0) / length3;
|
|
44881
|
+
const az = (s.x1 - s.x0) / length3;
|
|
44882
|
+
const corners = [
|
|
44883
|
+
[s.x0 + ax * s.w0 * 0.5, s.z0 + az * s.w0 * 0.5],
|
|
44884
|
+
[s.x0 - ax * s.w0 * 0.5, s.z0 - az * s.w0 * 0.5],
|
|
44885
|
+
[s.x1 + ax * s.w1 * 0.5, s.z1 + az * s.w1 * 0.5],
|
|
44886
|
+
[s.x1 - ax * s.w1 * 0.5, s.z1 - az * s.w1 * 0.5]
|
|
44887
|
+
];
|
|
44888
|
+
corners.forEach(([x, z], corner) => {
|
|
44889
|
+
const at3 = (quad * 4 + corner) * 3;
|
|
44890
|
+
positions[at3] = x;
|
|
44891
|
+
positions[at3 + 1] = lift(x, z);
|
|
44892
|
+
positions[at3 + 2] = z;
|
|
44893
|
+
colours[at3] = r;
|
|
44894
|
+
colours[at3 + 1] = g;
|
|
44895
|
+
colours[at3 + 2] = b;
|
|
44896
|
+
});
|
|
44897
|
+
quad++;
|
|
44898
|
+
}
|
|
44899
|
+
}
|
|
44900
|
+
position.needsUpdate = true;
|
|
44901
|
+
colour.needsUpdate = true;
|
|
44902
|
+
geometry.setDrawRange(0, quad * 6);
|
|
44903
|
+
},
|
|
44904
|
+
dispose() {
|
|
44905
|
+
stopListening();
|
|
44906
|
+
geometry.dispose();
|
|
44907
|
+
material.dispose();
|
|
44908
|
+
}
|
|
44909
|
+
};
|
|
44910
|
+
}
|
|
44377
44911
|
var BAR_RADIUS = 6e-3;
|
|
44378
44912
|
var EXPOSED_MARGIN = 2e-3;
|
|
44379
44913
|
var MAX_SAG = 0.07;
|
|
@@ -44488,7 +45022,8 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
44488
45022
|
const drawn = /* @__PURE__ */ new Map();
|
|
44489
45023
|
const marks = createMarkLayer2(THREE, terrain, options.markDistance ?? DEFAULT_MARK_DISTANCE);
|
|
44490
45024
|
const debris2 = createDebrisLayer(THREE, terrain);
|
|
44491
|
-
|
|
45025
|
+
const cracks = createCrackLayer(THREE, terrain);
|
|
45026
|
+
group.add(marks.mesh, cracks.mesh, debris2.mesh);
|
|
44492
45027
|
let pristineStale = true;
|
|
44493
45028
|
let pristineBuilt = false;
|
|
44494
45029
|
let pristineCount = 0;
|
|
@@ -44574,7 +45109,8 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
44574
45109
|
return {
|
|
44575
45110
|
group,
|
|
44576
45111
|
sync(camera2) {
|
|
44577
|
-
const
|
|
45112
|
+
const laidAnew = terrain.dirtyChunkCount >= terrain.chunksX * terrain.chunksZ;
|
|
45113
|
+
const limit = firstSync || laidAnew ? Infinity : void 0;
|
|
44578
45114
|
firstSync = false;
|
|
44579
45115
|
for (const chunk of terrain.drainDirtyChunks(limit)) {
|
|
44580
45116
|
if (chunk.pristine) {
|
|
@@ -44595,9 +45131,10 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
44595
45131
|
}
|
|
44596
45132
|
}
|
|
44597
45133
|
marks.sync(camera2);
|
|
45134
|
+
cracks.sync();
|
|
44598
45135
|
debris2.sync();
|
|
44599
45136
|
},
|
|
44600
|
-
stats: () => ({ chunkMeshes: drawn.size, pristineChunks: pristineCount, marksDrawn: marks.mesh.count, debrisDrawn: debris2.mesh.count }),
|
|
45137
|
+
stats: () => ({ chunkMeshes: drawn.size, pristineChunks: pristineCount, marksDrawn: marks.mesh.count, debrisDrawn: debris2.mesh.count, crackQuads: cracks.mesh.geometry.drawRange.count / 6 }),
|
|
44601
45138
|
dispose() {
|
|
44602
45139
|
for (const index of [...drawn.keys()]) drop(index);
|
|
44603
45140
|
for (const geometry of spareGeometries) geometry.dispose();
|
|
@@ -44605,11 +45142,19 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
44605
45142
|
surface.dispose();
|
|
44606
45143
|
rebarMaterial.dispose();
|
|
44607
45144
|
marks.dispose();
|
|
45145
|
+
cracks.dispose();
|
|
44608
45146
|
debris2.dispose();
|
|
44609
45147
|
group.removeFromParent();
|
|
44610
45148
|
}
|
|
44611
45149
|
};
|
|
44612
45150
|
}
|
|
45151
|
+
var PROFILE_NAMES = {
|
|
45152
|
+
en: { lawn: "Lawn", dirt: "Dirt", sand: "Sand", road: "Asphalt road", concrete_slab: "Concrete slab", suspended_slab: "Slab over a void", tile_floor: "Tile floor", wood_floor: "Wood floor", stone_paving: "Stone paving" },
|
|
45153
|
+
"pt-BR": { lawn: "Grama", dirt: "Terra", sand: "Areia", road: "Asfalto", concrete_slab: "Laje de concreto", suspended_slab: "Laje sobre v\xE3o", tile_floor: "Piso cer\xE2mico", wood_floor: "Assoalho", stone_paving: "Cal\xE7amento de pedra" }
|
|
45154
|
+
};
|
|
45155
|
+
function terrainProfileName(profileId, localeId) {
|
|
45156
|
+
return (PROFILE_NAMES[localeId] ?? PROFILE_NAMES.en)[profileId] ?? profileId;
|
|
45157
|
+
}
|
|
44613
45158
|
var TERRAIN_STRIPS = ["dirt", "lawn", "sand", "road", "concrete_slab", "suspended_slab", "wood_floor", "tile_floor", "stone_paving"];
|
|
44614
45159
|
var STRIP_WIDTH = 3;
|
|
44615
45160
|
var STRIP_Z0 = 4;
|
|
@@ -44992,6 +45537,8 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
44992
45537
|
"ins.damage": "Marks",
|
|
44993
45538
|
"ins.damage_counts": "{dents}, {holes}, {cracks}",
|
|
44994
45539
|
"ins.mass": "Mass",
|
|
45540
|
+
"ins.dug": "Dug",
|
|
45541
|
+
"ins.dig_limit": "Ground left to dig",
|
|
44995
45542
|
"ins.load": "Load",
|
|
44996
45543
|
"ins.stress": "Stress",
|
|
44997
45544
|
"ins.joints": "Joints",
|
|
@@ -45340,6 +45887,8 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
45340
45887
|
"ins.damage": "Marcas",
|
|
45341
45888
|
"ins.damage_counts": "{dents}, {holes}, {cracks}",
|
|
45342
45889
|
"ins.mass": "Massa",
|
|
45890
|
+
"ins.dug": "Escavado",
|
|
45891
|
+
"ins.dig_limit": "Ch\xE3o at\xE9 o limite",
|
|
45343
45892
|
"ins.load": "Carga",
|
|
45344
45893
|
"ins.stress": "Tens\xE3o",
|
|
45345
45894
|
"ins.joints": "Juntas",
|
|
@@ -46227,6 +46776,15 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
46227
46776
|
insp.appendChild(mk3("div", void 0, t("ui.aim_at_something")));
|
|
46228
46777
|
return;
|
|
46229
46778
|
}
|
|
46779
|
+
if (i.ground) {
|
|
46780
|
+
const g = i.ground;
|
|
46781
|
+
insp.appendChild(mk3("div", "t", `${i.object} \u203A ${g.surface}`));
|
|
46782
|
+
insp.appendChild(row(t("ins.material"), g.material));
|
|
46783
|
+
insp.appendChild(row(t("ins.dug"), `${num(g.dug * 100, 0)} cm`));
|
|
46784
|
+
insp.appendChild(row(t("ins.dig_limit"), `${num(g.remaining, 2)} m`));
|
|
46785
|
+
if (g.scorch > 0.01) insp.appendChild(row(t("ins.char"), `${num(g.scorch * 100, 0)} %`));
|
|
46786
|
+
return;
|
|
46787
|
+
}
|
|
46230
46788
|
if (i.thumbnail) insp.appendChild(thumb(i.thumbnail, i.thumbnailCredit));
|
|
46231
46789
|
insp.appendChild(mk3("div", "t", `${i.object} \u203A ${i.part}`));
|
|
46232
46790
|
insp.appendChild(row(t("ins.material"), i.material));
|
|
@@ -47207,6 +47765,23 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
47207
47765
|
}
|
|
47208
47766
|
return m;
|
|
47209
47767
|
};
|
|
47768
|
+
let releaseBatch = null;
|
|
47769
|
+
const dropTree = (root) => {
|
|
47770
|
+
if (!root) return;
|
|
47771
|
+
if (releaseBatch) releaseBatch.push(root);
|
|
47772
|
+
else releaseObject3D(root, { keep: scene2 });
|
|
47773
|
+
};
|
|
47774
|
+
const releasingTogether = (fn) => {
|
|
47775
|
+
if (releaseBatch) return fn();
|
|
47776
|
+
releaseBatch = [];
|
|
47777
|
+
try {
|
|
47778
|
+
fn();
|
|
47779
|
+
} finally {
|
|
47780
|
+
const roots = releaseBatch;
|
|
47781
|
+
releaseBatch = null;
|
|
47782
|
+
releaseObject3D(roots, { keep: scene2 });
|
|
47783
|
+
}
|
|
47784
|
+
};
|
|
47210
47785
|
const removeEntry = (id) => {
|
|
47211
47786
|
const e = entries.get(id);
|
|
47212
47787
|
if (!e) return;
|
|
@@ -47223,7 +47798,10 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
47223
47798
|
e.follower?.dispose?.();
|
|
47224
47799
|
if (world.has(id)) world.remove(id);
|
|
47225
47800
|
e.so.root.removeFromParent();
|
|
47801
|
+
const inner = wrapped.get(e.so.root);
|
|
47226
47802
|
letGo(e.so.root);
|
|
47803
|
+
dropTree(e.so.root);
|
|
47804
|
+
dropTree(inner);
|
|
47227
47805
|
entries.delete(id);
|
|
47228
47806
|
doors.forget(id);
|
|
47229
47807
|
rendererPieces.delete(id);
|
|
@@ -47239,12 +47817,14 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
47239
47817
|
}
|
|
47240
47818
|
if (world.has(id)) world.remove(id);
|
|
47241
47819
|
p?.root.removeFromParent();
|
|
47820
|
+
dropTree(p?.root);
|
|
47242
47821
|
rendererPieces.delete(id);
|
|
47243
47822
|
splitOf.delete(id);
|
|
47244
47823
|
}
|
|
47245
47824
|
loose.length = 0;
|
|
47246
47825
|
};
|
|
47247
|
-
const clearEverything = () =>
|
|
47826
|
+
const clearEverything = () => releasingTogether(clearEverythingNow);
|
|
47827
|
+
const clearEverythingNow = () => {
|
|
47248
47828
|
if (heldEntry || heldPiece) releaseHeld();
|
|
47249
47829
|
useItemPlayer = null;
|
|
47250
47830
|
playing.length = 0;
|
|
@@ -47293,8 +47873,10 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
47293
47873
|
seating.release();
|
|
47294
47874
|
pushByKey = false;
|
|
47295
47875
|
push.end();
|
|
47296
|
-
|
|
47297
|
-
|
|
47876
|
+
releasingTogether(() => {
|
|
47877
|
+
clearEverythingNow();
|
|
47878
|
+
for (const id of [...entries.keys()]) removeEntry(id);
|
|
47879
|
+
});
|
|
47298
47880
|
renderer.reset();
|
|
47299
47881
|
for (const listener of [...resetListeners]) listener();
|
|
47300
47882
|
tools.clear();
|
|
@@ -47447,11 +48029,11 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
47447
48029
|
};
|
|
47448
48030
|
const reachAvatar = () => {
|
|
47449
48031
|
const doorHand = doors.handTargets();
|
|
47450
|
-
const targets = push.active ? null : heldPiece ? twistHand : handSource?.() ?? null;
|
|
48032
|
+
const targets = push.active ? null : doorHand ?? (heldPiece ? twistHand : handSource?.() ?? null);
|
|
47451
48033
|
lastHand = {
|
|
47452
48034
|
stance: push.active || doorHand ? "hold" : handStances[toolId] ?? (targets ? "hold" : "relaxed"),
|
|
47453
48035
|
triggerFinger: targets?.fingers?.index ?? null,
|
|
47454
|
-
targets: push.handTargets() ??
|
|
48036
|
+
targets: push.handTargets() ?? targets
|
|
47455
48037
|
};
|
|
47456
48038
|
if (!avatar?.reach) return;
|
|
47457
48039
|
avatar.reach(targets, { camera: camera2, keepOutside: { contact: (origin, direction, maxDistance) => rayWorld(origin, direction, maxDistance)?.distance ?? null } });
|
|
@@ -48561,9 +49143,36 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
48561
49143
|
if (!leaf2) return void 0;
|
|
48562
49144
|
return t(leaf2.locked ? "hud.door_hint_locked" : leaf2.open ? "hud.door_hint_close" : "hud.door_hint_open");
|
|
48563
49145
|
};
|
|
49146
|
+
const groundInspect = (r) => {
|
|
49147
|
+
const onFloor = terrain.raycast(aimO, aimD, r.distance + 3);
|
|
49148
|
+
const [x, , z] = onFloor?.point ?? r.point;
|
|
49149
|
+
const column = terrain.columnAt(x, z);
|
|
49150
|
+
const materialName = S.text[`material.${column.material}`] ?? dStrings.materialNames[column.material] ?? column.material;
|
|
49151
|
+
return {
|
|
49152
|
+
object: t("ground.name"),
|
|
49153
|
+
objectId: GROUND_ID2,
|
|
49154
|
+
part: column.profile,
|
|
49155
|
+
material: materialName,
|
|
49156
|
+
status: "",
|
|
49157
|
+
hp: 0,
|
|
49158
|
+
maxHp: 0,
|
|
49159
|
+
temperature: 0,
|
|
49160
|
+
burning: false,
|
|
49161
|
+
char: column.scorch,
|
|
49162
|
+
melt: 0,
|
|
49163
|
+
dents: 0,
|
|
49164
|
+
holes: 0,
|
|
49165
|
+
cracks: 0,
|
|
49166
|
+
mass: 0,
|
|
49167
|
+
joints: [],
|
|
49168
|
+
distance: onFloor?.distance ?? r.distance,
|
|
49169
|
+
ground: { surface: terrainProfileName(column.profile, locale), material: materialName, dug: column.depth, remaining: column.remaining, scorch: column.scorch }
|
|
49170
|
+
};
|
|
49171
|
+
};
|
|
48564
49172
|
const inspectInfo = () => {
|
|
48565
49173
|
const r = inspectTarget();
|
|
48566
49174
|
if (!r) return null;
|
|
49175
|
+
if (r.object === GROUND_ID2) return groundInspect(r);
|
|
48567
49176
|
const st = world.state(r.object);
|
|
48568
49177
|
const p = world.part(r.object, r.part);
|
|
48569
49178
|
if (!st || !p) return null;
|