@adatechnology/game-floorplan-three 0.6.0 → 0.7.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.global.js +198 -71
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +182 -66
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
package/dist/index.js
CHANGED
|
@@ -6251,6 +6251,19 @@ function restoreRange(mesh, v0, saved) {
|
|
|
6251
6251
|
pos.array.set(saved, v0 * 3);
|
|
6252
6252
|
pos.needsUpdate = true;
|
|
6253
6253
|
}
|
|
6254
|
+
function noise2(x, y, cell) {
|
|
6255
|
+
const h = (i2, j2) => {
|
|
6256
|
+
const s = Math.sin(i2 * 127.1 + j2 * 311.7) * 43758.5453;
|
|
6257
|
+
return s - Math.floor(s);
|
|
6258
|
+
};
|
|
6259
|
+
const fx = x / cell, fy = y / cell, i = Math.floor(fx), j = Math.floor(fy), u = fx - i, v = fy - j;
|
|
6260
|
+
const su = u * u * (3 - 2 * u), sv = v * v * (3 - 2 * v);
|
|
6261
|
+
return (h(i, j) * (1 - su) + h(i + 1, j) * su) * (1 - sv) + (h(i, j + 1) * (1 - su) + h(i + 1, j + 1) * su) * sv;
|
|
6262
|
+
}
|
|
6263
|
+
var MASK_TEXEL = 0.02;
|
|
6264
|
+
var SPALL_MIN = 0.025;
|
|
6265
|
+
var SPALL_RAGGED = 0.045;
|
|
6266
|
+
var COVER = 0.015;
|
|
6254
6267
|
function installDestructionBreach(K, _shared) {
|
|
6255
6268
|
const { THREE, fragmentMaterial, invalidate, invalidateShadow } = K;
|
|
6256
6269
|
function createBreachView(opts) {
|
|
@@ -6260,55 +6273,29 @@ function installDestructionBreach(K, _shared) {
|
|
|
6260
6273
|
const unitMaterial = new THREE.MeshLambertMaterial({ color: 16777215 });
|
|
6261
6274
|
const unitGeometry = new THREE.BoxGeometry(1, 1, 1);
|
|
6262
6275
|
const tmp = { m: new THREE.Matrix4(), q: new THREE.Quaternion(), p: new THREE.Vector3(), s: new THREE.Vector3(), c: new THREE.Color() };
|
|
6263
|
-
const wallColour = (items) => {
|
|
6264
|
-
for (const it of items) {
|
|
6265
|
-
if (!it.mesh) continue;
|
|
6266
|
-
const c = it.mesh.geometry.attributes.color;
|
|
6267
|
-
if (!c) continue;
|
|
6268
|
-
const a = c.array;
|
|
6269
|
-
tmp.c.setRGB(a[it.v0 * 3], a[it.v0 * 3 + 1], a[it.v0 * 3 + 2]);
|
|
6270
|
-
return tmp.c.getHex();
|
|
6271
|
-
}
|
|
6272
|
-
return null;
|
|
6273
|
-
};
|
|
6274
6276
|
const local = (p) => {
|
|
6275
6277
|
house.updateMatrixWorld(true);
|
|
6276
6278
|
const v = house.worldToLocal(tmp.p.set(p[0], p[1], p[2]));
|
|
6277
6279
|
return [v.x, v.y, v.z];
|
|
6278
6280
|
};
|
|
6279
|
-
function
|
|
6281
|
+
function cells(part, units) {
|
|
6280
6282
|
const [u0, v0, u1, v1] = part.aabb;
|
|
6281
6283
|
const alongU = u1 - u0 >= v1 - v0;
|
|
6282
6284
|
const len = alongU ? u1 - u0 : v1 - v0;
|
|
6283
|
-
const thick = alongU ? v1 - v0 : u1 - u0;
|
|
6284
6285
|
const [ul, uh] = units.size;
|
|
6285
6286
|
const rows = Math.max(1, Math.round((part.y1 - part.y0) / uh));
|
|
6286
6287
|
const rowH = (part.y1 - part.y0) / rows;
|
|
6287
6288
|
const per = Math.max(1, Math.round(len / ul));
|
|
6288
6289
|
const w = len / per;
|
|
6289
|
-
const
|
|
6290
|
-
const list = [];
|
|
6290
|
+
const out = [];
|
|
6291
6291
|
for (let r = 0; r < rows; r++) {
|
|
6292
6292
|
const shift = units.bond === "running" && r & 1 ? w / 2 : 0;
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
a = Math.max(0, a);
|
|
6297
|
-
b = Math.min(len, b);
|
|
6298
|
-
if (b - a < 1e-3) continue;
|
|
6299
|
-
const mid = (a + b) / 2;
|
|
6300
|
-
const x = alongU ? u0 + mid : (u0 + u1) / 2;
|
|
6301
|
-
const z = alongU ? (v0 + v1) / 2 : v0 + mid;
|
|
6302
|
-
const y = part.y0 + (r + 0.5) * rowH;
|
|
6303
|
-
const d = opening ? Math.hypot(x - opening.center[0], y - opening.center[1], z - opening.center[2]) : Infinity;
|
|
6304
|
-
if (opening && d < opening.radius) continue;
|
|
6305
|
-
const gone = (c) => Math.abs(c[1] - y) <= rowH / 2 && (alongU ? c[0] >= u0 + a && c[0] <= u0 + b : c[2] >= v0 + a && c[2] <= v0 + b);
|
|
6306
|
-
if (chips.some(gone)) continue;
|
|
6307
|
-
const near = opening && d < opening.radius + 0.25 || chips.some((c) => Math.hypot(c[0] - x, c[1] - y, c[2] - z) < 0.15);
|
|
6308
|
-
list.push({ x, y, z, sx: alongU ? b - a : thick, sy: rowH, sz: alongU ? thick : b - a, colour: near || paint === null ? edge : paint });
|
|
6293
|
+
for (let i = 0; i < per + (shift ? 1 : 0); i++) {
|
|
6294
|
+
const a = Math.max(0, i * w - shift), b = Math.min(len, i * w - shift + w);
|
|
6295
|
+
if (b - a > 1e-3) out.push({ a, b, y0: part.y0 + r * rowH, y1: part.y0 + (r + 1) * rowH, r, i });
|
|
6309
6296
|
}
|
|
6310
6297
|
}
|
|
6311
|
-
return
|
|
6298
|
+
return out;
|
|
6312
6299
|
}
|
|
6313
6300
|
const specOf = (id) => opts.spec()?.parts?.find((q) => q.id === id);
|
|
6314
6301
|
const same = (a, b) => a.every((x, k) => Math.abs(x - b[k]) < 1e-3);
|
|
@@ -6322,6 +6309,137 @@ function installDestructionBreach(K, _shared) {
|
|
|
6322
6309
|
return null;
|
|
6323
6310
|
}
|
|
6324
6311
|
const riders = (hostId) => structure.parts.filter((q) => q.id !== hostId && specOf(q.id)?.units && hostOf(q.id) === hostId && !structure.meshesOf(q.id).some((it) => it.mesh)).map((q) => q.id);
|
|
6312
|
+
function shell(it, mask) {
|
|
6313
|
+
const g0 = it.mesh.geometry, g = new THREE.BufferGeometry();
|
|
6314
|
+
const src = it.mesh.userData._p0 || g0.attributes.position.array;
|
|
6315
|
+
for (const [name, attr] of Object.entries(g0.attributes)) {
|
|
6316
|
+
const k = attr.itemSize;
|
|
6317
|
+
g.setAttribute(name, new THREE.BufferAttribute((name === "position" ? src : attr.array).slice(it.v0 * k, it.v1 * k), k));
|
|
6318
|
+
}
|
|
6319
|
+
if (g0.index) {
|
|
6320
|
+
const ix = g0.index.array.slice(it.i0, it.i1);
|
|
6321
|
+
for (let k = 0; k < ix.length; k++) ix[k] -= it.v0;
|
|
6322
|
+
g.setIndex(new THREE.BufferAttribute(ix, 1));
|
|
6323
|
+
}
|
|
6324
|
+
g.computeBoundingBox();
|
|
6325
|
+
g.computeBoundingSphere();
|
|
6326
|
+
const base = it.mesh.material;
|
|
6327
|
+
const material = base.clone();
|
|
6328
|
+
const toHouse = { value: new THREE.Matrix4() };
|
|
6329
|
+
material.onBeforeCompile = (sh) => {
|
|
6330
|
+
base.onBeforeCompile?.(sh);
|
|
6331
|
+
sh.uniforms.uToHouse = toHouse;
|
|
6332
|
+
sh.uniforms.uMask = { value: mask.texture };
|
|
6333
|
+
sh.uniforms.uMaskRect = { value: mask.rect };
|
|
6334
|
+
sh.uniforms.uMaskAlongX = { value: mask.alongU ? 1 : 0 };
|
|
6335
|
+
sh.vertexShader = sh.vertexShader.replace("void main() {", "uniform mat4 uToHouse;\nvarying vec3 vHousePos;\nvoid main() {").replace("#include <begin_vertex>", "#include <begin_vertex>\nvHousePos = (uToHouse * vec4(transformed, 1.0)).xyz;");
|
|
6336
|
+
sh.fragmentShader = sh.fragmentShader.replace("void main() {", "uniform sampler2D uMask;\nuniform vec4 uMaskRect;\nuniform float uMaskAlongX;\nvarying vec3 vHousePos;\nvoid main() {\n vec2 mUv = vec2(((uMaskAlongX > 0.5 ? vHousePos.x : vHousePos.z) - uMaskRect.x) / uMaskRect.z, (vHousePos.y - uMaskRect.y) / uMaskRect.w);\n if (mUv.x >= 0.0 && mUv.x <= 1.0 && mUv.y >= 0.0 && mUv.y <= 1.0 && texture2D(uMask, mUv).r > 0.5) discard;");
|
|
6337
|
+
};
|
|
6338
|
+
material.customProgramCacheKey = () => "breachMask" + (base.customProgramCacheKey?.() ?? "");
|
|
6339
|
+
const mesh = new THREE.Mesh(g, material);
|
|
6340
|
+
mesh.name = "breach-shell";
|
|
6341
|
+
mesh.userData.breachMask = mask;
|
|
6342
|
+
mesh.position.copy(it.mesh.position);
|
|
6343
|
+
mesh.quaternion.copy(it.mesh.quaternion);
|
|
6344
|
+
mesh.scale.copy(it.mesh.scale);
|
|
6345
|
+
mesh.castShadow = it.mesh.castShadow;
|
|
6346
|
+
mesh.receiveShadow = it.mesh.receiveShadow;
|
|
6347
|
+
mesh.renderOrder = it.mesh.renderOrder;
|
|
6348
|
+
mesh.onBeforeRender = () => {
|
|
6349
|
+
house.updateMatrixWorld();
|
|
6350
|
+
toHouse.value.copy(house.matrixWorld).invert().multiply(mesh.matrixWorld);
|
|
6351
|
+
};
|
|
6352
|
+
it.mesh.parent.add(mesh);
|
|
6353
|
+
mesh.updateMatrixWorld(true);
|
|
6354
|
+
toHouse.value.copy(house.matrixWorld).invert().multiply(mesh.matrixWorld);
|
|
6355
|
+
return mesh;
|
|
6356
|
+
}
|
|
6357
|
+
function maskOf(hostId, parts) {
|
|
6358
|
+
const host = structure.byId.get(hostId);
|
|
6359
|
+
const [u0, v0, u1, v1] = host.aabb;
|
|
6360
|
+
const alongU = u1 - u0 >= v1 - v0;
|
|
6361
|
+
const y0 = Math.min(...parts.map((id) => structure.byId.get(id).y0)), y1 = Math.max(...parts.map((id) => structure.byId.get(id).y1));
|
|
6362
|
+
const len = alongU ? u1 - u0 : v1 - v0;
|
|
6363
|
+
const w = Math.max(2, Math.min(2048, Math.ceil(len / MASK_TEXEL))), h = Math.max(2, Math.min(1024, Math.ceil((y1 - y0) / MASK_TEXEL)));
|
|
6364
|
+
const data = new Uint8Array(w * h);
|
|
6365
|
+
const texture = new THREE.DataTexture(data, w, h, THREE.RedFormat);
|
|
6366
|
+
texture.magFilter = THREE.LinearFilter;
|
|
6367
|
+
texture.minFilter = THREE.LinearFilter;
|
|
6368
|
+
texture.needsUpdate = true;
|
|
6369
|
+
return { data, texture, w, h, alongU, start: alongU ? u0 : v0, len, y0, height: y1 - y0, rect: new THREE.Vector4(alongU ? u0 : v0, y0, len, y1 - y0) };
|
|
6370
|
+
}
|
|
6371
|
+
const boxDistance = (s, y, a, b, c, d) => Math.hypot(Math.max(a - s, 0, s - b), Math.max(c - y, 0, y - d));
|
|
6372
|
+
function paint(view) {
|
|
6373
|
+
const { mask } = view;
|
|
6374
|
+
const along = (p) => (mask.alongU ? p[0] : p[2]) - mask.start;
|
|
6375
|
+
const holes = [];
|
|
6376
|
+
const discs = [];
|
|
6377
|
+
const shown = [];
|
|
6378
|
+
for (const id of view.parts) {
|
|
6379
|
+
const part = structure.byId.get(id), units2 = specOf(id).units, chips = view.chips.get(id), opening = view.openings.get(id);
|
|
6380
|
+
const all = cells(part, units2);
|
|
6381
|
+
const thick = mask.alongU ? part.aabb[3] - part.aabb[1] : part.aabb[2] - part.aabb[0];
|
|
6382
|
+
const mid = mask.alongU ? (part.aabb[1] + part.aabb[3]) / 2 : (part.aabb[0] + part.aabb[2]) / 2;
|
|
6383
|
+
if (opening) discs.push({ s: along(opening.center), y: opening.center[1], r: opening.radius });
|
|
6384
|
+
const gone = (c) => chips.some((p) => p[1] >= c.y0 && p[1] <= c.y1 && along(p) >= c.a && along(p) <= c.b) || opening && Math.hypot((c.a + c.b) / 2 - along(opening.center), (c.y0 + c.y1) / 2 - opening.center[1]) < opening.radius;
|
|
6385
|
+
const kept = [];
|
|
6386
|
+
for (const c of all) (gone(c) ? holes : kept).push(c);
|
|
6387
|
+
for (const c of kept) shown.push({ c, part, units: units2, thick, mid });
|
|
6388
|
+
}
|
|
6389
|
+
const reach = SPALL_MIN + SPALL_RAGGED;
|
|
6390
|
+
mask.data.fill(0);
|
|
6391
|
+
const stamp = (s0, s1, y0, y1, inside) => {
|
|
6392
|
+
const i0 = Math.max(0, Math.floor((s0 - reach) / mask.len * mask.w)), i1 = Math.min(mask.w - 1, Math.ceil((s1 + reach) / mask.len * mask.w));
|
|
6393
|
+
const j0 = Math.max(0, Math.floor((y0 - reach - mask.y0) / mask.height * mask.h)), j1 = Math.min(mask.h - 1, Math.ceil((y1 + reach - mask.y0) / mask.height * mask.h));
|
|
6394
|
+
for (let j = j0; j <= j1; j++) {
|
|
6395
|
+
const y = mask.y0 + (j + 0.5) / mask.h * mask.height;
|
|
6396
|
+
for (let i = i0; i <= i1; i++) {
|
|
6397
|
+
const s = (i + 0.5) / mask.w * mask.len;
|
|
6398
|
+
const edge = SPALL_MIN + SPALL_RAGGED * (0.6 * noise2(s, y, 0.03) + 0.4 * noise2(s + 7.3, y - 3.1, 0.011));
|
|
6399
|
+
if (inside(s, y) <= edge) mask.data[j * mask.w + i] = 255;
|
|
6400
|
+
}
|
|
6401
|
+
}
|
|
6402
|
+
};
|
|
6403
|
+
for (const c of holes) stamp(c.a, c.b, c.y0, c.y1, (s, y) => boxDistance(s, y, c.a, c.b, c.y0, c.y1));
|
|
6404
|
+
for (const d of discs) stamp(d.s - d.r, d.s + d.r, d.y - d.r, d.y + d.r, (s, y) => Math.max(0, Math.hypot(s - d.s, y - d.y) - d.r));
|
|
6405
|
+
mask.texture.needsUpdate = true;
|
|
6406
|
+
const near = (c) => holes.some((h) => boxDistance((c.a + c.b) / 2, (c.y0 + c.y1) / 2, h.a - (c.b - c.a) / 2, h.b + (c.b - c.a) / 2, h.y0 - (c.y1 - c.y0) / 2, h.y1 + (c.y1 - c.y0) / 2) <= reach) || discs.some((d) => boxDistance(d.s, d.y, c.a, c.b, c.y0, c.y1) <= d.r + reach);
|
|
6407
|
+
const list = [];
|
|
6408
|
+
const tone = (hex, k) => tmp.c.setHex(hex).multiplyScalar(k).getHex();
|
|
6409
|
+
for (const { c, part, units: units2, thick, mid } of shown) {
|
|
6410
|
+
if (!near(c)) continue;
|
|
6411
|
+
const centre = mask.start + (c.a + c.b) / 2, y = (c.y0 + c.y1) / 2, len = c.b - c.a, h = c.y1 - c.y0;
|
|
6412
|
+
const at = (s, dy, d, colour) => list.push({ x: mask.alongU ? centre : mid, y, z: mask.alongU ? mid : centre, sx: mask.alongU ? s : d, sy: dy, sz: mask.alongU ? d : s, colour });
|
|
6413
|
+
const base = fragmentMaterial(part.material).color.getHex();
|
|
6414
|
+
const n = noise2(centre * 3.1, y * 2.7, 0.07);
|
|
6415
|
+
if (units2.mortar === "concrete") {
|
|
6416
|
+
at(len, h, thick - 2 * COVER - 0.03 * n, tone(base, 0.86 + 0.2 * n));
|
|
6417
|
+
} else {
|
|
6418
|
+
at(len, h, thick - 2 * COVER - 0.012, 10327948);
|
|
6419
|
+
at(len - 0.012, h - 0.012, thick - 2 * COVER, tone(base, 0.8 + 0.35 * n));
|
|
6420
|
+
}
|
|
6421
|
+
}
|
|
6422
|
+
if (view.units) {
|
|
6423
|
+
view.units.removeFromParent();
|
|
6424
|
+
view.units.dispose();
|
|
6425
|
+
}
|
|
6426
|
+
const units = new THREE.InstancedMesh(unitGeometry, unitMaterial, Math.max(1, list.length));
|
|
6427
|
+
units.name = "breach:" + view.host;
|
|
6428
|
+
list.forEach((u, i) => {
|
|
6429
|
+
tmp.m.compose(tmp.p.set(u.x, u.y, u.z), tmp.q.identity(), tmp.s.set(u.sx, u.sy, u.sz));
|
|
6430
|
+
units.setMatrixAt(i, tmp.m);
|
|
6431
|
+
units.setColorAt(i, tmp.c.setHex(u.colour));
|
|
6432
|
+
});
|
|
6433
|
+
units.count = list.length;
|
|
6434
|
+
units.instanceMatrix.needsUpdate = true;
|
|
6435
|
+
if (units.instanceColor) units.instanceColor.needsUpdate = true;
|
|
6436
|
+
units.castShadow = true;
|
|
6437
|
+
units.receiveShadow = true;
|
|
6438
|
+
units.visible = lod === 0;
|
|
6439
|
+
house.add(units);
|
|
6440
|
+
view.units = units;
|
|
6441
|
+
view.gone = holes.length;
|
|
6442
|
+
}
|
|
6325
6443
|
function draw2(partId, change) {
|
|
6326
6444
|
if (lod !== 0) return false;
|
|
6327
6445
|
const hostId = hostOf(partId);
|
|
@@ -6331,37 +6449,21 @@ function installDestructionBreach(K, _shared) {
|
|
|
6331
6449
|
const items = structure.meshesOf(hostId).filter((it) => it.mesh);
|
|
6332
6450
|
if (!items.length) return false;
|
|
6333
6451
|
const parts = [hostId, ...riders(hostId)].filter((id) => structure.byId.get(id) && specOf(id)?.units);
|
|
6334
|
-
|
|
6452
|
+
if (!parts.includes(partId)) return false;
|
|
6453
|
+
const mask = maskOf(hostId, parts);
|
|
6454
|
+
view = { host: hostId, parts, items, mask, shells: [], saved: null, units: null, gone: 0, chips: new Map(parts.map((id) => [id, []])), openings: /* @__PURE__ */ new Map() };
|
|
6335
6455
|
}
|
|
6336
6456
|
if (!view.chips.has(partId)) return false;
|
|
6337
6457
|
if (change.opening) {
|
|
6338
6458
|
if (view.openings.has(partId)) return false;
|
|
6339
6459
|
view.openings.set(partId, { center: local(change.opening.center), radius: change.opening.radius });
|
|
6340
|
-
if (partId === hostId) view.opening = view.openings.get(partId);
|
|
6341
6460
|
}
|
|
6342
6461
|
if (change.chip) view.chips.get(partId).push(local(change.chip));
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
view.mesh.removeFromParent();
|
|
6347
|
-
view.mesh.dispose();
|
|
6462
|
+
if (!view.saved) {
|
|
6463
|
+
view.shells = view.items.map((it) => shell(it, view.mask));
|
|
6464
|
+
view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
|
|
6348
6465
|
}
|
|
6349
|
-
|
|
6350
|
-
mesh.name = "breach:" + hostId;
|
|
6351
|
-
list.forEach((u, i) => {
|
|
6352
|
-
tmp.m.compose(tmp.p.set(u.x, u.y, u.z), tmp.q.identity(), tmp.s.set(u.sx, u.sy, u.sz));
|
|
6353
|
-
mesh.setMatrixAt(i, tmp.m);
|
|
6354
|
-
mesh.setColorAt(i, tmp.c.setHex(u.colour));
|
|
6355
|
-
});
|
|
6356
|
-
mesh.count = list.length;
|
|
6357
|
-
mesh.instanceMatrix.needsUpdate = true;
|
|
6358
|
-
if (mesh.instanceColor) mesh.instanceColor.needsUpdate = true;
|
|
6359
|
-
mesh.castShadow = true;
|
|
6360
|
-
mesh.receiveShadow = true;
|
|
6361
|
-
house.add(mesh);
|
|
6362
|
-
if (!view.saved) view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
|
|
6363
|
-
view.mesh = mesh;
|
|
6364
|
-
view.units = list.length;
|
|
6466
|
+
paint(view);
|
|
6365
6467
|
views.set(hostId, view);
|
|
6366
6468
|
invalidate();
|
|
6367
6469
|
invalidateShadow();
|
|
@@ -6373,30 +6475,40 @@ function installDestructionBreach(K, _shared) {
|
|
|
6373
6475
|
else s.data = collapseRange(s.it.mesh, s.v0, s.it.v1);
|
|
6374
6476
|
}
|
|
6375
6477
|
}
|
|
6478
|
+
function dispose(view) {
|
|
6479
|
+
view.units.removeFromParent();
|
|
6480
|
+
view.units.dispose();
|
|
6481
|
+
for (const m of view.shells) {
|
|
6482
|
+
m.removeFromParent();
|
|
6483
|
+
m.geometry.dispose();
|
|
6484
|
+
m.material.dispose();
|
|
6485
|
+
}
|
|
6486
|
+
view.mask.texture.dispose();
|
|
6487
|
+
}
|
|
6376
6488
|
return {
|
|
6377
|
-
/** Handles a `stage` event of the house's object. Returns true when the wall was
|
|
6489
|
+
/** Handles a `stage` event of the house's object. Returns true when the wall was cut. */
|
|
6378
6490
|
stage(event) {
|
|
6379
6491
|
return event.stage === 2 && !!event.opening ? draw2(event.part, { opening: event.opening }) : false;
|
|
6380
6492
|
},
|
|
6381
|
-
/** Handles a `chip` event: the unit that came out leaves a
|
|
6493
|
+
/** Handles a `chip` event: the unit that came out leaves a hole in the wall where it was. Returns true when the wall was cut. */
|
|
6382
6494
|
chip(event) {
|
|
6383
6495
|
return draw2(event.part, { chip: event.center });
|
|
6384
6496
|
},
|
|
6385
|
-
/** The part broke or fell:
|
|
6497
|
+
/** The part broke or fell: its damage goes (the plain range stays collapsed, the renderer hides the part). */
|
|
6386
6498
|
drop(partId) {
|
|
6387
6499
|
const v = views.get(partId);
|
|
6388
6500
|
if (!v) return;
|
|
6389
|
-
v
|
|
6390
|
-
v.mesh.dispose();
|
|
6501
|
+
dispose(v);
|
|
6391
6502
|
views.delete(partId);
|
|
6392
6503
|
},
|
|
6393
|
-
/** LOD 0 draws the
|
|
6504
|
+
/** LOD 0 draws the cut wall; LOD 1 and 2 give the wall its box back. */
|
|
6394
6505
|
setLod(level) {
|
|
6395
6506
|
const was = lod;
|
|
6396
6507
|
lod = level;
|
|
6397
6508
|
if (was === 0 === (level === 0)) return;
|
|
6398
6509
|
for (const v of views.values()) {
|
|
6399
|
-
v.
|
|
6510
|
+
v.units.visible = level === 0;
|
|
6511
|
+
for (const m of v.shells) m.visible = level === 0;
|
|
6400
6512
|
plain(v, level !== 0);
|
|
6401
6513
|
}
|
|
6402
6514
|
invalidate();
|
|
@@ -6405,17 +6517,21 @@ function installDestructionBreach(K, _shared) {
|
|
|
6405
6517
|
/** Everything back to what it was (after `world.reset`). */
|
|
6406
6518
|
restore() {
|
|
6407
6519
|
for (const v of views.values()) {
|
|
6408
|
-
v
|
|
6409
|
-
v.mesh.dispose();
|
|
6520
|
+
dispose(v);
|
|
6410
6521
|
if (lod === 0) plain(v, true);
|
|
6411
6522
|
}
|
|
6412
6523
|
views.clear();
|
|
6413
6524
|
},
|
|
6414
|
-
/** The wall
|
|
6525
|
+
/** The wall has damage drawn. */
|
|
6415
6526
|
has(partId) {
|
|
6416
6527
|
return views.has(partId);
|
|
6417
6528
|
},
|
|
6418
|
-
|
|
6529
|
+
/** Walls with damage drawn, units out of them, and units laid bare at the edge of the cuts. */
|
|
6530
|
+
statistics: () => ({
|
|
6531
|
+
walls: views.size,
|
|
6532
|
+
gone: [...views.values()].reduce((n, v) => n + v.gone, 0),
|
|
6533
|
+
units: [...views.values()].reduce((n, v) => n + v.units.count, 0)
|
|
6534
|
+
})
|
|
6419
6535
|
};
|
|
6420
6536
|
}
|
|
6421
6537
|
Object.assign(K, { createBreachView });
|