@adatechnology/game-test-room 0.19.1 → 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/dist/index.d.ts +15 -0
- package/dist/index.global.js +603 -113
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +41 -1
- package/dist/index.js.map +1 -1
- package/package.json +13 -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]];
|
|
@@ -3602,8 +3602,8 @@ var GameTestRoom = (() => {
|
|
|
3602
3602
|
}
|
|
3603
3603
|
solveStructure(o);
|
|
3604
3604
|
if (peak <= sec.steel) return;
|
|
3605
|
-
const
|
|
3606
|
-
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;
|
|
3607
3607
|
markDamaged(p);
|
|
3608
3608
|
if (p.rt.hinge >= flexure.failRotationDeg * Math.PI / 180) hingeDrop(o, p, src);
|
|
3609
3609
|
};
|
|
@@ -4305,8 +4305,8 @@ var GameTestRoom = (() => {
|
|
|
4305
4305
|
const detachEvents = (o, opened, by, src) => {
|
|
4306
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]) });
|
|
4307
4307
|
};
|
|
4308
|
-
const slideOffResting = (o,
|
|
4309
|
-
const upY = 1 - 2 * (
|
|
4308
|
+
const slideOffResting = (o, rotation2) => {
|
|
4309
|
+
const upY = 1 - 2 * (rotation2[0] * rotation2[0] + rotation2[2] * rotation2[2]);
|
|
4310
4310
|
if (upY >= RESTING_HOLD_COS) return;
|
|
4311
4311
|
const opened = o.joints.filter((j) => j.spec.kind === "resting" && !j.st.open);
|
|
4312
4312
|
if (opened.length === 0) return;
|
|
@@ -5729,11 +5729,11 @@ var GameTestRoom = (() => {
|
|
|
5729
5729
|
impls.set(id, { impl, position: opts.position ?? [0, 0, 0], rotation: opts.rotation ?? [0, 0, 0, 1], poses: /* @__PURE__ */ new Map() });
|
|
5730
5730
|
return id;
|
|
5731
5731
|
},
|
|
5732
|
-
setPartPose(objectId, partId, position,
|
|
5733
|
-
const q = quatFromEuler(...
|
|
5732
|
+
setPartPose(objectId, partId, position, rotation2) {
|
|
5733
|
+
const q = quatFromEuler(...rotation2 ?? [0, 0, 0]);
|
|
5734
5734
|
const im = impls.get(objectId);
|
|
5735
5735
|
if (im) {
|
|
5736
|
-
im.impl.setPartPose?.(partId, position,
|
|
5736
|
+
im.impl.setPartPose?.(partId, position, rotation2);
|
|
5737
5737
|
im.poses.set(partId, { pos: [position[0], position[1], position[2]], q });
|
|
5738
5738
|
return;
|
|
5739
5739
|
}
|
|
@@ -5750,17 +5750,17 @@ var GameTestRoom = (() => {
|
|
|
5750
5750
|
},
|
|
5751
5751
|
has: (id) => taken(id),
|
|
5752
5752
|
ids: () => [...objects.keys(), ...impls.keys()],
|
|
5753
|
-
setTransform(id, position,
|
|
5753
|
+
setTransform(id, position, rotation2) {
|
|
5754
5754
|
const im = impls.get(id);
|
|
5755
5755
|
if (im) {
|
|
5756
5756
|
im.position = [position[0], position[1], position[2]];
|
|
5757
|
-
im.rotation = [
|
|
5757
|
+
im.rotation = [rotation2[0], rotation2[1], rotation2[2], rotation2[3]];
|
|
5758
5758
|
return;
|
|
5759
5759
|
}
|
|
5760
5760
|
const o = getObj(id);
|
|
5761
|
-
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]] };
|
|
5762
5762
|
applySoilPose(o);
|
|
5763
|
-
slideOffResting(o,
|
|
5763
|
+
slideOffResting(o, rotation2);
|
|
5764
5764
|
},
|
|
5765
5765
|
splitGroup(id, group, newId) {
|
|
5766
5766
|
if (impls.has(id)) throw new Error(`object "${id}" is a registered DestructibleImpl and cannot be split; its module owns its pieces`);
|
|
@@ -9166,11 +9166,231 @@ var GameTestRoom = (() => {
|
|
|
9166
9166
|
glow.outIntensity = glow.i * Math.pow(1 - age, glow.curve) * flicker;
|
|
9167
9167
|
}
|
|
9168
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
|
+
}
|
|
9169
9387
|
var FLOOR_FRACTION = 0.4;
|
|
9170
9388
|
var FLOOR_BOUNCE = -0.2;
|
|
9171
9389
|
var ARRIVAL_FRAME = 30;
|
|
9172
9390
|
var ARRIVAL_BASE = 0.3;
|
|
9173
9391
|
var GROWTH_CAP_SECONDS = 3.5;
|
|
9392
|
+
var CARRIED_KINDS = [true, true, false, true, false];
|
|
9393
|
+
var PAD_OF_SIZE = 0.35;
|
|
9174
9394
|
function createPuffPool(capacity) {
|
|
9175
9395
|
const placeholder = { next: () => 0, between: (min2) => min2, direction: (out) => out, state: 0 };
|
|
9176
9396
|
return new OrderedPool(capacity, () => ({
|
|
@@ -9265,13 +9485,24 @@ var GameTestRoom = (() => {
|
|
|
9265
9485
|
if (puff3.vy < 0) puff3.vy *= FLOOR_BOUNCE;
|
|
9266
9486
|
}
|
|
9267
9487
|
}
|
|
9268
|
-
function updatePuffs(pool, dt, wind) {
|
|
9488
|
+
function updatePuffs(pool, dt, wind, confiner) {
|
|
9269
9489
|
pool.compact(ageOrKeep2, dt);
|
|
9490
|
+
const confining = confiner !== void 0 && !confiner.empty;
|
|
9270
9491
|
for (const puff3 of pool.items) {
|
|
9271
9492
|
const age = puff3.t / puff3.life;
|
|
9272
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;
|
|
9273
9497
|
if (puff3.ring) moveOnRing(puff3, puff3.ring, wind);
|
|
9274
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
|
+
}
|
|
9275
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);
|
|
9276
9507
|
puff3.size = size * Math.min(1, puff3.t * ARRIVAL_FRAME + ARRIVAL_BASE);
|
|
9277
9508
|
puff3.age = age;
|
|
@@ -9797,10 +10028,10 @@ var GameTestRoom = (() => {
|
|
|
9797
10028
|
])
|
|
9798
10029
|
]
|
|
9799
10030
|
};
|
|
9800
|
-
function localToWorld(translation,
|
|
10031
|
+
function localToWorld(translation, rotation2, local2) {
|
|
9801
10032
|
const [x, y, z] = local2;
|
|
9802
|
-
const [a, c, e] = [Math.cos(
|
|
9803
|
-
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])];
|
|
9804
10035
|
const [ae, af, be, bf] = [a * e, a * f, b * e, b * f];
|
|
9805
10036
|
return [
|
|
9806
10037
|
c * e * x + -c * f * y + d * z + translation[0],
|
|
@@ -11463,46 +11694,6 @@ var GameTestRoom = (() => {
|
|
|
11463
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];
|
|
11464
11695
|
var WORKSHOP_EFFECTS = Object.fromEntries(ALL_EFFECTS.map((effect) => [effect.id, effect]));
|
|
11465
11696
|
var GAME_EFFECTS = { ...WORKSHOP_EFFECTS, ...Object.fromEntries([...EVENT_EFFECTS, ...VIEWMODEL_EFFECTS, ...VEHICLE_EFFECTS].map((effect) => [effect.id, effect])) };
|
|
11466
|
-
var LEHMER_MULTIPLIER = 16807;
|
|
11467
|
-
var LEHMER_MODULUS = 2147483647;
|
|
11468
|
-
var HASH_MIX = 2654435761;
|
|
11469
|
-
function normalizeLehmerSeed(seed) {
|
|
11470
|
-
const whole = Math.floor(Math.abs(seed)) % (LEHMER_MODULUS - 1);
|
|
11471
|
-
return whole === 0 ? 1 : whole;
|
|
11472
|
-
}
|
|
11473
|
-
function lehmer(seed) {
|
|
11474
|
-
let state = normalizeLehmerSeed(seed);
|
|
11475
|
-
const next = () => {
|
|
11476
|
-
state = state * LEHMER_MULTIPLIER % LEHMER_MODULUS;
|
|
11477
|
-
return (state - 1) / (LEHMER_MODULUS - 1);
|
|
11478
|
-
};
|
|
11479
|
-
return {
|
|
11480
|
-
next,
|
|
11481
|
-
between: (min2, max2) => min2 + (max2 - min2) * next(),
|
|
11482
|
-
direction(out) {
|
|
11483
|
-
const up = next() * 2 - 1;
|
|
11484
|
-
const angle = next() * Math.PI * 2;
|
|
11485
|
-
const ring2 = Math.sqrt(1 - up * up);
|
|
11486
|
-
out.x = ring2 * Math.cos(angle);
|
|
11487
|
-
out.y = up;
|
|
11488
|
-
out.z = ring2 * Math.sin(angle);
|
|
11489
|
-
return out;
|
|
11490
|
-
},
|
|
11491
|
-
get state() {
|
|
11492
|
-
return state;
|
|
11493
|
-
}
|
|
11494
|
-
};
|
|
11495
|
-
}
|
|
11496
|
-
function mixEventSeed(eventSeed) {
|
|
11497
|
-
let mixed = Math.imul((eventSeed | 0) ^ HASH_MIX, 2246822507);
|
|
11498
|
-
mixed ^= mixed >>> 13;
|
|
11499
|
-
mixed = Math.imul(mixed, 3266489909);
|
|
11500
|
-
mixed ^= mixed >>> 16;
|
|
11501
|
-
return (mixed >>> 0) % (LEHMER_MODULUS - 1) + 1;
|
|
11502
|
-
}
|
|
11503
|
-
function streamFor2(eventSeed) {
|
|
11504
|
-
return lehmer(mixEventSeed(eventSeed));
|
|
11505
|
-
}
|
|
11506
11697
|
var TABLE = {
|
|
11507
11698
|
concrete: { dust: 9078138, chip: 7236195, spark: 2 },
|
|
11508
11699
|
metal: { dust: 0, chip: 0, spark: 18 },
|
|
@@ -12806,8 +12997,8 @@ var GameTestRoom = (() => {
|
|
|
12806
12997
|
function addScorch(store, random, x, z, radius) {
|
|
12807
12998
|
const variant = Math.floor(random.next() * SCORCH_VARIANTS);
|
|
12808
12999
|
const lift = 0.03 + nextLift(store) * 1e-3;
|
|
12809
|
-
const
|
|
12810
|
-
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 });
|
|
12811
13002
|
}
|
|
12812
13003
|
function addRimRocks(store, ground, random, x, z, radius) {
|
|
12813
13004
|
const count = Math.round(6 + radius * 7);
|
|
@@ -12836,8 +13027,8 @@ var GameTestRoom = (() => {
|
|
|
12836
13027
|
function addCrater(store, ground, random, spec) {
|
|
12837
13028
|
ground?.dent(random, spec.x, spec.z, spec.radius, spec.depth);
|
|
12838
13029
|
if (!spec.marks) return;
|
|
12839
|
-
const
|
|
12840
|
-
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 });
|
|
12841
13032
|
addRimRocks(store, ground, random, spec.x, spec.z, spec.radius);
|
|
12842
13033
|
}
|
|
12843
13034
|
function addBloodSplat(store, ground, random, spec) {
|
|
@@ -13393,6 +13584,7 @@ var GameTestRoom = (() => {
|
|
|
13393
13584
|
state.gas = Math.max(0, state.gas - dt / DECAY.gasSeconds);
|
|
13394
13585
|
state.beat *= Math.exp(-DECAY.beat * dt);
|
|
13395
13586
|
}
|
|
13587
|
+
var PAD_OF_SIZE2 = 0.35;
|
|
13396
13588
|
var clamp4 = (v, lo, hi) => v < lo ? lo : v > hi ? hi : v;
|
|
13397
13589
|
var lerp4 = (a, b, t) => a + (b - a) * t;
|
|
13398
13590
|
function rgb(hex) {
|
|
@@ -13552,9 +13744,20 @@ var GameTestRoom = (() => {
|
|
|
13552
13744
|
vy2 *= k;
|
|
13553
13745
|
vz2 *= k;
|
|
13554
13746
|
}
|
|
13555
|
-
|
|
13747
|
+
let x = this.position[i3] + vx2 * dt;
|
|
13556
13748
|
let y = this.position[i3 + 1] + vy2 * dt;
|
|
13557
|
-
|
|
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
|
+
}
|
|
13558
13761
|
if (def.ground !== "none") {
|
|
13559
13762
|
const own = this.floor[i];
|
|
13560
13763
|
const gy = Number.isNaN(own) ? host.groundAt(x, z) + 5e-3 : own;
|
|
@@ -13640,7 +13843,8 @@ var GameTestRoom = (() => {
|
|
|
13640
13843
|
alpha: 0.35,
|
|
13641
13844
|
fadeIn: 0.15,
|
|
13642
13845
|
cone: 0.6,
|
|
13643
|
-
ground: "none"
|
|
13846
|
+
ground: "none",
|
|
13847
|
+
carried: true
|
|
13644
13848
|
},
|
|
13645
13849
|
sparks: {
|
|
13646
13850
|
id: "sparks",
|
|
@@ -13684,7 +13888,8 @@ var GameTestRoom = (() => {
|
|
|
13684
13888
|
alpha: 0.4,
|
|
13685
13889
|
fadeIn: 0.1,
|
|
13686
13890
|
cone: 0.4,
|
|
13687
|
-
ground: "none"
|
|
13891
|
+
ground: "none",
|
|
13892
|
+
carried: true
|
|
13688
13893
|
},
|
|
13689
13894
|
shards: {
|
|
13690
13895
|
id: "shards",
|
|
@@ -13842,7 +14047,8 @@ var GameTestRoom = (() => {
|
|
|
13842
14047
|
fadeIn: 0.1,
|
|
13843
14048
|
cone: 0.5,
|
|
13844
14049
|
ground: "stop",
|
|
13845
|
-
flutter: 0.6
|
|
14050
|
+
flutter: 0.6,
|
|
14051
|
+
carried: true
|
|
13846
14052
|
},
|
|
13847
14053
|
steam: {
|
|
13848
14054
|
id: "steam",
|
|
@@ -13864,7 +14070,8 @@ var GameTestRoom = (() => {
|
|
|
13864
14070
|
alpha: 0.35,
|
|
13865
14071
|
fadeIn: 0.15,
|
|
13866
14072
|
cone: 0.6,
|
|
13867
|
-
ground: "none"
|
|
14073
|
+
ground: "none",
|
|
14074
|
+
carried: true
|
|
13868
14075
|
},
|
|
13869
14076
|
flash: {
|
|
13870
14077
|
id: "flash",
|
|
@@ -14005,7 +14212,8 @@ var GameTestRoom = (() => {
|
|
|
14005
14212
|
const host = {
|
|
14006
14213
|
groundAt: this.options.groundAt,
|
|
14007
14214
|
gravity: this.options.gravity,
|
|
14008
|
-
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 } : {}
|
|
14009
14217
|
};
|
|
14010
14218
|
if (this.additive.live > 0 || this.additive.drawCount > 0) this.additive.update(dt, host);
|
|
14011
14219
|
if (this.normal.live > 0 || this.normal.drawCount > 0) this.normal.update(dt, host);
|
|
@@ -14211,8 +14419,8 @@ var GameTestRoom = (() => {
|
|
|
14211
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
|
|
14212
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.
|
|
14213
14421
|
*/
|
|
14214
|
-
clearInside(center, half,
|
|
14215
|
-
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];
|
|
14216
14424
|
let gone = 0;
|
|
14217
14425
|
for (const decal2 of this.decals) {
|
|
14218
14426
|
if (!decal2.on) continue;
|
|
@@ -14333,10 +14541,14 @@ var GameTestRoom = (() => {
|
|
|
14333
14541
|
var DEFAULT_FADE_IN = 0.1;
|
|
14334
14542
|
var FLOATS_PER_VECTOR = 3;
|
|
14335
14543
|
var BYTE_MAX2 = 255;
|
|
14544
|
+
var CARRIED_GRAVITY = 3;
|
|
14545
|
+
var PAD_OF_SIZE3 = 0.35;
|
|
14336
14546
|
var SpritePool = class {
|
|
14337
|
-
|
|
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) {
|
|
14338
14549
|
__publicField(this, "capacity", capacity);
|
|
14339
14550
|
__publicField(this, "context", context);
|
|
14551
|
+
__publicField(this, "carried", carried);
|
|
14340
14552
|
__publicField(this, "count", 0);
|
|
14341
14553
|
__publicField(this, "position");
|
|
14342
14554
|
__publicField(this, "velocity");
|
|
@@ -14436,6 +14648,7 @@ var GameTestRoom = (() => {
|
|
|
14436
14648
|
}
|
|
14437
14649
|
update(dt, leaveDecal) {
|
|
14438
14650
|
const { position, velocity } = this;
|
|
14651
|
+
const confiner = this.context.confiner;
|
|
14439
14652
|
for (let index = this.count - 1; index >= 0; index--) {
|
|
14440
14653
|
this.life[index] -= dt;
|
|
14441
14654
|
if (this.life[index] <= 0) {
|
|
@@ -14449,9 +14662,25 @@ var GameTestRoom = (() => {
|
|
|
14449
14662
|
velocity[offset] *= factor;
|
|
14450
14663
|
velocity[offset + 1] *= factor;
|
|
14451
14664
|
velocity[offset + 2] *= factor;
|
|
14665
|
+
const x0 = position[offset];
|
|
14666
|
+
const y0 = position[offset + 1];
|
|
14667
|
+
const z0 = position[offset + 2];
|
|
14452
14668
|
position[offset] += velocity[offset] * dt;
|
|
14453
14669
|
position[offset + 1] += velocity[offset + 1] * dt;
|
|
14454
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
|
+
}
|
|
14455
14684
|
const mode = this.groundMode[index];
|
|
14456
14685
|
if (mode) {
|
|
14457
14686
|
const groundHeight = this.context.groundAt(position[offset], position[offset + 2]);
|
|
@@ -14728,9 +14957,9 @@ var GameTestRoom = (() => {
|
|
|
14728
14957
|
__publicField(this, "placement");
|
|
14729
14958
|
__publicField(this, "accumulators", /* @__PURE__ */ new Map());
|
|
14730
14959
|
const profile = options.profile ?? PROFILES.high;
|
|
14731
|
-
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 } : {} };
|
|
14732
14961
|
this.add = new SpritePool(profile.sprites.add, this.context);
|
|
14733
|
-
this.normal = new SpritePool(profile.sprites.normal, this.context);
|
|
14962
|
+
this.normal = new SpritePool(profile.sprites.normal, this.context, true);
|
|
14734
14963
|
this.streaks = new StreakPool(profile.streaks, this.context);
|
|
14735
14964
|
this.debris = new DebrisPool(this.context);
|
|
14736
14965
|
this.decals = new DecalPool(this.context);
|
|
@@ -14918,12 +15147,14 @@ var GameTestRoom = (() => {
|
|
|
14918
15147
|
const groundAt = options.groundAt ?? (ground ? (x, z) => ground.heightAt(x, z) : () => 0);
|
|
14919
15148
|
const handles = { next: 0, events: 0 };
|
|
14920
15149
|
const low = options.profile === "low";
|
|
15150
|
+
const enclosures = new Enclosures(20973 + (options.seed ?? 0));
|
|
14921
15151
|
const spriteSystem = new SpriteKindSystem({
|
|
14922
15152
|
capacity: options.sprites?.capacity ?? (low ? 1250 : 2500),
|
|
14923
15153
|
density: options.sprites?.density ?? (low ? 0.6 : 1),
|
|
14924
15154
|
seed: 2654435761 + (options.seed ?? 0),
|
|
14925
15155
|
groundAt,
|
|
14926
15156
|
gravity: options.gravity ?? DEFAULT_GRAVITY,
|
|
15157
|
+
confiner: enclosures,
|
|
14927
15158
|
...options.sprites?.kinds ? { kinds: options.sprites.kinds } : {}
|
|
14928
15159
|
});
|
|
14929
15160
|
const core = {
|
|
@@ -14973,7 +15204,7 @@ var GameTestRoom = (() => {
|
|
|
14973
15204
|
return [camera2.x, camera2.y, camera2.z];
|
|
14974
15205
|
}, forward: (local2) => [local2[0] ?? 0, local2[1] ?? 0, local2[2] ?? 0] };
|
|
14975
15206
|
function workshop() {
|
|
14976
|
-
return engine ?? (engine = new WorkshopEngine({ random: sharedRandom, profile, groundAt }));
|
|
15207
|
+
return engine ?? (engine = new WorkshopEngine({ random: sharedRandom, profile, groundAt, confiner: enclosures }));
|
|
14977
15208
|
}
|
|
14978
15209
|
function effectPlayer() {
|
|
14979
15210
|
return player ?? (player = createEffectPlayer({ engine: workshop(), effects, view }));
|
|
@@ -15032,6 +15263,10 @@ var GameTestRoom = (() => {
|
|
|
15032
15263
|
puff3.vz += dz * strength;
|
|
15033
15264
|
}
|
|
15034
15265
|
},
|
|
15266
|
+
enclose(id, enclosure) {
|
|
15267
|
+
enclosures.set(id, enclosure);
|
|
15268
|
+
},
|
|
15269
|
+
enclosures: () => enclosures,
|
|
15035
15270
|
stop(handle) {
|
|
15036
15271
|
player?.stop(handle);
|
|
15037
15272
|
const fires = core.fires;
|
|
@@ -15059,7 +15294,7 @@ var GameTestRoom = (() => {
|
|
|
15059
15294
|
core.clock.time += dt;
|
|
15060
15295
|
core.schedule.update(core.clock.time);
|
|
15061
15296
|
updateRings(core.rings, dt);
|
|
15062
|
-
updatePuffs(core.puffs, dt, wind);
|
|
15297
|
+
updatePuffs(core.puffs, dt, wind, enclosures);
|
|
15063
15298
|
updateSparks(core.sparks, { dt, groundAt });
|
|
15064
15299
|
updateGlows(core.glows, dt);
|
|
15065
15300
|
updateShocks(core.shocks, core.puffs.items, dt);
|
|
@@ -16459,6 +16694,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
16459
16694
|
});
|
|
16460
16695
|
},
|
|
16461
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),
|
|
16462
16699
|
configure(settings) {
|
|
16463
16700
|
const band = settings.lod_band;
|
|
16464
16701
|
if (typeof band === "string" && band in LOD_BANDS) world.forceLod(LOD_BANDS[band] ?? null);
|
|
@@ -18389,8 +18626,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
18389
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
|
|
18390
18627
|
* marked is gone (a unit came out of the wall with its bullet holes and spalls).
|
|
18391
18628
|
*/
|
|
18392
|
-
clearDecals(mv, center, half,
|
|
18393
|
-
const inv =
|
|
18629
|
+
clearDecals(mv, center, half, rotation2) {
|
|
18630
|
+
const inv = rotation2.clone().invert();
|
|
18394
18631
|
const p = new this.THREE.Vector3();
|
|
18395
18632
|
for (let i = mv.decals.length - 1; i >= 0; i--) {
|
|
18396
18633
|
const d = mv.decals[i];
|
|
@@ -19820,8 +20057,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
19820
20057
|
const T = this.THREE;
|
|
19821
20058
|
const center = new T.Vector3(ev.center[0], ev.center[1], ev.center[2]);
|
|
19822
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);
|
|
19823
|
-
const
|
|
19824
|
-
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);
|
|
19825
20062
|
this.vfx.peekWorkshop()?.decals.clearInside(ev.center, [half.x, half.y, half.z], ev.rotation);
|
|
19826
20063
|
this.vfx.burst("dust", ev.center, [0, 1, 0], 8, 0.8, { color });
|
|
19827
20064
|
this.sound(impactKey(def), ev.center, 0.7);
|
|
@@ -36139,11 +36376,11 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
36139
36376
|
for (const key2 of Object.keys(c.streams)) endStreamKey(c, key2);
|
|
36140
36377
|
containers.delete(id);
|
|
36141
36378
|
},
|
|
36142
|
-
setTransform(id, position,
|
|
36379
|
+
setTransform(id, position, rotation2, velocity) {
|
|
36143
36380
|
const c = containers.get(id);
|
|
36144
36381
|
if (!c) return;
|
|
36145
36382
|
c.position = copy3(position);
|
|
36146
|
-
c.rotation = [...
|
|
36383
|
+
c.rotation = [...rotation2];
|
|
36147
36384
|
if (velocity) c.velocity = copy3(velocity);
|
|
36148
36385
|
refreshLevel(c);
|
|
36149
36386
|
},
|
|
@@ -37065,10 +37302,10 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
37065
37302
|
const hand = getHandTransform();
|
|
37066
37303
|
const p = pose();
|
|
37067
37304
|
const position = add2(hand.position, quatRotate(hand.rotation, p.position));
|
|
37068
|
-
const
|
|
37305
|
+
const rotation2 = quatMultiply(hand.rotation, quatFromEuler2(p.rotation[0], p.rotation[1], p.rotation[2]));
|
|
37069
37306
|
const velocity = lastPos && dt > 0 ? [(position[0] - lastPos[0]) / dt, (position[1] - lastPos[1]) / dt, (position[2] - lastPos[2]) / dt] : void 0;
|
|
37070
37307
|
lastPos = position;
|
|
37071
|
-
world.setTransform(containerId, position,
|
|
37308
|
+
world.setTransform(containerId, position, rotation2, velocity);
|
|
37072
37309
|
};
|
|
37073
37310
|
const player = {
|
|
37074
37311
|
def,
|
|
@@ -39097,7 +39334,7 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
39097
39334
|
const direction = new THREE.Vector3();
|
|
39098
39335
|
const location = new THREE.Vector3();
|
|
39099
39336
|
const scale2 = new THREE.Vector3();
|
|
39100
|
-
const
|
|
39337
|
+
const rotation2 = new THREE.Quaternion();
|
|
39101
39338
|
const matrix = new THREE.Matrix4();
|
|
39102
39339
|
return {
|
|
39103
39340
|
drops,
|
|
@@ -39117,9 +39354,9 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
39117
39354
|
const o = i * 3;
|
|
39118
39355
|
const speed = Math.hypot(velocity[o], velocity[o + 1], velocity[o + 2]);
|
|
39119
39356
|
direction.set(velocity[o], velocity[o + 1], velocity[o + 2]).normalize();
|
|
39120
|
-
|
|
39357
|
+
rotation2.setFromUnitVectors(up, direction);
|
|
39121
39358
|
const size = radius[i] * METRES_PER_MM;
|
|
39122
|
-
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));
|
|
39123
39360
|
drops.setMatrixAt(i, matrix);
|
|
39124
39361
|
drawn++;
|
|
39125
39362
|
}
|
|
@@ -42661,7 +42898,7 @@ void main(){
|
|
|
42661
42898
|
var NEAR_OPEN_LEAF = 0.9;
|
|
42662
42899
|
var BODY_HEIGHT = 1.8;
|
|
42663
42900
|
var HAND_REST = [0.22, -0.42, -0.32];
|
|
42664
|
-
var
|
|
42901
|
+
var SKIN2 = 0.01;
|
|
42665
42902
|
var HANDLE_INSET = 0.06;
|
|
42666
42903
|
var STANDOFF2 = 0.55;
|
|
42667
42904
|
var DRAWER_TRAVEL = 0.3;
|
|
@@ -42805,7 +43042,7 @@ void main(){
|
|
|
42805
43042
|
const o = outs[0];
|
|
42806
43043
|
return [o[1] * (o[0] + PLAYER_RADIUS), o[2] * (o[0] + PLAYER_RADIUS)];
|
|
42807
43044
|
}
|
|
42808
|
-
const push = PLAYER_RADIUS - d +
|
|
43045
|
+
const push = PLAYER_RADIUS - d + SKIN2;
|
|
42809
43046
|
return [dx / d * push, dz / d * push];
|
|
42810
43047
|
};
|
|
42811
43048
|
const isFree = (u, from, to) => {
|
|
@@ -42815,7 +43052,7 @@ void main(){
|
|
|
42815
43052
|
options.pose(objectId, leaf2.part, leaf2.clip, to);
|
|
42816
43053
|
obj.updateMatrixWorld(true);
|
|
42817
43054
|
box2.setFromObject(obj);
|
|
42818
|
-
box2.expandByScalar(-
|
|
43055
|
+
box2.expandByScalar(-SKIN2);
|
|
42819
43056
|
let by = null;
|
|
42820
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";
|
|
42821
43058
|
else
|
|
@@ -42833,7 +43070,7 @@ void main(){
|
|
|
42833
43070
|
const dir = [tmp.x - centre.x, tmp.y - centre.y, tmp.z - centre.z];
|
|
42834
43071
|
const len = Math.hypot(dir[0], dir[1], dir[2]);
|
|
42835
43072
|
if (len > 1e-5) {
|
|
42836
|
-
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 });
|
|
42837
43074
|
if (hit && hit.normal[1] < 0.7) by = hit.object;
|
|
42838
43075
|
}
|
|
42839
43076
|
}
|
|
@@ -43121,6 +43358,7 @@ void main(){
|
|
|
43121
43358
|
debris: "chips",
|
|
43122
43359
|
color: [0.05, 0.05, 0.055],
|
|
43123
43360
|
pattern: "asphalt",
|
|
43361
|
+
crack: { reach: 0.6, width: 8e-3, thresholdJoules: 800 },
|
|
43124
43362
|
hits: {
|
|
43125
43363
|
ballistic: { specificEnergy: 3e7, aspect: 0.2, minRadius: 0.03 },
|
|
43126
43364
|
blunt: { specificEnergy: 1e8, aspect: 0.1, thresholdJoules: 400 },
|
|
@@ -43134,6 +43372,8 @@ void main(){
|
|
|
43134
43372
|
debris: "chips",
|
|
43135
43373
|
color: [0.33, 0.33, 0.31],
|
|
43136
43374
|
pattern: "concrete",
|
|
43375
|
+
crack: { reach: 1, width: 6e-3, thresholdJoules: 300 },
|
|
43376
|
+
breach: { joulesPerCubedThickness: 24e8, radiusOverThickness: 1.5 },
|
|
43137
43377
|
hits: {
|
|
43138
43378
|
ballistic: { specificEnergy: 15e7, aspect: 0.14, minRadius: 0.018 },
|
|
43139
43379
|
blunt: { specificEnergy: 3e8, aspect: 0.08, thresholdJoules: 800 },
|
|
@@ -43160,6 +43400,7 @@ void main(){
|
|
|
43160
43400
|
debris: "shards",
|
|
43161
43401
|
color: [0.72, 0.7, 0.66],
|
|
43162
43402
|
pattern: "tile",
|
|
43403
|
+
crack: { reach: 0.5, width: 2e-3, thresholdJoules: 40 },
|
|
43163
43404
|
hits: {
|
|
43164
43405
|
ballistic: { specificEnergy: 8e6, aspect: 0.1, minRadius: 0.05 },
|
|
43165
43406
|
blunt: { specificEnergy: 1e7, aspect: 0.08, thresholdJoules: 80, minRadius: 0.06 },
|
|
@@ -43186,6 +43427,7 @@ void main(){
|
|
|
43186
43427
|
debris: "chips",
|
|
43187
43428
|
color: [0.23, 0.22, 0.2],
|
|
43188
43429
|
pattern: "stone",
|
|
43430
|
+
crack: { reach: 0.5, width: 4e-3, thresholdJoules: 1e3 },
|
|
43189
43431
|
hits: {
|
|
43190
43432
|
ballistic: { specificEnergy: 25e7, aspect: 0.12, minRadius: 0.015 },
|
|
43191
43433
|
blunt: { specificEnergy: 5e8, aspect: 0.08, thresholdJoules: 1500 },
|
|
@@ -43208,6 +43450,91 @@ void main(){
|
|
|
43208
43450
|
];
|
|
43209
43451
|
var DEFAULT_BAR_YIELD_JOULES = 24e5;
|
|
43210
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
|
+
}
|
|
43211
43538
|
var REST_SPEED2 = 0.6;
|
|
43212
43539
|
var RESTITUTION2 = 0.25;
|
|
43213
43540
|
var FRICTION = 0.55;
|
|
@@ -43385,15 +43712,6 @@ void main(){
|
|
|
43385
43712
|
}
|
|
43386
43713
|
};
|
|
43387
43714
|
}
|
|
43388
|
-
function createRandom(seed) {
|
|
43389
|
-
let state = seed | 0;
|
|
43390
|
-
return () => {
|
|
43391
|
-
state = state + 1831565813 | 0;
|
|
43392
|
-
let mixed = Math.imul(state ^ state >>> 15, 1 | state);
|
|
43393
|
-
mixed = mixed + Math.imul(mixed ^ mixed >>> 7, 61 | mixed) ^ mixed;
|
|
43394
|
-
return ((mixed ^ mixed >>> 14) >>> 0) / 4294967296;
|
|
43395
|
-
};
|
|
43396
|
-
}
|
|
43397
43715
|
var DEFAULT_TERRAIN_BUDGET = {
|
|
43398
43716
|
markAreaSize: 2,
|
|
43399
43717
|
maxMarksPerArea: 24,
|
|
@@ -43402,7 +43720,8 @@ void main(){
|
|
|
43402
43720
|
maxDebris: 400,
|
|
43403
43721
|
maxDebrisPerBlow: 36,
|
|
43404
43722
|
maxSlideCellsPerFrame: 2500,
|
|
43405
|
-
maxBurningCells: 300
|
|
43723
|
+
maxBurningCells: 300,
|
|
43724
|
+
maxCracks: 120
|
|
43406
43725
|
};
|
|
43407
43726
|
var GRAVITY5 = 9.81;
|
|
43408
43727
|
var FINE_CELLS = 1.5;
|
|
@@ -43479,6 +43798,7 @@ void main(){
|
|
|
43479
43798
|
const mixed = new Uint8Array(chunksX * chunksZ);
|
|
43480
43799
|
const dirty = /* @__PURE__ */ new Set();
|
|
43481
43800
|
const marks = createMarkStore2(budget);
|
|
43801
|
+
const cracks = createCrackStore();
|
|
43482
43802
|
const debrisStore = createDebrisStore(() => budget.maxDebris);
|
|
43483
43803
|
const sliding = /* @__PURE__ */ new Set();
|
|
43484
43804
|
const burning = /* @__PURE__ */ new Map();
|
|
@@ -43655,6 +43975,7 @@ void main(){
|
|
|
43655
43975
|
let depth = start.depth;
|
|
43656
43976
|
let radius = 0;
|
|
43657
43977
|
let carved = 0;
|
|
43978
|
+
let breached = false;
|
|
43658
43979
|
const firstMaterial = materials.get(start.material);
|
|
43659
43980
|
if (start.loose <= 0) {
|
|
43660
43981
|
for (; ; ) {
|
|
@@ -43666,6 +43987,19 @@ void main(){
|
|
|
43666
43987
|
const response = material.hits[blow3];
|
|
43667
43988
|
if (!response || energy < (response.thresholdJoules ?? 0)) break;
|
|
43668
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
|
+
}
|
|
43669
44003
|
const pastCover = bars !== void 0 && depth - layer2.top >= bars.cover - 1e-6;
|
|
43670
44004
|
const specificEnergy = response.specificEnergy * (pastCover ? bars.resistance : 1);
|
|
43671
44005
|
const limit = bars && !pastCover ? Math.min(room, layer2.top + bars.cover - depth) : room;
|
|
@@ -43693,8 +44027,10 @@ void main(){
|
|
|
43693
44027
|
removed.push({ material: firstMaterial.id, volume });
|
|
43694
44028
|
}
|
|
43695
44029
|
}
|
|
43696
|
-
|
|
43697
|
-
|
|
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 };
|
|
43698
44034
|
if (firstMaterial.reposeDegrees === void 0 && start.loose <= 0) radius *= 1 + RIGID_WIDENING * (start.depth / maxDepthOfProfile(profile));
|
|
43699
44035
|
const volumeTotal = removed.reduce((sum2, entry) => sum2 + entry.volume, 0);
|
|
43700
44036
|
const fine = radius < cellSize * FINE_CELLS;
|
|
@@ -43712,8 +44048,16 @@ void main(){
|
|
|
43712
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 });
|
|
43713
44049
|
quota -= share;
|
|
43714
44050
|
}
|
|
44051
|
+
if (breached) collapsed = loadBars(blow3, spec.energy, x, z, profile) || collapsed;
|
|
43715
44052
|
const after2 = columnAt(x, z);
|
|
43716
|
-
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);
|
|
43717
44061
|
}
|
|
43718
44062
|
function loadBars(blow3, energy, x, z, profile) {
|
|
43719
44063
|
const bars = profile.strata.find((stratum) => stratum.reinforcement);
|
|
@@ -43954,6 +44298,7 @@ void main(){
|
|
|
43954
44298
|
barBend.fill(0);
|
|
43955
44299
|
touched.fill(0);
|
|
43956
44300
|
marks.clear();
|
|
44301
|
+
cracks.clear();
|
|
43957
44302
|
debrisStore.clear();
|
|
43958
44303
|
sliding.clear();
|
|
43959
44304
|
burning.clear();
|
|
@@ -44005,6 +44350,9 @@ void main(){
|
|
|
44005
44350
|
updateSlides();
|
|
44006
44351
|
updateFire(dt);
|
|
44007
44352
|
},
|
|
44353
|
+
get dirtyChunkCount() {
|
|
44354
|
+
return dirty.size;
|
|
44355
|
+
},
|
|
44008
44356
|
drainDirtyChunks(max2 = budget.maxDirtyChunksPerFrame) {
|
|
44009
44357
|
const taken = [];
|
|
44010
44358
|
for (const index of dirty) {
|
|
@@ -44016,6 +44364,10 @@ void main(){
|
|
|
44016
44364
|
},
|
|
44017
44365
|
chunk,
|
|
44018
44366
|
marks: () => marks.list,
|
|
44367
|
+
cracks: () => cracks.list,
|
|
44368
|
+
get cracksVersion() {
|
|
44369
|
+
return cracks.version;
|
|
44370
|
+
},
|
|
44019
44371
|
debris: () => debrisStore.list,
|
|
44020
44372
|
burningPoints: () => [...burning.keys()].map((key2) => {
|
|
44021
44373
|
const cellRow = Math.floor(key2 / 65536);
|
|
@@ -44028,7 +44380,7 @@ void main(){
|
|
|
44028
44380
|
stats: () => ({ marks: marks.list.length, debris: debrisStore.list.length, debrisMoving: debrisStore.list.filter((piece) => !piece.atRest).length, dirtyChunks: dirty.size, burning: burning.size }),
|
|
44029
44381
|
reset,
|
|
44030
44382
|
serialize() {
|
|
44031
|
-
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 })) };
|
|
44032
44384
|
},
|
|
44033
44385
|
load(snapshot) {
|
|
44034
44386
|
currentLayout = snapshot.layout;
|
|
@@ -44038,6 +44390,7 @@ void main(){
|
|
|
44038
44390
|
fillSparse(scorch, snapshot.scorch);
|
|
44039
44391
|
fillSparse(barBend, snapshot.barBend ?? []);
|
|
44040
44392
|
marks.load(snapshot.marks);
|
|
44393
|
+
cracks.load(snapshot.cracks ?? []);
|
|
44041
44394
|
for (let chunkIndex = 0; chunkIndex < touched.length; chunkIndex++) markChunk(chunkIndex);
|
|
44042
44395
|
}
|
|
44043
44396
|
};
|
|
@@ -44382,7 +44735,7 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
44382
44735
|
mesh2.renderOrder = 1;
|
|
44383
44736
|
mesh2.setColorAt(0, new THREE.Color(1, 1, 1));
|
|
44384
44737
|
const matrix = new THREE.Matrix4();
|
|
44385
|
-
const
|
|
44738
|
+
const rotation2 = new THREE.Matrix4();
|
|
44386
44739
|
const scale2 = new THREE.Matrix4();
|
|
44387
44740
|
const colour = new THREE.Color();
|
|
44388
44741
|
let seen = "";
|
|
@@ -44403,9 +44756,9 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
44403
44756
|
for (const mark of marks) {
|
|
44404
44757
|
if (Math.hypot(mark.x - camera2.x, mark.z - camera2.z) > drawDistance) continue;
|
|
44405
44758
|
const size = mark.radius * 2 * MARK_REACH;
|
|
44406
|
-
|
|
44759
|
+
rotation2.makeRotationY(mark.id * 2.399);
|
|
44407
44760
|
scale2.makeScale(size, 1, size);
|
|
44408
|
-
matrix.multiplyMatrices(
|
|
44761
|
+
matrix.multiplyMatrices(rotation2, scale2);
|
|
44409
44762
|
matrix.setPosition(mark.x, terrain.heightAt(mark.x, mark.z) + MARK_LIFT, mark.z);
|
|
44410
44763
|
mesh2.setMatrixAt(count, matrix);
|
|
44411
44764
|
const [r, g, b] = terrain.material(mark.material).color;
|
|
@@ -44469,6 +44822,92 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
44469
44822
|
}
|
|
44470
44823
|
};
|
|
44471
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
|
+
}
|
|
44472
44911
|
var BAR_RADIUS = 6e-3;
|
|
44473
44912
|
var EXPOSED_MARGIN = 2e-3;
|
|
44474
44913
|
var MAX_SAG = 0.07;
|
|
@@ -44583,7 +45022,8 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
44583
45022
|
const drawn = /* @__PURE__ */ new Map();
|
|
44584
45023
|
const marks = createMarkLayer2(THREE, terrain, options.markDistance ?? DEFAULT_MARK_DISTANCE);
|
|
44585
45024
|
const debris2 = createDebrisLayer(THREE, terrain);
|
|
44586
|
-
|
|
45025
|
+
const cracks = createCrackLayer(THREE, terrain);
|
|
45026
|
+
group.add(marks.mesh, cracks.mesh, debris2.mesh);
|
|
44587
45027
|
let pristineStale = true;
|
|
44588
45028
|
let pristineBuilt = false;
|
|
44589
45029
|
let pristineCount = 0;
|
|
@@ -44669,7 +45109,8 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
44669
45109
|
return {
|
|
44670
45110
|
group,
|
|
44671
45111
|
sync(camera2) {
|
|
44672
|
-
const
|
|
45112
|
+
const laidAnew = terrain.dirtyChunkCount >= terrain.chunksX * terrain.chunksZ;
|
|
45113
|
+
const limit = firstSync || laidAnew ? Infinity : void 0;
|
|
44673
45114
|
firstSync = false;
|
|
44674
45115
|
for (const chunk of terrain.drainDirtyChunks(limit)) {
|
|
44675
45116
|
if (chunk.pristine) {
|
|
@@ -44690,9 +45131,10 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
44690
45131
|
}
|
|
44691
45132
|
}
|
|
44692
45133
|
marks.sync(camera2);
|
|
45134
|
+
cracks.sync();
|
|
44693
45135
|
debris2.sync();
|
|
44694
45136
|
},
|
|
44695
|
-
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 }),
|
|
44696
45138
|
dispose() {
|
|
44697
45139
|
for (const index of [...drawn.keys()]) drop(index);
|
|
44698
45140
|
for (const geometry of spareGeometries) geometry.dispose();
|
|
@@ -44700,11 +45142,19 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
44700
45142
|
surface.dispose();
|
|
44701
45143
|
rebarMaterial.dispose();
|
|
44702
45144
|
marks.dispose();
|
|
45145
|
+
cracks.dispose();
|
|
44703
45146
|
debris2.dispose();
|
|
44704
45147
|
group.removeFromParent();
|
|
44705
45148
|
}
|
|
44706
45149
|
};
|
|
44707
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
|
+
}
|
|
44708
45158
|
var TERRAIN_STRIPS = ["dirt", "lawn", "sand", "road", "concrete_slab", "suspended_slab", "wood_floor", "tile_floor", "stone_paving"];
|
|
44709
45159
|
var STRIP_WIDTH = 3;
|
|
44710
45160
|
var STRIP_Z0 = 4;
|
|
@@ -45087,6 +45537,8 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
45087
45537
|
"ins.damage": "Marks",
|
|
45088
45538
|
"ins.damage_counts": "{dents}, {holes}, {cracks}",
|
|
45089
45539
|
"ins.mass": "Mass",
|
|
45540
|
+
"ins.dug": "Dug",
|
|
45541
|
+
"ins.dig_limit": "Ground left to dig",
|
|
45090
45542
|
"ins.load": "Load",
|
|
45091
45543
|
"ins.stress": "Stress",
|
|
45092
45544
|
"ins.joints": "Joints",
|
|
@@ -45435,6 +45887,8 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
45435
45887
|
"ins.damage": "Marcas",
|
|
45436
45888
|
"ins.damage_counts": "{dents}, {holes}, {cracks}",
|
|
45437
45889
|
"ins.mass": "Massa",
|
|
45890
|
+
"ins.dug": "Escavado",
|
|
45891
|
+
"ins.dig_limit": "Ch\xE3o at\xE9 o limite",
|
|
45438
45892
|
"ins.load": "Carga",
|
|
45439
45893
|
"ins.stress": "Tens\xE3o",
|
|
45440
45894
|
"ins.joints": "Juntas",
|
|
@@ -46322,6 +46776,15 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
46322
46776
|
insp.appendChild(mk3("div", void 0, t("ui.aim_at_something")));
|
|
46323
46777
|
return;
|
|
46324
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
|
+
}
|
|
46325
46788
|
if (i.thumbnail) insp.appendChild(thumb(i.thumbnail, i.thumbnailCredit));
|
|
46326
46789
|
insp.appendChild(mk3("div", "t", `${i.object} \u203A ${i.part}`));
|
|
46327
46790
|
insp.appendChild(row(t("ins.material"), i.material));
|
|
@@ -48680,9 +49143,36 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
48680
49143
|
if (!leaf2) return void 0;
|
|
48681
49144
|
return t(leaf2.locked ? "hud.door_hint_locked" : leaf2.open ? "hud.door_hint_close" : "hud.door_hint_open");
|
|
48682
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
|
+
};
|
|
48683
49172
|
const inspectInfo = () => {
|
|
48684
49173
|
const r = inspectTarget();
|
|
48685
49174
|
if (!r) return null;
|
|
49175
|
+
if (r.object === GROUND_ID2) return groundInspect(r);
|
|
48686
49176
|
const st = world.state(r.object);
|
|
48687
49177
|
const p = world.part(r.object, r.part);
|
|
48688
49178
|
if (!st || !p) return null;
|