@adatechnology/game-floorplan-three 0.8.3 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/chunk-QUVGWVEC.js +8882 -0
- package/dist/chunk-QUVGWVEC.js.map +1 -0
- package/dist/index.d.ts +6 -349
- package/dist/index.global.js +631 -231
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +23 -8627
- package/dist/index.js.map +1 -1
- package/dist/testing-ikPy2Nxl.d.ts +379 -0
- package/dist/testing.d.ts +3 -0
- package/dist/testing.js +19 -0
- package/dist/testing.js.map +1 -0
- package/package.json +23 -17
package/dist/index.global.js
CHANGED
|
@@ -70,7 +70,7 @@ var GameFloorplanThree = (() => {
|
|
|
70
70
|
shade: () => shade
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
-
// ../game-shapes/dist/chunk-
|
|
73
|
+
// ../game-shapes/dist/chunk-M5N2SHNL.js
|
|
74
74
|
function canonicalJson(value) {
|
|
75
75
|
if (value === null) return "null";
|
|
76
76
|
if (typeof value === "number") return Object.is(value, -0) ? "-0" : Number.isFinite(value) ? String(value) : JSON.stringify(String(value));
|
|
@@ -1227,13 +1227,13 @@ var GameFloorplanThree = (() => {
|
|
|
1227
1227
|
uvArray.push(x);
|
|
1228
1228
|
uvArray.push(y);
|
|
1229
1229
|
};
|
|
1230
|
-
const
|
|
1230
|
+
const at2 = (index, axis) => verticesArray[index * 3 + axis];
|
|
1231
1231
|
const f3 = (a, b, c) => {
|
|
1232
1232
|
addVertex(a);
|
|
1233
1233
|
addVertex(b);
|
|
1234
1234
|
addVertex(c);
|
|
1235
1235
|
const nextIndex = verticesArray.length / 3;
|
|
1236
|
-
for (const index of [nextIndex - 3, nextIndex - 2, nextIndex - 1]) addUV(
|
|
1236
|
+
for (const index of [nextIndex - 3, nextIndex - 2, nextIndex - 1]) addUV(at2(index, 0), at2(index, 1));
|
|
1237
1237
|
};
|
|
1238
1238
|
const f4 = (a, b, c, d) => {
|
|
1239
1239
|
addVertex(a);
|
|
@@ -1247,8 +1247,8 @@ var GameFloorplanThree = (() => {
|
|
|
1247
1247
|
const iB = nextIndex - 3;
|
|
1248
1248
|
const iC = nextIndex - 2;
|
|
1249
1249
|
const iD = nextIndex - 1;
|
|
1250
|
-
const byX = Math.abs(
|
|
1251
|
-
const uv = (index) => [byX ?
|
|
1250
|
+
const byX = Math.abs(at2(iA, 1) - at2(iB, 1)) < Math.abs(at2(iA, 0) - at2(iB, 0));
|
|
1251
|
+
const uv = (index) => [byX ? at2(index, 0) : at2(index, 1), 1 - at2(index, 2)];
|
|
1252
1252
|
const uvs = [uv(iA), uv(iB), uv(iC), uv(iD)];
|
|
1253
1253
|
for (const k of [0, 1, 3, 1, 2, 3]) addUV(...uvs[k]);
|
|
1254
1254
|
};
|
|
@@ -1353,8 +1353,8 @@ var GameFloorplanThree = (() => {
|
|
|
1353
1353
|
groups: []
|
|
1354
1354
|
};
|
|
1355
1355
|
}
|
|
1356
|
-
function make(
|
|
1357
|
-
switch (kind) {
|
|
1356
|
+
function make(p) {
|
|
1357
|
+
switch (p.kind) {
|
|
1358
1358
|
case "box": {
|
|
1359
1359
|
const size = p.size ?? [1, 1, 1];
|
|
1360
1360
|
const segments = p.segments ?? [1, 1, 1];
|
|
@@ -1383,7 +1383,7 @@ var GameFloorplanThree = (() => {
|
|
|
1383
1383
|
case "mesh":
|
|
1384
1384
|
return mesh(p);
|
|
1385
1385
|
default:
|
|
1386
|
-
throw new Error(`game-shapes: unknown primitive kind "${String(kind)}"`);
|
|
1386
|
+
throw new Error(`game-shapes: unknown primitive kind "${String(p.kind)}"`);
|
|
1387
1387
|
}
|
|
1388
1388
|
}
|
|
1389
1389
|
var templates = /* @__PURE__ */ new Map();
|
|
@@ -1391,7 +1391,7 @@ var GameFloorplanThree = (() => {
|
|
|
1391
1391
|
var stats = { hits: 0, misses: 0 };
|
|
1392
1392
|
function buildPrimitive(node, options = {}) {
|
|
1393
1393
|
const parameters = primitiveParameters(node, options);
|
|
1394
|
-
if (node.kind === "mesh" || templateLimit === 0) return make(node
|
|
1394
|
+
if (node.kind === "mesh" || templateLimit === 0) return make({ ...node, ...parameters });
|
|
1395
1395
|
const key = `${node.kind}:${canonicalJson(parameters)}`;
|
|
1396
1396
|
const cached = templates.get(key);
|
|
1397
1397
|
if (cached) {
|
|
@@ -1401,7 +1401,7 @@ var GameFloorplanThree = (() => {
|
|
|
1401
1401
|
return cached;
|
|
1402
1402
|
}
|
|
1403
1403
|
stats.misses++;
|
|
1404
|
-
const built = make(node
|
|
1404
|
+
const built = make({ ...node, ...parameters });
|
|
1405
1405
|
templates.set(key, built);
|
|
1406
1406
|
if (templates.size > templateLimit) templates.delete(templates.keys().next().value);
|
|
1407
1407
|
return built;
|
|
@@ -1499,7 +1499,7 @@ var GameFloorplanThree = (() => {
|
|
|
1499
1499
|
const positions2 = new Float32Array(total * 3);
|
|
1500
1500
|
const normals = new Float32Array(total * 3);
|
|
1501
1501
|
const uvs = new Float32Array(total * 2);
|
|
1502
|
-
let
|
|
1502
|
+
let at2 = 0;
|
|
1503
1503
|
for (const piece2 of pieces) {
|
|
1504
1504
|
const e = piece2.matrix;
|
|
1505
1505
|
const nm = normalMatrix(e);
|
|
@@ -1513,15 +1513,15 @@ var GameFloorplanThree = (() => {
|
|
|
1513
1513
|
if (piece2.normals) n[k * 3 + c] = piece2.normals[i * 3 + c];
|
|
1514
1514
|
}
|
|
1515
1515
|
if (piece2.uvs) {
|
|
1516
|
-
uvs[(
|
|
1517
|
-
uvs[(
|
|
1516
|
+
uvs[(at2 + k) * 2] = piece2.uvs[i * 2];
|
|
1517
|
+
uvs[(at2 + k) * 2 + 1] = piece2.uvs[i * 2 + 1];
|
|
1518
1518
|
}
|
|
1519
1519
|
}
|
|
1520
1520
|
for (let k = 0; k < count; k++) {
|
|
1521
1521
|
const q = transformPoint(e, p[k * 3], p[k * 3 + 1], p[k * 3 + 2]);
|
|
1522
|
-
positions2[(
|
|
1523
|
-
positions2[(
|
|
1524
|
-
positions2[(
|
|
1522
|
+
positions2[(at2 + k) * 3] = q[0];
|
|
1523
|
+
positions2[(at2 + k) * 3 + 1] = q[1];
|
|
1524
|
+
positions2[(at2 + k) * 3 + 2] = q[2];
|
|
1525
1525
|
const x = n[k * 3];
|
|
1526
1526
|
const y = n[k * 3 + 1];
|
|
1527
1527
|
const z = n[k * 3 + 2];
|
|
@@ -1529,15 +1529,116 @@ var GameFloorplanThree = (() => {
|
|
|
1529
1529
|
const vy = nm[1] * x + nm[4] * y + nm[7] * z;
|
|
1530
1530
|
const vz = nm[2] * x + nm[5] * y + nm[8] * z;
|
|
1531
1531
|
const s = 1 / (Math.sqrt(vx * vx + vy * vy + vz * vz) || 1);
|
|
1532
|
-
normals[(
|
|
1533
|
-
normals[(
|
|
1534
|
-
normals[(
|
|
1532
|
+
normals[(at2 + k) * 3] = vx * s;
|
|
1533
|
+
normals[(at2 + k) * 3 + 1] = vy * s;
|
|
1534
|
+
normals[(at2 + k) * 3 + 2] = vz * s;
|
|
1535
1535
|
}
|
|
1536
|
-
|
|
1536
|
+
at2 += count;
|
|
1537
1537
|
}
|
|
1538
1538
|
return { positions: positions2, normals, uvs };
|
|
1539
1539
|
}
|
|
1540
1540
|
|
|
1541
|
+
// ../game-contracts/dist/index.js
|
|
1542
|
+
var DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024;
|
|
1543
|
+
var DEFAULT_IGNITION_RULES = {
|
|
1544
|
+
fillCurve: [
|
|
1545
|
+
[0, 0.6],
|
|
1546
|
+
[0.1, 1],
|
|
1547
|
+
[0.35, 0.6],
|
|
1548
|
+
[0.65, 0.3],
|
|
1549
|
+
[0.9, 0.15],
|
|
1550
|
+
[1, 0.12]
|
|
1551
|
+
],
|
|
1552
|
+
flameFillInfluence: 0.5,
|
|
1553
|
+
flameDefaults: { incendiary: 0.7, tracer: 0.2 },
|
|
1554
|
+
sparkTarget: { steel: 1, iron: 1, aluminium: 0.25 },
|
|
1555
|
+
sparkMetalDefault: 0.5,
|
|
1556
|
+
sparkFluid: { diesel: 0.15 },
|
|
1557
|
+
fireNear: { radius: 1.5, chancePerSecond: 0.5 }
|
|
1558
|
+
};
|
|
1559
|
+
var resolveIgnitionRules = (rules) => ({
|
|
1560
|
+
...DEFAULT_IGNITION_RULES,
|
|
1561
|
+
...rules,
|
|
1562
|
+
flameDefaults: { ...DEFAULT_IGNITION_RULES.flameDefaults, ...rules?.flameDefaults },
|
|
1563
|
+
sparkTarget: { ...DEFAULT_IGNITION_RULES.sparkTarget, ...rules?.sparkTarget },
|
|
1564
|
+
sparkFluid: { ...DEFAULT_IGNITION_RULES.sparkFluid, ...rules?.sparkFluid },
|
|
1565
|
+
fireNear: { ...DEFAULT_IGNITION_RULES.fireNear, ...rules?.fireNear }
|
|
1566
|
+
});
|
|
1567
|
+
var fillFactor = (fill2, curve = DEFAULT_IGNITION_RULES.fillCurve) => {
|
|
1568
|
+
if (curve.length === 0) return 1;
|
|
1569
|
+
const f = Math.min(1, Math.max(0, fill2));
|
|
1570
|
+
if (f <= curve[0][0]) return curve[0][1];
|
|
1571
|
+
for (let i = 1; i < curve.length; i++) {
|
|
1572
|
+
const [x1, y1] = curve[i];
|
|
1573
|
+
const [x0, y0] = curve[i - 1];
|
|
1574
|
+
if (f <= x1) return x1 === x0 ? y1 : y0 + (y1 - y0) * (f - x0) / (x1 - x0);
|
|
1575
|
+
}
|
|
1576
|
+
return curve[curve.length - 1][1];
|
|
1577
|
+
};
|
|
1578
|
+
var sparkTargetFactor = (materialId, metal, rules = DEFAULT_IGNITION_RULES) => !metal ? 0 : rules.sparkTarget[materialId] ?? rules.sparkMetalDefault;
|
|
1579
|
+
var ignitionChance = (hit, target, rules = DEFAULT_IGNITION_RULES) => {
|
|
1580
|
+
const k = fillFactor(target.fill, rules.fillCurve);
|
|
1581
|
+
const spark = (hit.ignition?.spark ?? 0) * target.sparkTarget * (target.fluid === void 0 ? 1 : rules.sparkFluid[target.fluid] ?? 1) * k;
|
|
1582
|
+
const flameBase = hit.ignition?.flame ?? Math.max(hit.incendiary ? rules.flameDefaults.incendiary : 0, hit.tracer ? rules.flameDefaults.tracer : 0);
|
|
1583
|
+
const flame = flameBase * (1 - rules.flameFillInfluence * (1 - k));
|
|
1584
|
+
return 1 - (1 - Math.min(1, Math.max(0, spark))) * (1 - Math.min(1, Math.max(0, flame)));
|
|
1585
|
+
};
|
|
1586
|
+
var DEFERRED_QUEUE_ID = {
|
|
1587
|
+
DESTRUCTION_EVENTS: "destruction.events",
|
|
1588
|
+
BREACH_PAINT: "floorplan.breach-paint",
|
|
1589
|
+
AUDIO_VOICES: "audio.voices",
|
|
1590
|
+
VEHICLE_CREASE: "vehicles.crease"
|
|
1591
|
+
};
|
|
1592
|
+
var DEFERRED_PRIORITY = {
|
|
1593
|
+
[DEFERRED_QUEUE_ID.DESTRUCTION_EVENTS]: { priority: 300, phase: "present" },
|
|
1594
|
+
[DEFERRED_QUEUE_ID.BREACH_PAINT]: { priority: 250, phase: "present" },
|
|
1595
|
+
[DEFERRED_QUEUE_ID.AUDIO_VOICES]: { priority: 200, phase: "idle", reserveMs: 1 },
|
|
1596
|
+
[DEFERRED_QUEUE_ID.VEHICLE_CREASE]: { priority: 100, phase: "idle" }
|
|
1597
|
+
};
|
|
1598
|
+
var KIT_ORIGIN_KEY = "kitOrigin";
|
|
1599
|
+
function markKitOrigin(object2, origin) {
|
|
1600
|
+
const node = object2;
|
|
1601
|
+
node.userData = node.userData ?? {};
|
|
1602
|
+
node.userData[KIT_ORIGIN_KEY] = { ...origin };
|
|
1603
|
+
return object2;
|
|
1604
|
+
}
|
|
1605
|
+
var SURFACE_IDS = ["concrete", "asphalt", "wood", "tile", "dirt", "grass", "gravel", "sand", "metal", "water", "glass", "carpet"];
|
|
1606
|
+
var GAIT_IDS = ["walk", "run"];
|
|
1607
|
+
var LANDING_IDS = ["light", "heavy"];
|
|
1608
|
+
var BODY_SOUND_IDS = [
|
|
1609
|
+
"jump",
|
|
1610
|
+
"cloth_rustle",
|
|
1611
|
+
"body_fall",
|
|
1612
|
+
"fall_damage",
|
|
1613
|
+
"player_hurt",
|
|
1614
|
+
"player_breath_run",
|
|
1615
|
+
"player_death",
|
|
1616
|
+
"bite",
|
|
1617
|
+
"grab",
|
|
1618
|
+
"punch_swing",
|
|
1619
|
+
"punch_hit_body",
|
|
1620
|
+
"punch_hit_face",
|
|
1621
|
+
"punch_hit_object",
|
|
1622
|
+
"kick_swing",
|
|
1623
|
+
"kick_hit",
|
|
1624
|
+
"kick_hit_object",
|
|
1625
|
+
"shove_two_hands",
|
|
1626
|
+
"knife_swing",
|
|
1627
|
+
"knife_stab",
|
|
1628
|
+
"knife_slash",
|
|
1629
|
+
"knife_hit_object",
|
|
1630
|
+
"blunt_swing",
|
|
1631
|
+
"blunt_hit",
|
|
1632
|
+
"blunt_hit_object",
|
|
1633
|
+
"axe_swing",
|
|
1634
|
+
"axe_chop",
|
|
1635
|
+
"axe_hit_object"
|
|
1636
|
+
];
|
|
1637
|
+
var footstepSoundId = (surface, gait) => `footstep_${surface}_${gait}`;
|
|
1638
|
+
var FOOTSTEP_SOUND_IDS = SURFACE_IDS.flatMap((surface) => GAIT_IDS.map((gait) => footstepSoundId(surface, gait)));
|
|
1639
|
+
var LAND_SOUND_IDS = SURFACE_IDS.flatMap((surface) => LANDING_IDS.map((landing) => `land_${surface}_${landing}`));
|
|
1640
|
+
var BODY_FOLEY_IDS = [...FOOTSTEP_SOUND_IDS, ...LAND_SOUND_IDS, ...BODY_SOUND_IDS];
|
|
1641
|
+
|
|
1541
1642
|
// ../game-shapes-three/dist/index.js
|
|
1542
1643
|
var UV_BEFORE_NORMAL = /* @__PURE__ */ new Set(["LatheGeometry", "ExtrudeGeometry"]);
|
|
1543
1644
|
var INDEX_FIRST = /* @__PURE__ */ new Set(["BoxGeometry", "CylinderGeometry", "ConeGeometry", "SphereGeometry", "PlaneGeometry", "CircleGeometry", "RingGeometry", "LatheGeometry", "TorusGeometry"]);
|
|
@@ -3307,17 +3408,17 @@ var GameFloorplanThree = (() => {
|
|
|
3307
3408
|
const index = geometry2.index ? geometry2.index.array : null;
|
|
3308
3409
|
const count = index ? index.length : position.count;
|
|
3309
3410
|
for (let item = 0; item < count; item++) {
|
|
3310
|
-
const
|
|
3311
|
-
vertex.fromBufferAttribute(position,
|
|
3411
|
+
const at2 = index ? index[item] : item;
|
|
3412
|
+
vertex.fromBufferAttribute(position, at2).applyMatrix4(matrix);
|
|
3312
3413
|
positions2.push(vertex.x, vertex.y, vertex.z);
|
|
3313
|
-
if (normalAttribute) normal.fromBufferAttribute(normalAttribute,
|
|
3414
|
+
if (normalAttribute) normal.fromBufferAttribute(normalAttribute, at2).applyMatrix3(normalMatrix2).normalize();
|
|
3314
3415
|
else normal.set(0, 1, 0);
|
|
3315
3416
|
normals.push(normal.x, normal.y, normal.z);
|
|
3316
3417
|
color2.copy(material2.color || color2.set(1, 1, 1)).convertLinearToSRGB();
|
|
3317
3418
|
if (sample && uv && material2.map) {
|
|
3318
3419
|
const repeat = material2.map.repeat;
|
|
3319
|
-
const u = (uv.getX(
|
|
3320
|
-
const v = (uv.getY(
|
|
3420
|
+
const u = (uv.getX(at2) * repeat.x % 1 + 1) % 1;
|
|
3421
|
+
const v = (uv.getY(at2) * repeat.y % 1 + 1) % 1;
|
|
3321
3422
|
const pixelX = Math.min(sample.width - 1, u * sample.width | 0);
|
|
3322
3423
|
const pixelY = Math.min(sample.height - 1, (1 - v) * sample.height | 0);
|
|
3323
3424
|
const offset = (pixelY * sample.width + pixelX) * 4;
|
|
@@ -8997,7 +9098,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
8997
9098
|
const em = w.emitters();
|
|
8998
9099
|
if (em.length && !IV.efx && K.IVK.effects) {
|
|
8999
9100
|
const g = h.houseGroup;
|
|
9000
|
-
IV.efx = ik.gfx.createEffects(g, { maxParticles: 1400, seed: 11, document: DOC });
|
|
9101
|
+
IV.efx = ik.gfx.createEffects(g, { maxParticles: 1400, seed: 11, document: DOC, ...K.IVK.effectSink ? { effects: K.IVK.effectSink } : {} });
|
|
9001
9102
|
}
|
|
9002
9103
|
if (IV.efx) {
|
|
9003
9104
|
const alive = IV.efx.stats().alive;
|
|
@@ -9770,8 +9871,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
9770
9871
|
// was `maquina`
|
|
9771
9872
|
});
|
|
9772
9873
|
var OWN_TYPES = Object.freeze({ lamp: true, gas_piped: true });
|
|
9874
|
+
var sourceOf = (result) => result;
|
|
9773
9875
|
var ADAPTER_VERSION = "0.3.0";
|
|
9774
9876
|
var r3 = (n) => Math.round(n * 1e3) / 1e3;
|
|
9877
|
+
var at = (it) => ({ x: it.x ?? 0, z: it.z ?? 0, ry: it.ry ?? 0 });
|
|
9775
9878
|
function mergeRegistry(base, extra) {
|
|
9776
9879
|
const out = { ...base };
|
|
9777
9880
|
if (extra) {
|
|
@@ -9790,14 +9893,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
9790
9893
|
});
|
|
9791
9894
|
function create2(options = {}) {
|
|
9792
9895
|
const opts = options || {};
|
|
9793
|
-
const GI = opts.GameInteractables;
|
|
9794
|
-
const HH = opts.GameInteractablesHousehold;
|
|
9795
9896
|
const locale = opts.locale || "pt-BR";
|
|
9796
9897
|
const msg = createTranslator2(locale, opts.messages);
|
|
9797
|
-
if (!
|
|
9898
|
+
if (!opts.GameInteractables || !opts.GameInteractablesHousehold) throw new Error(msg("error.missingKit"));
|
|
9899
|
+
const GI = opts.GameInteractables;
|
|
9900
|
+
const HH = opts.GameInteractablesHousehold;
|
|
9798
9901
|
const region = opts.region || "br";
|
|
9799
9902
|
const hh = HH.createHousehold({ locale, region });
|
|
9800
9903
|
const householdTypes = new Set(hh.types.map((t) => t.id));
|
|
9904
|
+
const recorderApi = () => HH.createRecorder().api;
|
|
9801
9905
|
const worlds = /* @__PURE__ */ new WeakMap();
|
|
9802
9906
|
const typeMap = mergeRegistry(TYPE_MAP, opts.typeMap);
|
|
9803
9907
|
const contentMap = mergeRegistry(CONTENT_MAP, opts.contentMap);
|
|
@@ -9833,7 +9937,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
9833
9937
|
function colorOf(res, color2) {
|
|
9834
9938
|
if (color2 == null) return void 0;
|
|
9835
9939
|
if (typeof color2 === "number") return color2;
|
|
9836
|
-
const v = res.colors && res.colors[color2];
|
|
9940
|
+
const v = res.colors && res.colors[String(color2)];
|
|
9837
9941
|
return typeof v === "number" ? v : void 0;
|
|
9838
9942
|
}
|
|
9839
9943
|
function paletteOf(res) {
|
|
@@ -9862,17 +9966,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
9862
9966
|
drawerItem: (s) => drawerItems.has(s.itemId)
|
|
9863
9967
|
};
|
|
9864
9968
|
const itemOfContent = (c) => {
|
|
9865
|
-
const
|
|
9969
|
+
const group = stackGroup(c);
|
|
9970
|
+
const id = contentMap[c.itemId] || (hh.items[c.itemId] ? c.itemId : null) || (group != null ? contentByGroup[group] : void 0) || contentFallback;
|
|
9866
9971
|
return hh.items[id] ? id : contentFallback;
|
|
9867
9972
|
};
|
|
9868
9973
|
const volume = (d) => d.size[0] * d.size[1] * d.size[2];
|
|
9869
9974
|
const candidates = (id, objectType) => {
|
|
9870
9975
|
const def = hh.items[id];
|
|
9871
|
-
const siblings = Object.values(hh.items).filter((i) => i.category === def
|
|
9976
|
+
const siblings = Object.values(hh.items).filter((i) => i.category === def?.category && i.id !== id).sort((a, b) => volume(a) - volume(b) || (a.id < b.id ? -1 : 1));
|
|
9872
9977
|
return [id].concat(siblings.map((i) => i.id), substitutes[objectType] || []);
|
|
9873
9978
|
};
|
|
9874
9979
|
function distribute(type, probeItem, stacks) {
|
|
9875
|
-
const spec = hh.build(type, probeItem,
|
|
9980
|
+
const spec = hh.build(type, probeItem, recorderApi());
|
|
9876
9981
|
const conts = spec.containers || [];
|
|
9877
9982
|
const contents = {};
|
|
9878
9983
|
for (const c of conts) contents[c.id] = c.slots.map(() => null);
|
|
@@ -9903,8 +10008,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
9903
10008
|
}
|
|
9904
10009
|
return { contents, rejected };
|
|
9905
10010
|
}
|
|
9906
|
-
function plan(
|
|
9907
|
-
|
|
10011
|
+
function plan(source, options2 = {}) {
|
|
10012
|
+
const res = sourceOf(source);
|
|
10013
|
+
const popts = options2 || {};
|
|
9908
10014
|
const o = { ox: popts.originX || 0, oz: popts.originZ || 0, inw: popts.inw || 1, base: popts.base || 0 };
|
|
9909
10015
|
const K = conv(o);
|
|
9910
10016
|
const floorSel = popts.floor;
|
|
@@ -9968,7 +10074,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
9968
10074
|
const item = {
|
|
9969
10075
|
x: K.x(m.x),
|
|
9970
10076
|
z: K.z(m.z),
|
|
9971
|
-
ry: m.frontU != null ? K.ry(m.frontU, m.frontV) : r3(m.ry || 0),
|
|
10077
|
+
ry: m.frontU != null ? K.ry(m.frontU, m.frontV ?? 0) : r3(m.ry || 0),
|
|
9972
10078
|
w: m.w,
|
|
9973
10079
|
d: m.d,
|
|
9974
10080
|
h: m.h,
|
|
@@ -9981,7 +10087,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
9981
10087
|
return item;
|
|
9982
10088
|
}
|
|
9983
10089
|
function entry2(id, type, item, origin, floor, extra) {
|
|
9984
|
-
|
|
10090
|
+
const e = { id, type, item, origin, floor, floorY: floorYOf(res, o, floor), connections: {} };
|
|
10091
|
+
return Object.assign(e, extra || {});
|
|
9985
10092
|
}
|
|
9986
10093
|
function store(targets, stacks) {
|
|
9987
10094
|
let rest2 = stacks || [];
|
|
@@ -9994,10 +10101,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
9994
10101
|
}
|
|
9995
10102
|
const hidden = [];
|
|
9996
10103
|
function distRect(c, x, z) {
|
|
9997
|
-
const
|
|
9998
|
-
const
|
|
9999
|
-
const
|
|
10000
|
-
const
|
|
10104
|
+
const ci = at(c.item);
|
|
10105
|
+
const dx = x - ci.x;
|
|
10106
|
+
const dz = z - ci.z;
|
|
10107
|
+
const s = Math.sin(ci.ry);
|
|
10108
|
+
const co = Math.cos(ci.ry);
|
|
10001
10109
|
const lx = dx * co - dz * s;
|
|
10002
10110
|
const lz = dx * s + dz * co;
|
|
10003
10111
|
return Math.hypot(Math.max(Math.abs(lx) - (c.item.w || 0) / 2, 0), Math.max(Math.abs(lz) - (c.item.d || 0) / 2, 0));
|
|
@@ -10005,9 +10113,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10005
10113
|
function hideCylinders() {
|
|
10006
10114
|
for (const b of hidden) {
|
|
10007
10115
|
let target = null;
|
|
10116
|
+
const bi = at(b.item);
|
|
10008
10117
|
for (const c2 of result.items) {
|
|
10009
10118
|
if (c2.type !== "kitchen_cabinet_base" || c2.floor !== b.floor) continue;
|
|
10010
|
-
const dist = distRect(c2,
|
|
10119
|
+
const dist = distRect(c2, bi.x, bi.z);
|
|
10011
10120
|
if (!target || dist < target.dist) target = { c: c2, dist };
|
|
10012
10121
|
}
|
|
10013
10122
|
if (!target) {
|
|
@@ -10015,16 +10124,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10015
10124
|
continue;
|
|
10016
10125
|
}
|
|
10017
10126
|
const c = target.c;
|
|
10018
|
-
const spec = hh.build(c.type, c.item,
|
|
10019
|
-
const
|
|
10020
|
-
const
|
|
10127
|
+
const spec = hh.build(c.type, c.item, recorderApi());
|
|
10128
|
+
const ci = at(c.item);
|
|
10129
|
+
const sn = Math.sin(ci.ry);
|
|
10130
|
+
const cs = Math.cos(ci.ry);
|
|
10021
10131
|
let door = null;
|
|
10022
10132
|
for (const it of spec.interactions || []) {
|
|
10023
|
-
const
|
|
10024
|
-
|
|
10025
|
-
|
|
10026
|
-
const
|
|
10027
|
-
const
|
|
10133
|
+
const action = it.action;
|
|
10134
|
+
const pt = action.do === "toggle_part" ? (spec.parts || []).find((q) => q.id === action.part) : null;
|
|
10135
|
+
if (!pt || !pt.motion || pt.motion.kind !== "hinge") continue;
|
|
10136
|
+
const wx = ci.x + it.pos[0] * cs + it.pos[2] * sn;
|
|
10137
|
+
const wz = ci.z - it.pos[0] * sn + it.pos[2] * cs;
|
|
10138
|
+
const dist = Math.hypot(wx - bi.x, wz - bi.z);
|
|
10028
10139
|
if (!door || dist < door.dist) door = { id: pt.id, dist };
|
|
10029
10140
|
}
|
|
10030
10141
|
if (!door) {
|
|
@@ -10054,9 +10165,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10054
10165
|
const campCylinder = firstOfType("gas_canister");
|
|
10055
10166
|
function planFireplace(m, e, item) {
|
|
10056
10167
|
const def = hh.types.find((t) => t.id === "fireplace");
|
|
10057
|
-
const lack = (def.d - m.d) / 2;
|
|
10058
|
-
|
|
10059
|
-
item.
|
|
10168
|
+
const lack = ((def ? def.d : m.d) - m.d) / 2;
|
|
10169
|
+
const p = at(item);
|
|
10170
|
+
item.x = r3(p.x + Math.sin(p.ry) * lack);
|
|
10171
|
+
item.z = r3(p.z + Math.cos(p.ry) * lack);
|
|
10060
10172
|
const room = (res.rooms || []).find((c) => c.id === m.room && c.floor === m.floor);
|
|
10061
10173
|
const f = (res.floors || []).find((x) => x.index === m.floor);
|
|
10062
10174
|
item.h = r3(room && room.ceiling || f && f.ceiling || 2.6);
|
|
@@ -10084,7 +10196,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10084
10196
|
e.connections.gas = m.gas || "cylinder";
|
|
10085
10197
|
e.connections.cylinder = m.cylinder || null;
|
|
10086
10198
|
}
|
|
10087
|
-
if (map.type === "gas_bottle") result.cylinders.push({ id: e.id, stove: m.link
|
|
10199
|
+
if (map.type === "gas_bottle") result.cylinders.push({ id: e.id, stove: typeof m.link === "string" ? m.link : null, place: m.placement || null });
|
|
10088
10200
|
if (map.type === "gas_canister") {
|
|
10089
10201
|
result.canisters.push(e.id);
|
|
10090
10202
|
if (campCylinder && campCylinder.id === m.id && campStove) result.cylinders.push({ id: e.id, stove: campStove.id, place: null });
|
|
@@ -10108,7 +10220,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10108
10220
|
push(e);
|
|
10109
10221
|
}
|
|
10110
10222
|
function planCompound(m, kind) {
|
|
10111
|
-
const ry = m.frontU != null ? K.ry(m.frontU, m.frontV) : r3(m.ry || 0);
|
|
10223
|
+
const ry = m.frontU != null ? K.ry(m.frontU, m.frontV ?? 0) : r3(m.ry || 0);
|
|
10112
10224
|
const cx = K.x(m.x);
|
|
10113
10225
|
const cz = K.z(m.z);
|
|
10114
10226
|
const part = (id, type, w, d, h, y, lx, lz) => {
|
|
@@ -10160,11 +10272,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10160
10272
|
} else {
|
|
10161
10273
|
const basin = part(m.id, "sink_bathroom", m.w, m.d, m.h + 0.2, 0, 0, 0);
|
|
10162
10274
|
list2.push(basin);
|
|
10163
|
-
|
|
10164
|
-
|
|
10275
|
+
const own = contents[m.id];
|
|
10276
|
+
if (own) {
|
|
10277
|
+
if (own.length) {
|
|
10165
10278
|
const cabinet = part(m.id + "#cabinet", "bathroom_cabinet", Math.max(0.45, Math.min(0.6, m.w)), 0.15, 0.75, 1.3, 0, -(m.d / 2) + 0.075);
|
|
10166
10279
|
list2.push(cabinet);
|
|
10167
|
-
store([["bathroom_cabinet", cabinet.item], ["sink_bathroom", basin.item]],
|
|
10280
|
+
store([["bathroom_cabinet", cabinet.item], ["sink_bathroom", basin.item]], own);
|
|
10168
10281
|
} else {
|
|
10169
10282
|
store([["sink_bathroom", basin.item]], []);
|
|
10170
10283
|
}
|
|
@@ -10204,7 +10317,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10204
10317
|
result.chairs = [];
|
|
10205
10318
|
if (opts.chairs !== false && popts.chairs !== false) {
|
|
10206
10319
|
const blocked = blockedOf(res, { originX: o.ox, originZ: o.oz, inw: o.inw });
|
|
10207
|
-
const floorKind = (q) => !q.decor && !q.flat && (q.y || 0) < 0.9 && q.aabb;
|
|
10320
|
+
const floorKind = (q) => !q.decor && !q.flat && (q.y || 0) < 0.9 && !!q.aabb;
|
|
10208
10321
|
const placed = [];
|
|
10209
10322
|
const free = (m, cu, cv, half) => {
|
|
10210
10323
|
const a = [cu - half + 0.03, cv - half + 0.03, cu + half - 0.03, cv + half - 0.03];
|
|
@@ -10220,8 +10333,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10220
10333
|
for (const m of res.items || []) {
|
|
10221
10334
|
const mode = chairTables[m.type];
|
|
10222
10335
|
if (!mode || !onFloor(m.floor, m.outdoor) || m.frontU == null) continue;
|
|
10223
|
-
const
|
|
10224
|
-
const
|
|
10336
|
+
const fv = m.frontV ?? 0;
|
|
10337
|
+
const f = [m.frontU, fv];
|
|
10338
|
+
const pp = [-fv, m.frontU];
|
|
10225
10339
|
const seats = [];
|
|
10226
10340
|
if (mode === "dining") {
|
|
10227
10341
|
const n = Math.max(1, Math.min(3, Math.floor((m.w - 0.1) / 0.55)));
|
|
@@ -10290,8 +10404,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10290
10404
|
const item = { x: K.x(s.u), z: K.z(s.v), ry: K.ry(s.frontU, s.frontV), y: s.y, seed: seedOf2(s.id) };
|
|
10291
10405
|
item.controls = (s.controls || []).map((id) => id + ":lamp");
|
|
10292
10406
|
const e = entry2(s.id, "wall_switch", item, s.id, s.floor);
|
|
10293
|
-
|
|
10294
|
-
e.
|
|
10407
|
+
const controls = (s.controls || []).slice();
|
|
10408
|
+
e.connections.controls = controls;
|
|
10409
|
+
e.lit = controls.some((id) => result.items.find((x) => x.id === id)?.lit === true);
|
|
10295
10410
|
if (floorSel == null) {
|
|
10296
10411
|
for (const id of s.controls || []) if (!lights.has(id)) result.warnings.push(msg("warn.switchUnknownLamp", { id: s.id, lamp: id }));
|
|
10297
10412
|
}
|
|
@@ -10331,7 +10446,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10331
10446
|
seed: seedOf2("panel"),
|
|
10332
10447
|
circuits: circuits.map((c) => ({ id: c.id, label: c.room }))
|
|
10333
10448
|
};
|
|
10334
|
-
if (!item.circuits
|
|
10449
|
+
if (!item.circuits?.length) delete item.circuits;
|
|
10335
10450
|
const e = entry2("panel", "electrical_panel", item, "panel", q.floor);
|
|
10336
10451
|
push(e);
|
|
10337
10452
|
result.panel = e.id;
|
|
@@ -10353,10 +10468,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10353
10468
|
}
|
|
10354
10469
|
}
|
|
10355
10470
|
const piped = result.items.filter((e) => e.type === "stove" && e.connections.gas === "piped");
|
|
10356
|
-
|
|
10471
|
+
const firstPiped = piped[0];
|
|
10472
|
+
if (firstPiped) {
|
|
10357
10473
|
const med = utilities.gas && utilities.gas.meter;
|
|
10358
|
-
const ref = med ? { x: K.x(med.u), z: K.z(med.v), y: med.y || 1 } : { x:
|
|
10359
|
-
const e = entry2("piped_gas", "gas_piped", { x: ref.x, z: ref.z, ry: 0, y: ref.y, seed: seedOf2("piped_gas") }, "piped_gas",
|
|
10474
|
+
const ref = med ? { x: K.x(med.u), z: K.z(med.v), y: med.y || 1 } : { x: firstPiped.item.x, z: firstPiped.item.z, y: 0.3 };
|
|
10475
|
+
const e = entry2("piped_gas", "gas_piped", { x: ref.x, z: ref.z, ry: 0, y: ref.y, seed: seedOf2("piped_gas") }, "piped_gas", firstPiped.floor);
|
|
10360
10476
|
e.floorY = o.base;
|
|
10361
10477
|
push(e);
|
|
10362
10478
|
for (const f of piped) f.connections.fuel = "piped_gas:gas";
|
|
@@ -10403,9 +10519,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10403
10519
|
for (const dv of spec.devices || []) if (L.outlet && dv.socket === "auto") dv.socket = L.outlet + ":socket";
|
|
10404
10520
|
} else {
|
|
10405
10521
|
const sh = L.shower || {};
|
|
10406
|
-
const
|
|
10522
|
+
const devices = spec.devices || [];
|
|
10523
|
+
const heater = devices.find((d) => d.id === "heater");
|
|
10407
10524
|
if (heater && sh.electric === false) {
|
|
10408
|
-
spec.devices =
|
|
10525
|
+
spec.devices = devices.filter((d) => d !== heater);
|
|
10409
10526
|
for (const f of spec.fixtures || []) if (f.heater === "heater") delete f.heater;
|
|
10410
10527
|
} else if (heater) {
|
|
10411
10528
|
if (sh.powerW) heater.watts = sh.powerW;
|
|
@@ -10416,7 +10533,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10416
10533
|
for (const b of spec.burners || []) if (b.fuel === "auto") b.fuel = L.fuel;
|
|
10417
10534
|
}
|
|
10418
10535
|
if (entry2.type === "fireplace" && L.chimneyTop) {
|
|
10419
|
-
const it = entry2.item;
|
|
10536
|
+
const it = at(entry2.item);
|
|
10420
10537
|
const dx = L.chimneyTop[0] - it.x;
|
|
10421
10538
|
const dz = L.chimneyTop[2] - it.z;
|
|
10422
10539
|
const lx = Math.cos(it.ry) * dx - Math.sin(it.ry) * dz;
|
|
@@ -10435,8 +10552,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10435
10552
|
}
|
|
10436
10553
|
return spec;
|
|
10437
10554
|
}
|
|
10438
|
-
function createWorld(
|
|
10439
|
-
|
|
10555
|
+
function createWorld(source, options2 = {}) {
|
|
10556
|
+
const res = sourceOf(source);
|
|
10557
|
+
const copts = options2 || {};
|
|
10440
10558
|
const info = { points: /* @__PURE__ */ new Map(), water: copts.water || null, lightsOn: copts.lightsOn };
|
|
10441
10559
|
const electrical = res.utilities && res.utilities.electrical;
|
|
10442
10560
|
const world = GI.createWorld({
|
|
@@ -10464,8 +10582,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10464
10582
|
const info = worlds.get(world);
|
|
10465
10583
|
return info ? info.points.get(fixtureId) : void 0;
|
|
10466
10584
|
}
|
|
10467
|
-
function blockedOf(
|
|
10468
|
-
|
|
10585
|
+
function blockedOf(source, options2 = {}) {
|
|
10586
|
+
const res = sourceOf(source);
|
|
10587
|
+
const bopts = options2 || {};
|
|
10469
10588
|
const ox = bopts.originX || 0;
|
|
10470
10589
|
const oz = bopts.originZ || 0;
|
|
10471
10590
|
const inw = bopts.inw || 1;
|
|
@@ -10500,33 +10619,33 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10500
10619
|
return false;
|
|
10501
10620
|
};
|
|
10502
10621
|
}
|
|
10503
|
-
function add(world, planned,
|
|
10504
|
-
aopts =
|
|
10622
|
+
function add(world, planned, options2 = {}) {
|
|
10623
|
+
const aopts = options2 || {};
|
|
10505
10624
|
const info = worlds.get(world);
|
|
10506
|
-
const build = aopts.build || ((type, item) => hh.build(type, item,
|
|
10625
|
+
const build = aopts.build || ((type, item) => hh.build(type, item, recorderApi()));
|
|
10507
10626
|
const isBlocked = aopts.isBlocked || null;
|
|
10508
10627
|
const out = { added: 0, parts: [], hinges: {}, moved: {}, warnings: [] };
|
|
10509
10628
|
const override = aopts.lightsOn !== void 0 ? aopts.lightsOn : info && info.lightsOn;
|
|
10510
10629
|
if (override !== void 0) {
|
|
10511
10630
|
for (const e of planned.items) if (e.type === "lamp") e.lit = typeof override === "function" ? !!override(e.id, e) : !!override;
|
|
10512
10631
|
for (const e of planned.items) if (e.type === "lantern_lamp") e.lit = typeof override === "function" ? !!override(e.id, e) : !!override;
|
|
10513
|
-
for (const e of planned.items) if (e.type === "wall_switch") e.lit = (e.connections.controls || []).some((id) =>
|
|
10632
|
+
for (const e of planned.items) if (e.type === "wall_switch") e.lit = (e.connections.controls || []).some((id) => planned.items.find((x) => x.id === id)?.lit === true);
|
|
10514
10633
|
}
|
|
10515
10634
|
for (const e of planned.items) if (e.type === "lantern_lamp") e.item.on = !!e.lit;
|
|
10516
10635
|
let scratch = null;
|
|
10517
|
-
function probe(e, hinge, setback) {
|
|
10636
|
+
function probe(e, hinge, setback, blockedAt) {
|
|
10518
10637
|
if (!scratch) scratch = GI.createWorld({ locale, strings: hh.strings, items: hh.items, loot: hh.loot, grid: false });
|
|
10519
|
-
const it = e.item;
|
|
10638
|
+
const it = at(e.item);
|
|
10520
10639
|
const x = it.x + Math.sin(it.ry) * setback;
|
|
10521
10640
|
const z = it.z + Math.cos(it.ry) * setback;
|
|
10522
|
-
const spec = hh.build(e.type, Object.assign({},
|
|
10641
|
+
const spec = hh.build(e.type, Object.assign({}, e.item, { hinge }), recorderApi());
|
|
10523
10642
|
scratch.add("__probe", spec, { x, y: e.floorY, z, ry: it.ry });
|
|
10524
|
-
const blocks = (px, pz) =>
|
|
10643
|
+
const blocks = (px, pz) => blockedAt(px, pz, e.floor);
|
|
10525
10644
|
let sum = 0;
|
|
10526
10645
|
let min = 1;
|
|
10527
10646
|
let n = 0;
|
|
10528
10647
|
for (const p of spec.parts || []) {
|
|
10529
|
-
if (p.motion.kind !== "hinge" || !(p.bounds || p.sweep)) continue;
|
|
10648
|
+
if (!p.motion || p.motion.kind !== "hinge" || !(p.bounds || p.sweep)) continue;
|
|
10530
10649
|
const t = scratch.fitSweep("__probe", p.id, blocks);
|
|
10531
10650
|
sum += t;
|
|
10532
10651
|
min = Math.min(min, t);
|
|
@@ -10538,12 +10657,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10538
10657
|
const better = (a, b) => a.sum > b.sum + 1e-9 || Math.abs(a.sum - b.sum) <= 1e-9 && a.min > b.min + 1e-9;
|
|
10539
10658
|
function fitDoors(e) {
|
|
10540
10659
|
if (!isBlocked || !householdTypes.has(e.type)) return;
|
|
10541
|
-
const standard = probe(e, void 0, 0);
|
|
10660
|
+
const standard = probe(e, void 0, 0, isBlocked);
|
|
10542
10661
|
if (!standard.n || standard.min >= 1) return;
|
|
10543
10662
|
let bestSide;
|
|
10544
10663
|
let m = standard;
|
|
10545
10664
|
for (const side of ["left", "right"]) {
|
|
10546
|
-
const r = probe(e, side, 0);
|
|
10665
|
+
const r = probe(e, side, 0, isBlocked);
|
|
10547
10666
|
if (better(r, m)) {
|
|
10548
10667
|
m = r;
|
|
10549
10668
|
bestSide = side;
|
|
@@ -10556,13 +10675,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10556
10675
|
if (m.min >= 1) return;
|
|
10557
10676
|
let target = { setback: 0, r: m };
|
|
10558
10677
|
for (const setback of [0.01, 0.02, 0.03, 0.04]) {
|
|
10559
|
-
const r = probe(e, bestSide, setback);
|
|
10678
|
+
const r = probe(e, bestSide, setback, isBlocked);
|
|
10560
10679
|
if (better(r, target.r)) target = { setback, r };
|
|
10561
10680
|
if (r.min >= 1) break;
|
|
10562
10681
|
}
|
|
10563
10682
|
if (target.setback > 0 && target.r.sum > m.sum + 0.2) {
|
|
10564
|
-
|
|
10565
|
-
e.item.
|
|
10683
|
+
const p = at(e.item);
|
|
10684
|
+
e.item.x = r3(p.x + Math.sin(p.ry) * target.setback);
|
|
10685
|
+
e.item.z = r3(p.z + Math.cos(p.ry) * target.setback);
|
|
10566
10686
|
e.moved = target.setback;
|
|
10567
10687
|
out.moved[e.id] = target.setback;
|
|
10568
10688
|
}
|
|
@@ -10585,7 +10705,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10585
10705
|
}
|
|
10586
10706
|
}
|
|
10587
10707
|
connect(e, spec);
|
|
10588
|
-
|
|
10708
|
+
const pose = at(e.item);
|
|
10709
|
+
world.add(e.id, spec, { x: pose.x, y: e.floorY, z: pose.z, ry: pose.ry });
|
|
10589
10710
|
out.added++;
|
|
10590
10711
|
if (!isBlocked) continue;
|
|
10591
10712
|
for (const p of spec.parts || []) {
|
|
@@ -10614,7 +10735,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10614
10735
|
return null;
|
|
10615
10736
|
}
|
|
10616
10737
|
const A = AD.plan ? AD : AD.create({ ...o.adapterOptions || {}, GameInteractables: GI, GameInteractablesHousehold: HH, locale: o.locale || cfg.locale, region: o.region, ...cfg.seedKey ? { seedKey: cfg.seedKey } : {} });
|
|
10617
|
-
return { GI, HH, GT, A, gfx: GT.createThreeAdapter(THREE, { document: DOC, Reflector }), items: o.items !== false, effects: o.effects !== false, camera: o.camera || null, onEvent: o.onEvent || null, onSeat: o.onSeat || null };
|
|
10738
|
+
return { GI, HH, GT, A, gfx: GT.createThreeAdapter(THREE, { document: DOC, Reflector }), items: o.items !== false, effects: o.effects !== false, effectSink: o.effectSink || null, camera: o.camera || null, onEvent: o.onEvent || null, onSeat: o.onSeat || null };
|
|
10618
10739
|
})();
|
|
10619
10740
|
const VEG = (() => {
|
|
10620
10741
|
const l = cfg.vegetation || null, G = l && (l.GameVegetation || (l.buildLot ? l : null)), S = l && (l.GameVegetationSpecies || (l.toSpec ? l : null));
|
|
@@ -10631,7 +10752,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10631
10752
|
|
|
10632
10753
|
// src/lights/room-light.ts
|
|
10633
10754
|
function installLightsRoomLight(K, shared) {
|
|
10634
|
-
const { THREE, rectsOf: rectsOf2 } = K;
|
|
10755
|
+
const { THREE, rectsOf: rectsOf2, cfg } = K;
|
|
10635
10756
|
const MAX_LIGHTS = 12, EMPTY = [1e9, 1e9, -1e9, -1e9];
|
|
10636
10757
|
const LZU = { uRB0: { value: new Float32Array(MAX_LIGHTS * 4) }, uRB1: { value: new Float32Array(MAX_LIGHTS * 4) }, uRB2: { value: new Float32Array(MAX_LIGHTS * 4) }, uRBY: { value: new Float32Array(MAX_LIGHTS * 2) }, uREx: { value: new Float32Array(MAX_LIGHTS * 4) }, uIndK: { value: 0.06 } };
|
|
10637
10758
|
for (let i = 0; i < MAX_LIGHTS; i++) for (const k of ["uRB0", "uRB1", "uRB2", "uREx"]) LZU[k].value.set(EMPTY, i * 4);
|
|
@@ -10670,8 +10791,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10670
10791
|
o = o || {};
|
|
10671
10792
|
const scene = o.scene, N = Math.max(1, Math.min(MAX_LIGHTS, o.n || 6)), NS = Math.max(0, Math.min(N, o.shadows != null ? o.shadows : 2)), size = o.shadowSize || 512, MAX_EXTERNAL = o.external != null ? o.external : 2;
|
|
10672
10793
|
for (const k of Object.keys(shared.mats)) roomLightMask(shared.mats[k]);
|
|
10794
|
+
const budget = o.budget, lease = budget ? budget.lease({ owner: "floorplan.rooms", point: N, shadows: NS }) : null;
|
|
10795
|
+
if (budget && !lease) throw new Error("lighting: the LightBudget has no " + N + " free point slots (" + NS + " with shadow) for the rooms");
|
|
10796
|
+
if (budget) for (const [key, width] of [["uRB0", 4], ["uRB1", 4], ["uRB2", 4], ["uRBY", 2], ["uREx", 4]]) {
|
|
10797
|
+
const next = new Float32Array(budget.sizes.point * width);
|
|
10798
|
+
if (width === 4) for (let i = 0; i < budget.sizes.point; i++) next.set(EMPTY, i * 4);
|
|
10799
|
+
LZU[key].value = next;
|
|
10800
|
+
}
|
|
10673
10801
|
const PL = [], sig = new Array(N).fill(""), seg = { n: 0 };
|
|
10674
|
-
for (let i = 0; i < N; i++) {
|
|
10802
|
+
if (!lease) for (let i = 0; i < N; i++) {
|
|
10675
10803
|
const l = new THREE.PointLight(16763008, 0, 8, 1.6);
|
|
10676
10804
|
l.visible = true;
|
|
10677
10805
|
l.castShadow = i < NS;
|
|
@@ -10687,12 +10815,30 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10687
10815
|
if (scene) scene.add(l);
|
|
10688
10816
|
PL.push(l);
|
|
10689
10817
|
}
|
|
10690
|
-
const
|
|
10818
|
+
const slotOf = (i) => lease ? lease.handles[i].slot : i;
|
|
10819
|
+
const put = (i, v) => {
|
|
10820
|
+
if (lease) {
|
|
10821
|
+
lease.handles[i].update(v.color === void 0 || typeof v.color === "number" ? v : { ...v, color: new THREE.Color(v.color).getHex() });
|
|
10822
|
+
return;
|
|
10823
|
+
}
|
|
10824
|
+
const pl = PL[i];
|
|
10825
|
+
if (v.position) pl.position.set(v.position[0], v.position[1], v.position[2]);
|
|
10826
|
+
if (v.color !== void 0) pl.color.set(v.color);
|
|
10827
|
+
if (v.intensity !== void 0) pl.intensity = v.intensity;
|
|
10828
|
+
if (v.distance !== void 0) pl.distance = v.distance;
|
|
10829
|
+
if (v.decay !== void 0) pl.decay = v.decay;
|
|
10830
|
+
};
|
|
10831
|
+
const effects = lease ? effectLights({ budget, ours: lease.handles.map((h) => h.slot) }) : null;
|
|
10832
|
+
const A = { lights: lease ? lease.handles : PL, crates: new Array(N).fill(null), n: N, shadows: NS, stats: { rooms: 0, external: 0, shadows: 0, shadowChanged: false }, indirect: (v) => {
|
|
10691
10833
|
LZU.uIndK.value = v;
|
|
10692
10834
|
} };
|
|
10693
10835
|
const _p = new THREE.Vector3(), _f = new THREE.Vector3();
|
|
10694
10836
|
const lim = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
10695
10837
|
A.invalidate = () => {
|
|
10838
|
+
if (lease) {
|
|
10839
|
+
lease.invalidateShadow();
|
|
10840
|
+
return;
|
|
10841
|
+
}
|
|
10696
10842
|
for (let i = 0; i < NS; i++) PL[i].shadow.needsUpdate = true;
|
|
10697
10843
|
};
|
|
10698
10844
|
A.update = function(houses2, focus, op) {
|
|
@@ -10800,47 +10946,44 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10800
10946
|
A.stats.external = Ne;
|
|
10801
10947
|
let shadows = 0;
|
|
10802
10948
|
for (let i = 0; i < N; i++) {
|
|
10803
|
-
const
|
|
10949
|
+
const g = asg[i], at2 = slotOf(i), b0 = LZU.uRB0.value, b1 = LZU.uRB1.value, b2 = LZU.uRB2.value, by = LZU.uRBY.value, ex = LZU.uREx.value;
|
|
10804
10950
|
A.crates[i] = g ? { k: g.k, rects: g.rects, y: g.y, exterior: !!g.exterior, exclusion: g.exclusion || null, d: g.d } : null;
|
|
10805
10951
|
if (!g) {
|
|
10806
|
-
|
|
10807
|
-
for (const a of [b0, b1, b2, ex]) a.set(EMPTY,
|
|
10808
|
-
by.set([0, 0],
|
|
10952
|
+
put(i, { intensity: 0 });
|
|
10953
|
+
for (const a of [b0, b1, b2, ex]) a.set(EMPTY, at2 * 4);
|
|
10954
|
+
by.set([0, 0], at2 * 2);
|
|
10809
10955
|
continue;
|
|
10810
10956
|
}
|
|
10811
|
-
|
|
10812
|
-
|
|
10813
|
-
if (g.exterior) {
|
|
10814
|
-
pl.intensity = g.lumens;
|
|
10815
|
-
pl.distance = g.dist;
|
|
10816
|
-
pl.decay = g.decay;
|
|
10817
|
-
} else {
|
|
10818
|
-
pl.intensity = (7 + g.range * 0.8) * lim(1 + 0.4 * (Math.sqrt(g.n) - 1), 1, 2.2);
|
|
10819
|
-
pl.distance = Math.max(3, g.dm * 1.3 + 0.5);
|
|
10820
|
-
pl.decay = 1.6;
|
|
10821
|
-
}
|
|
10957
|
+
const lamp = g.exterior ? { intensity: g.lumens, distance: g.dist, decay: g.decay } : { intensity: (7 + g.range * 0.8) * lim(1 + 0.4 * (Math.sqrt(g.n) - 1), 1, 2.2), distance: Math.max(3, g.dm * 1.3 + 0.5), decay: 1.6 };
|
|
10958
|
+
put(i, { position: g.pos, color: g.color, ...lamp });
|
|
10822
10959
|
const rs = g.rects;
|
|
10823
|
-
b0.set(rs[0] || EMPTY,
|
|
10824
|
-
b1.set(rs[1] || EMPTY,
|
|
10825
|
-
b2.set(rs[2] || EMPTY,
|
|
10826
|
-
by.set(g.y,
|
|
10827
|
-
ex.set(g.exclusion || EMPTY,
|
|
10960
|
+
b0.set(rs[0] || EMPTY, at2 * 4);
|
|
10961
|
+
b1.set(rs[1] || EMPTY, at2 * 4);
|
|
10962
|
+
b2.set(rs[2] || EMPTY, at2 * 4);
|
|
10963
|
+
by.set(g.y, at2 * 2);
|
|
10964
|
+
ex.set(g.exclusion || EMPTY, at2 * 4);
|
|
10828
10965
|
if (i < NS) {
|
|
10829
10966
|
shadows++;
|
|
10830
10967
|
const s2 = g.house.group.uuid + "|" + g.k + "|" + g.pos.map((v) => v.toFixed(2)).join(",");
|
|
10831
10968
|
if (sig[i] !== s2) {
|
|
10832
10969
|
sig[i] = s2;
|
|
10833
|
-
|
|
10970
|
+
if (lease) lease.invalidateShadow(i);
|
|
10971
|
+
else PL[i].shadow.needsUpdate = true;
|
|
10834
10972
|
seg.n++;
|
|
10835
10973
|
A.stats.shadowChanged = true;
|
|
10836
10974
|
}
|
|
10837
|
-
|
|
10975
|
+
if (!lease) PL[i].shadow.camera.far = Math.max(4, lamp.distance);
|
|
10838
10976
|
}
|
|
10839
10977
|
}
|
|
10978
|
+
if (effects) effects.update(houses2);
|
|
10840
10979
|
A.stats.shadows = shadows;
|
|
10841
10980
|
return A.stats;
|
|
10842
10981
|
};
|
|
10843
10982
|
A.dispose = () => {
|
|
10983
|
+
if (lease) {
|
|
10984
|
+
lease.release();
|
|
10985
|
+
return;
|
|
10986
|
+
}
|
|
10844
10987
|
for (const l of PL) {
|
|
10845
10988
|
if (l.shadow && l.shadow.map) l.shadow.map.dispose();
|
|
10846
10989
|
l.removeFromParent();
|
|
@@ -10848,59 +10991,116 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10848
10991
|
};
|
|
10849
10992
|
return A;
|
|
10850
10993
|
}
|
|
10851
|
-
|
|
10852
|
-
|
|
10853
|
-
|
|
10854
|
-
|
|
10855
|
-
|
|
10856
|
-
|
|
10857
|
-
|
|
10858
|
-
|
|
10859
|
-
[
|
|
10860
|
-
[
|
|
10861
|
-
|
|
10862
|
-
|
|
10863
|
-
|
|
10864
|
-
|
|
10865
|
-
|
|
10866
|
-
|
|
10867
|
-
|
|
10868
|
-
|
|
10869
|
-
|
|
10870
|
-
|
|
10871
|
-
|
|
10872
|
-
|
|
10873
|
-
|
|
10874
|
-
|
|
10875
|
-
|
|
10876
|
-
|
|
10877
|
-
|
|
10878
|
-
|
|
10879
|
-
|
|
10880
|
-
|
|
10881
|
-
|
|
10882
|
-
|
|
10883
|
-
|
|
10884
|
-
|
|
10885
|
-
|
|
10886
|
-
|
|
10994
|
+
const effectsByBudget = /* @__PURE__ */ new WeakMap();
|
|
10995
|
+
const OPENING_REACH = 2.5, OPENING_SIDE = 0.6;
|
|
10996
|
+
function effectLights(o) {
|
|
10997
|
+
o = o || {};
|
|
10998
|
+
const budget = o.budget;
|
|
10999
|
+
if (!budget) throw new Error("effectLights: a LightBudget is required");
|
|
11000
|
+
const known = effectsByBudget.get(budget);
|
|
11001
|
+
if (known && !o.ours) return known;
|
|
11002
|
+
const ours = new Set(o.ours || []), size = budget.sizes.point, _p = new THREE.Vector3(), P0 = new THREE.Vector3();
|
|
11003
|
+
for (const [key, width] of [["uRB0", 4], ["uRB1", 4], ["uRB2", 4], ["uRBY", 2], ["uREx", 4]]) {
|
|
11004
|
+
const had = LZU[key].value;
|
|
11005
|
+
if (had.length >= size * width) continue;
|
|
11006
|
+
const next = new Float32Array(size * width);
|
|
11007
|
+
if (width === 4) for (let i = 0; i < size; i++) next.set(EMPTY, i * 4);
|
|
11008
|
+
next.set(had);
|
|
11009
|
+
LZU[key].value = next;
|
|
11010
|
+
}
|
|
11011
|
+
const roomBoxes = (house, M) => {
|
|
11012
|
+
const list2 = [];
|
|
11013
|
+
for (const c of house.r.rooms) {
|
|
11014
|
+
if (c.type === "void") continue;
|
|
11015
|
+
const rs = [];
|
|
11016
|
+
for (const [a, b, c2, d] of rectsOf2(c)) {
|
|
11017
|
+
let x0 = 1e9, z0 = 1e9, x1 = -1e9, z1 = -1e9;
|
|
11018
|
+
for (const [u, v] of [[a, b], [c2, b], [a, d], [c2, d]]) {
|
|
11019
|
+
_p.set(u, 0, v).applyMatrix4(M);
|
|
11020
|
+
x0 = Math.min(x0, _p.x);
|
|
11021
|
+
x1 = Math.max(x1, _p.x);
|
|
11022
|
+
z0 = Math.min(z0, _p.z);
|
|
11023
|
+
z1 = Math.max(z1, _p.z);
|
|
11024
|
+
}
|
|
11025
|
+
rs.push([x0 - 0.08, z0 - 0.08, x1 + 0.08, z1 + 0.08]);
|
|
11026
|
+
}
|
|
11027
|
+
_p.set(0, house.y0(c.floor), 0).applyMatrix4(M);
|
|
11028
|
+
list2.push({ c, rs, y: [_p.y - 0.06, _p.y + (c.ceiling || 2.8) + 0.3] });
|
|
11029
|
+
}
|
|
11030
|
+
return list2;
|
|
11031
|
+
};
|
|
11032
|
+
const boxAt = (boxes, x, y, z) => boxes.find((q) => y >= q.y[0] && y <= q.y[1] && q.rs.some((r) => x >= r[0] && x <= r[2] && z >= r[1] && z <= r[3]));
|
|
11033
|
+
const openingSides = (house, M, boxes, into) => {
|
|
11034
|
+
const open = house.internal && house.internal.doorState || /* @__PURE__ */ new Map();
|
|
11035
|
+
const reach = (list2, isDoor) => {
|
|
11036
|
+
for (const p of list2 || []) {
|
|
11037
|
+
if (isDoor && !(open.has(p.id) ? open.get(p.id) : !!p.open)) continue;
|
|
11038
|
+
const alongU = p.axis === "u", y = house.y0(p.floor) + (isDoor ? 1 : ((p.y0 != null ? p.y0 : 0.9) + (p.y1 != null ? p.y1 : 2)) / 2);
|
|
11039
|
+
const at2 = (side) => _p.set(alongU ? p.at : p.pos + side, y, alongU ? p.pos + side : p.at).applyMatrix4(M).clone();
|
|
11040
|
+
if (at2(0).distanceTo(P0) > OPENING_REACH) continue;
|
|
11041
|
+
for (const side of [-OPENING_SIDE, OPENING_SIDE]) {
|
|
11042
|
+
const w = at2(side), hit = boxAt(boxes, w.x, w.y, w.z);
|
|
11043
|
+
if (hit) into.set(hit.c, hit);
|
|
11044
|
+
}
|
|
11045
|
+
}
|
|
11046
|
+
};
|
|
11047
|
+
reach(house.r.doors, true);
|
|
11048
|
+
reach(house.r.windows, false);
|
|
11049
|
+
};
|
|
11050
|
+
const clear = (at2) => {
|
|
11051
|
+
for (const key of ["uRB0", "uRB1", "uRB2", "uREx"]) LZU[key].value.set(EMPTY, at2 * 4);
|
|
11052
|
+
LZU.uRBY.value.set([0, 0], at2 * 2);
|
|
11053
|
+
};
|
|
11054
|
+
const write = (at2, into) => {
|
|
11055
|
+
const rs = [];
|
|
11056
|
+
let lo = 1e9, hi = -1e9;
|
|
11057
|
+
for (const q of into.values()) {
|
|
11058
|
+
rs.push(...q.rs);
|
|
11059
|
+
lo = Math.min(lo, q.y[0]);
|
|
11060
|
+
hi = Math.max(hi, q.y[1]);
|
|
11061
|
+
}
|
|
11062
|
+
while (rs.length > 3) {
|
|
11063
|
+
const r23 = rs.pop(), r1 = rs[rs.length - 1];
|
|
11064
|
+
rs[rs.length - 1] = [Math.min(r1[0], r23[0]), Math.min(r1[1], r23[1]), Math.max(r1[2], r23[2]), Math.max(r1[3], r23[3])];
|
|
11065
|
+
}
|
|
11066
|
+
LZU.uRB0.value.set(rs[0] || EMPTY, at2 * 4);
|
|
11067
|
+
LZU.uRB1.value.set(rs[1] || EMPTY, at2 * 4);
|
|
11068
|
+
LZU.uRB2.value.set(rs[2] || EMPTY, at2 * 4);
|
|
11069
|
+
LZU.uRBY.value.set([lo, hi], at2 * 2);
|
|
11070
|
+
LZU.uREx.value.set(EMPTY, at2 * 4);
|
|
11071
|
+
};
|
|
11072
|
+
const A = {
|
|
11073
|
+
/** Once per frame, after the budget's `present`: points the mask of every lit slot that is not the house's at the rooms its light reaches. */
|
|
11074
|
+
update(houses2) {
|
|
11075
|
+
const indoors = cfg.effectLightsIndoors !== false, list2 = (Array.isArray(houses2) ? houses2 : [houses2]).filter(Boolean), cache2 = /* @__PURE__ */ new Map();
|
|
11076
|
+
for (let at2 = 0; at2 < size; at2++) {
|
|
11077
|
+
if (ours.has(at2)) continue;
|
|
11078
|
+
const light = budget.group.children[at2];
|
|
11079
|
+
if (!indoors || !light || !light.isPointLight || !(light.intensity > 0) || !light.visible) {
|
|
11080
|
+
clear(at2);
|
|
11081
|
+
continue;
|
|
11082
|
+
}
|
|
11083
|
+
const into = /* @__PURE__ */ new Map();
|
|
11084
|
+
P0.set(light.position.x, light.position.y, light.position.z);
|
|
11085
|
+
for (const house of list2) {
|
|
11086
|
+
if (house.group && !house.group.visible) continue;
|
|
11087
|
+
house.house.updateMatrixWorld(true);
|
|
11088
|
+
const M = house.house.matrixWorld;
|
|
11089
|
+
let boxes = cache2.get(house);
|
|
11090
|
+
if (!boxes) cache2.set(house, boxes = roomBoxes(house, M));
|
|
11091
|
+
const here = boxAt(boxes, P0.x, P0.y, P0.z);
|
|
11092
|
+
if (here) into.set(here.c, here);
|
|
11093
|
+
openingSides(house, M, boxes, into);
|
|
11094
|
+
}
|
|
11095
|
+
if (into.size) write(at2, into);
|
|
11096
|
+
else clear(at2);
|
|
11097
|
+
}
|
|
11098
|
+
}
|
|
11099
|
+
};
|
|
11100
|
+
if (!o.ours) effectsByBudget.set(budget, A);
|
|
11101
|
+
return A;
|
|
10887
11102
|
}
|
|
10888
|
-
|
|
10889
|
-
};
|
|
10890
|
-
var sparkTargetFactor = (materialId, metal, rules = DEFAULT_IGNITION_RULES) => !metal ? 0 : rules.sparkTarget[materialId] ?? rules.sparkMetalDefault;
|
|
10891
|
-
var ignitionChance = (hit, target, rules = DEFAULT_IGNITION_RULES) => {
|
|
10892
|
-
const k = fillFactor(target.fill, rules.fillCurve);
|
|
10893
|
-
const spark = (hit.ignition?.spark ?? 0) * target.sparkTarget * (target.fluid === void 0 ? 1 : rules.sparkFluid[target.fluid] ?? 1) * k;
|
|
10894
|
-
const flameBase = hit.ignition?.flame ?? Math.max(hit.incendiary ? rules.flameDefaults.incendiary : 0, hit.tracer ? rules.flameDefaults.tracer : 0);
|
|
10895
|
-
const flame = flameBase * (1 - rules.flameFillInfluence * (1 - k));
|
|
10896
|
-
return 1 - (1 - Math.min(1, Math.max(0, spark))) * (1 - Math.min(1, Math.max(0, flame)));
|
|
10897
|
-
};
|
|
10898
|
-
var KIT_ORIGIN_KEY = "kitOrigin";
|
|
10899
|
-
function markKitOrigin(object2, origin) {
|
|
10900
|
-
const node = object2;
|
|
10901
|
-
node.userData = node.userData ?? {};
|
|
10902
|
-
node.userData[KIT_ORIGIN_KEY] = { ...origin };
|
|
10903
|
-
return object2;
|
|
11103
|
+
Object.assign(K, { MAX_LIGHTS, EMPTY, LZU, roomLightMask, lighting, effectLights });
|
|
10904
11104
|
}
|
|
10905
11105
|
|
|
10906
11106
|
// ../game-destruction/dist/index.js
|
|
@@ -11250,11 +11450,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
11250
11450
|
}
|
|
11251
11451
|
return pieces.slice(0, limit).map((p) => ({ center: p.c, size: [p.s[g], p.s[a], p.s[b]], q: frame(g, a, b), shape: "splinter", weight: p.s[0] * p.s[1] * p.s[2] }));
|
|
11252
11452
|
};
|
|
11253
|
-
var severAt = (inp, root,
|
|
11453
|
+
var severAt = (inp, root, at2, gap) => {
|
|
11254
11454
|
const dims = root.s;
|
|
11255
11455
|
const L = [0, 1, 2].sort((x, y) => dims[y] - dims[x])[0];
|
|
11256
11456
|
const half = dims[L] / 2;
|
|
11257
|
-
const lo = clamp(
|
|
11457
|
+
const lo = clamp(at2 - gap / 2, -half, half), hi = clamp(at2 + gap / 2, -half, half);
|
|
11258
11458
|
const out = [];
|
|
11259
11459
|
const stub = (from, to) => {
|
|
11260
11460
|
if (to - from < 0.02) return;
|
|
@@ -13613,6 +13813,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
13613
13813
|
const ignitionRules = resolveIgnitionRules(options.ignition);
|
|
13614
13814
|
const breachBlastFactor = options.breach?.blastFactor ?? BREACH_BLAST_FACTOR;
|
|
13615
13815
|
const chipEnergy = options.breach?.chipEnergy ?? CHIP_ENERGY;
|
|
13816
|
+
const chainLinkCap = options.chainLinksPerUpdate !== void 0 && options.chainLinksPerUpdate >= 1 ? Math.floor(options.chainLinksPerUpdate) : Infinity;
|
|
13616
13817
|
const rng2 = createRng(options.seed ?? 1);
|
|
13617
13818
|
const rnd = () => rng2.next();
|
|
13618
13819
|
let time = 0;
|
|
@@ -13635,7 +13836,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
13635
13836
|
const typed = listeners.get(e.type);
|
|
13636
13837
|
if (typed) for (const fn of [...typed]) fn(e);
|
|
13637
13838
|
};
|
|
13638
|
-
|
|
13839
|
+
let blow;
|
|
13840
|
+
const base = (o, source) => ({
|
|
13841
|
+
object: o.id,
|
|
13842
|
+
time,
|
|
13843
|
+
...source === void 0 ? {} : { source },
|
|
13844
|
+
...blow === void 0 ? {} : { blow }
|
|
13845
|
+
});
|
|
13639
13846
|
const pendingCollapse = /* @__PURE__ */ new Map();
|
|
13640
13847
|
let runDepth = 0;
|
|
13641
13848
|
const drainBlasts = () => {
|
|
@@ -13905,9 +14112,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
13905
14112
|
const [lo, hi] = contactBox(p, above);
|
|
13906
14113
|
return toWorld(p.pos, p.q, [(lo[0] + hi[0]) / 2, (lo[1] + hi[1]) / 2, (lo[2] + hi[2]) / 2]);
|
|
13907
14114
|
};
|
|
13908
|
-
const overSupportAt = (o, p,
|
|
14115
|
+
const overSupportAt = (o, p, at2, lower) => {
|
|
13909
14116
|
const g = p.bend;
|
|
13910
|
-
const local = toLocal(p.pos, p.q,
|
|
14117
|
+
const local = toLocal(p.pos, p.q, at2);
|
|
13911
14118
|
const depth = g.gravity >= 0 ? g.dims[g.gravity] : Math.min(...g.depthAxes.map((a) => g.dims[a]));
|
|
13912
14119
|
let best = -1;
|
|
13913
14120
|
let bestGap = depth;
|
|
@@ -14061,10 +14268,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14061
14268
|
const incoming = new Array(n).fill(0);
|
|
14062
14269
|
const bending = new Array(n).fill(0);
|
|
14063
14270
|
const through = parts.map(() => []);
|
|
14064
|
-
const pass = (k,
|
|
14065
|
-
const over = overSupportAt(o, parts[k],
|
|
14271
|
+
const pass = (k, at2, mass) => {
|
|
14272
|
+
const over = overSupportAt(o, parts[k], at2, lowerOf.get(k) ?? []);
|
|
14066
14273
|
if (over < 0) bending[k] += mass;
|
|
14067
|
-
else through[k].push({ at, mass, over });
|
|
14274
|
+
else through[k].push({ at: at2, mass, over });
|
|
14068
14275
|
};
|
|
14069
14276
|
for (let h = queue.length - 1; h >= 0; h--) {
|
|
14070
14277
|
const i = queue[h];
|
|
@@ -14131,7 +14338,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14131
14338
|
const terrain = cfg.terrains.get(cfg.terrain);
|
|
14132
14339
|
if (!terrain) throw new Error(`unknown wind terrain "${cfg.terrain}"`);
|
|
14133
14340
|
const inputs = [];
|
|
14134
|
-
const
|
|
14341
|
+
const at2 = /* @__PURE__ */ new Map();
|
|
14135
14342
|
const keep = [];
|
|
14136
14343
|
let ground = Infinity, foundationTop = -Infinity;
|
|
14137
14344
|
o.parts.forEach((p, i) => {
|
|
@@ -14140,7 +14347,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14140
14347
|
const role = p.spec.structure?.role;
|
|
14141
14348
|
const e = p.mat.strength?.elasticGPa;
|
|
14142
14349
|
const kind = role === "wall" ? "wall" : role === "column" ? "column" : role === "beam" ? "beam" : role === "foundation" ? "foundation" : "other";
|
|
14143
|
-
|
|
14350
|
+
at2.set(i, inputs.length);
|
|
14144
14351
|
keep.push(i);
|
|
14145
14352
|
ground = Math.min(ground, box3.min[1]);
|
|
14146
14353
|
if (kind === "foundation") foundationTop = Math.max(foundationTop, box3.max[1]);
|
|
@@ -14151,7 +14358,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14151
14358
|
const beams = [];
|
|
14152
14359
|
for (const j of o.byPart.get(o.parts[i].spec.id)) {
|
|
14153
14360
|
if (j.st.open) continue;
|
|
14154
|
-
const b =
|
|
14361
|
+
const b = at2.get(j.ia === i ? j.ib : j.ia);
|
|
14155
14362
|
if (b !== void 0 && inputs[b].kind === "beam") beams.push(b);
|
|
14156
14363
|
}
|
|
14157
14364
|
inputs[k].beams = beams;
|
|
@@ -14560,7 +14767,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14560
14767
|
if (disc < 0) return true;
|
|
14561
14768
|
return -b - Math.sqrt(disc) > maxDist;
|
|
14562
14769
|
};
|
|
14563
|
-
const raycastInternal = (origin, dir, maxDist, ignore, worldOnly = false) => {
|
|
14770
|
+
const raycastInternal = (origin, dir, maxDist, ignore, worldOnly = false, precise = false) => {
|
|
14564
14771
|
const d = vec.normalize(dir);
|
|
14565
14772
|
let best = null;
|
|
14566
14773
|
for (const o of objects.values()) {
|
|
@@ -14575,13 +14782,25 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14575
14782
|
}
|
|
14576
14783
|
}
|
|
14577
14784
|
for (const im of worldOnly ? [] : impls.values()) {
|
|
14785
|
+
let boxHit = null;
|
|
14578
14786
|
for (const ps of im.impl.describe().parts) {
|
|
14579
14787
|
if (ignore?.has(`${im.impl.id}\0${ps.id}`)) continue;
|
|
14580
14788
|
const ov = im.poses.get(ps.id);
|
|
14581
14789
|
const r = rayPartRaw(im.position, im.rotation, ps, ov?.q ?? quatFromEuler(...ps.rotation ?? [0, 0, 0]), origin, d, ov?.pos);
|
|
14582
|
-
if (!r || r.
|
|
14583
|
-
if (
|
|
14790
|
+
if (!r || r.t1 < 0 || r.t0 > maxDist) continue;
|
|
14791
|
+
if (r.t0 < 0) {
|
|
14792
|
+
if (precise && im.impl.surfaceRay) boxHit = boxHit ?? { object: im.impl.id, part: ps.id, point: origin, normal: r.n, distance: 0, pathLen: r.t1 };
|
|
14793
|
+
continue;
|
|
14794
|
+
}
|
|
14795
|
+
if (!boxHit || r.t0 < boxHit.distance) boxHit = { object: im.impl.id, part: ps.id, point: vec.madd(origin, d, r.t0), normal: r.n, distance: r.t0, pathLen: r.t1 - r.t0 };
|
|
14584
14796
|
}
|
|
14797
|
+
if (!boxHit) continue;
|
|
14798
|
+
if (precise && im.impl.surfaceRay) {
|
|
14799
|
+
const far = best ? Math.min(maxDist, best.distance) : maxDist;
|
|
14800
|
+
const implId = im.impl.id;
|
|
14801
|
+
const s = im.impl.surfaceRay({ origin, direction: d, maxDistance: far, ...ignore ? { ignored: (part) => ignore.has(`${implId}\0${part}`) } : {} });
|
|
14802
|
+
if (s && (!best || s.distance < best.distance)) best = { object: implId, part: s.part, point: s.point, normal: s.normal, distance: s.distance, pathLen: s.pathLen };
|
|
14803
|
+
} else if (!best || boxHit.distance < best.distance) best = boxHit;
|
|
14585
14804
|
}
|
|
14586
14805
|
return best;
|
|
14587
14806
|
};
|
|
@@ -14955,7 +15174,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14955
15174
|
}
|
|
14956
15175
|
};
|
|
14957
15176
|
const tornToEdge = (o) => {
|
|
14958
|
-
const { p, cell, a, b, at, crater: crater2, reach, gone } = o;
|
|
15177
|
+
const { p, cell, a, b, at: at2, crater: crater2, reach, gone } = o;
|
|
14959
15178
|
const half = p.dims[a] / 2;
|
|
14960
15179
|
const lo = cell.center[a] - cell.size[a] / 2, hi = cell.center[a] + cell.size[a] / 2;
|
|
14961
15180
|
const free = (side, sign2) => {
|
|
@@ -14963,8 +15182,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14963
15182
|
const probe = side + sign2 * 1e-3;
|
|
14964
15183
|
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);
|
|
14965
15184
|
};
|
|
14966
|
-
if (
|
|
14967
|
-
if (hi -
|
|
15185
|
+
if (at2 - lo <= reach && free(lo, -1)) return [lo, Math.max(crater2[1], lo)];
|
|
15186
|
+
if (hi - at2 <= reach && free(hi, 1)) return [Math.min(crater2[0], hi), hi];
|
|
14968
15187
|
return crater2;
|
|
14969
15188
|
};
|
|
14970
15189
|
const craterAcross = (energy) => clamp2(0.03 + 12e-4 * Math.sqrt(Math.max(0, energy)), 0.03, 0.14);
|
|
@@ -15768,7 +15987,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15768
15987
|
res.events = cur.slice(start);
|
|
15769
15988
|
return res;
|
|
15770
15989
|
};
|
|
15771
|
-
const
|
|
15990
|
+
const withBlow = (type, fn) => () => {
|
|
15991
|
+
const outer = blow;
|
|
15992
|
+
blow = type;
|
|
15993
|
+
try {
|
|
15994
|
+
return fn();
|
|
15995
|
+
} finally {
|
|
15996
|
+
blow = outer;
|
|
15997
|
+
}
|
|
15998
|
+
};
|
|
15999
|
+
const doHit = (o, hit, only) => withBlow(hit.type, () => resolveHit(o, hit, only))();
|
|
16000
|
+
const resolveHit = (o, hit, only) => {
|
|
15772
16001
|
let point = hit.point;
|
|
15773
16002
|
let dir = hit.direction;
|
|
15774
16003
|
if (hit.space === "local") {
|
|
@@ -16065,7 +16294,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16065
16294
|
};
|
|
16066
16295
|
const detonatePrimed = (until) => {
|
|
16067
16296
|
const end = time;
|
|
16068
|
-
|
|
16297
|
+
let fired = 0;
|
|
16298
|
+
for (let next = nextPrimed(until); next && fired < chainLinkCap; next = nextPrimed(until)) {
|
|
16299
|
+
fired++;
|
|
16069
16300
|
primed.delete(next.p);
|
|
16070
16301
|
time = Math.max(0, Math.min(end, next.p.rt.chainDue));
|
|
16071
16302
|
next.p.rt.chainDue = void 0;
|
|
@@ -16135,6 +16366,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16135
16366
|
updateBound(o);
|
|
16136
16367
|
},
|
|
16137
16368
|
remove(id) {
|
|
16369
|
+
impls.get(id)?.impl.dispose?.();
|
|
16138
16370
|
objects.delete(id);
|
|
16139
16371
|
impls.delete(id);
|
|
16140
16372
|
},
|
|
@@ -16204,13 +16436,51 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16204
16436
|
blastProbe() {
|
|
16205
16437
|
return { ...blastProbe };
|
|
16206
16438
|
},
|
|
16439
|
+
blastReach(point, target, options2 = {}) {
|
|
16440
|
+
const L = vec.distance(point, target);
|
|
16441
|
+
if (L < 1e-4) return 1;
|
|
16442
|
+
const shelter = { ...SHELTER_DEFAULTS, ...options2.shelter };
|
|
16443
|
+
const ignore = new Set(options2.ignore ?? []);
|
|
16444
|
+
const d = vec.scale(vec.sub(target, point), 1 / L);
|
|
16445
|
+
let t = 1;
|
|
16446
|
+
for (const o of objects.values()) {
|
|
16447
|
+
if (ignore.has(o.id) || raySphereMiss(point, d, toWorld(o.st.position, o.st.rotation, o.bc), o.br, L)) continue;
|
|
16448
|
+
for (const p of o.parts) {
|
|
16449
|
+
if (isLost(p) || p.st.stripped) continue;
|
|
16450
|
+
const r = rayPart(o, p, point, d);
|
|
16451
|
+
if (!r) continue;
|
|
16452
|
+
const t0 = Math.max(r.t0, 0);
|
|
16453
|
+
const path = Math.min(r.t1, L) - t0;
|
|
16454
|
+
if (path < shelter.minPath) continue;
|
|
16455
|
+
if (p.st.opening && insideOpening(o, p, toLocal(o.st.position, o.st.rotation, vec.madd(point, d, t0 + path / 2)))) continue;
|
|
16456
|
+
t *= Math.exp(-(p.mat.hpPerKg * p.mat.density * path * (p.mat.damageScale?.shelter ?? 1)) / shelter.k);
|
|
16457
|
+
if (t < 1e-4) return 0;
|
|
16458
|
+
}
|
|
16459
|
+
}
|
|
16460
|
+
for (const im of impls.values()) {
|
|
16461
|
+
if (ignore.has(im.impl.id)) continue;
|
|
16462
|
+
for (const ps of im.impl.describe().parts) {
|
|
16463
|
+
const mat = materials.get(ps.material);
|
|
16464
|
+
if (!mat) continue;
|
|
16465
|
+
const ov = im.poses.get(ps.id);
|
|
16466
|
+
const r = rayPartRaw(im.position, im.rotation, ps, ov?.q ?? quatFromEuler(...ps.rotation ?? [0, 0, 0]), point, d, ov?.pos);
|
|
16467
|
+
if (!r || r.t1 < 0 || r.t0 > L) continue;
|
|
16468
|
+
let path = Math.min(r.t1, L) - Math.max(r.t0, 0);
|
|
16469
|
+
if (ps.thickness !== void 0 && ps.thickness > 0) path = Math.min(path, 2 * ps.thickness);
|
|
16470
|
+
else if (path < shelter.minPath) continue;
|
|
16471
|
+
t *= Math.exp(-(mat.hpPerKg * mat.density * path * (mat.damageScale?.shelter ?? 1)) / shelter.k);
|
|
16472
|
+
if (t < 1e-4) return 0;
|
|
16473
|
+
}
|
|
16474
|
+
}
|
|
16475
|
+
return t;
|
|
16476
|
+
},
|
|
16207
16477
|
explode(point, energy, radius, source, blast) {
|
|
16208
16478
|
blastProbe.partsTested = 0;
|
|
16209
16479
|
blastProbe.partsNear = 0;
|
|
16210
16480
|
return withCollapses(run(() => blastWorld(point, energy, radius, source, blast)));
|
|
16211
16481
|
},
|
|
16212
16482
|
raycast(origin, direction, maxDistance = Infinity) {
|
|
16213
|
-
const r = raycastInternal(origin, direction, maxDistance);
|
|
16483
|
+
const r = raycastInternal(origin, direction, maxDistance, void 0, false, true);
|
|
16214
16484
|
return r ? { object: r.object, part: r.part, point: r.point, normal: r.normal, distance: r.distance } : null;
|
|
16215
16485
|
},
|
|
16216
16486
|
sweepBox(box3, direction, distance2, options2 = {}) {
|
|
@@ -16228,21 +16498,23 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16228
16498
|
},
|
|
16229
16499
|
shoot(origin, direction, energy, caliber, source, round3) {
|
|
16230
16500
|
const extras = typeof round3 === "number" ? { piercing: round3 } : round3 ?? {};
|
|
16231
|
-
return withCollapses(run(() => {
|
|
16501
|
+
return withCollapses(run(withBlow("ballistic", () => {
|
|
16232
16502
|
const results = [];
|
|
16233
16503
|
const d = vec.normalize(direction);
|
|
16234
16504
|
const ignore = /* @__PURE__ */ new Set();
|
|
16235
16505
|
let org = origin;
|
|
16236
16506
|
let E = energy;
|
|
16237
16507
|
for (let i = 0; i < 4 && E > 0; i++) {
|
|
16238
|
-
const rh = raycastInternal(org, d, Infinity, ignore);
|
|
16508
|
+
const rh = raycastInternal(org, d, Infinity, ignore, false, true);
|
|
16239
16509
|
if (!rh) break;
|
|
16240
16510
|
const im = impls.get(rh.object);
|
|
16241
16511
|
if (im) {
|
|
16242
|
-
const
|
|
16512
|
+
const scaled = extras.penetration && E < energy ? { ...extras, penetration: Object.fromEntries(Object.entries(extras.penetration).map(([k, mm]) => [k, mm * (E / energy)])) } : extras;
|
|
16513
|
+
const r = implHit(im, { type: "ballistic", point: rh.point, part: rh.part, normal: rh.normal, direction: d, energy: E, caliber, ...scaled, ...source !== void 0 ? { source } : {} });
|
|
16243
16514
|
r.part = rh.part;
|
|
16244
16515
|
r.point = rh.point;
|
|
16245
|
-
|
|
16516
|
+
const left = r.events.find((e) => e.type === "hole" && e.energyLeft !== void 0);
|
|
16517
|
+
r.exitEnergy = r.penetrated ? left?.energyLeft ?? E * 0.5 : 0;
|
|
16246
16518
|
results.push(r);
|
|
16247
16519
|
ignore.add(`${im.impl.id}\0${rh.part}`);
|
|
16248
16520
|
if (!r.penetrated) break;
|
|
@@ -16261,7 +16533,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16261
16533
|
E = out.exitEnergy;
|
|
16262
16534
|
}
|
|
16263
16535
|
return results;
|
|
16264
|
-
}));
|
|
16536
|
+
})));
|
|
16265
16537
|
},
|
|
16266
16538
|
disassemble(objectId, jointId, tool, dt) {
|
|
16267
16539
|
const im = impls.get(objectId);
|
|
@@ -16561,12 +16833,27 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16561
16833
|
breach: { area: 0.1 }
|
|
16562
16834
|
}
|
|
16563
16835
|
];
|
|
16836
|
+
var SHIPPED = structuredClone(assemblies_default);
|
|
16564
16837
|
var ASSEMBLIES = assemblies_default;
|
|
16565
|
-
var
|
|
16838
|
+
var assembliesOver = (defs) => {
|
|
16839
|
+
const get = (id) => defs.find((a) => a.id === id);
|
|
16840
|
+
return {
|
|
16841
|
+
list: () => defs,
|
|
16842
|
+
get,
|
|
16843
|
+
register(def) {
|
|
16844
|
+
const at2 = defs.findIndex((a) => a.id === def.id);
|
|
16845
|
+
if (at2 >= 0) defs[at2] = def;
|
|
16846
|
+
else defs.push(def);
|
|
16847
|
+
},
|
|
16848
|
+
part: (assemblyId, options) => buildAssemblyPart(get(assemblyId), assemblyId, options)
|
|
16849
|
+
};
|
|
16850
|
+
};
|
|
16851
|
+
var defaultSet;
|
|
16852
|
+
var defaultAssemblies = () => defaultSet ?? (defaultSet = assembliesOver(ASSEMBLIES));
|
|
16853
|
+
var getAssembly = (id) => defaultAssemblies().get(id);
|
|
16566
16854
|
var faceCount = (layer) => layer.faces === "both" ? 2 : 1;
|
|
16567
16855
|
var assemblyDepth = (def) => def.depth ?? def.core.thickness + (def.layers ?? []).reduce((sum, l) => sum + l.thickness * faceCount(l), 0);
|
|
16568
|
-
var
|
|
16569
|
-
const def = getAssembly(assemblyId);
|
|
16856
|
+
var buildAssemblyPart = (def, assemblyId, options) => {
|
|
16570
16857
|
if (!def) throw new Error(`unknown assembly "${assemblyId}"`);
|
|
16571
16858
|
const densityOf2 = (id) => {
|
|
16572
16859
|
const m = options.materials?.get(id) ?? MATERIALS2.find((x) => x.id === id);
|
|
@@ -16593,6 +16880,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16593
16880
|
...options.extra
|
|
16594
16881
|
};
|
|
16595
16882
|
};
|
|
16883
|
+
var assemblyPart = (assemblyId, options) => defaultAssemblies().part(assemblyId, options);
|
|
16596
16884
|
var buildFrame = (o = {}) => {
|
|
16597
16885
|
const spanX = o.spanX ?? 8, spanZ = o.spanZ ?? 8;
|
|
16598
16886
|
const nx = Math.max(2, o.columnsX ?? 3), nz = Math.max(2, o.columnsZ ?? 3);
|
|
@@ -17625,9 +17913,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17625
17913
|
}
|
|
17626
17914
|
if (context.isTimber && construction.roof.shape !== "slab") addCeilingJoists(context);
|
|
17627
17915
|
}
|
|
17916
|
+
var isStair = (item) => item.category === "stairs" && typeof item.link === "object" && item.link !== null;
|
|
17628
17917
|
function flightsOf(items) {
|
|
17629
17918
|
const flights = /* @__PURE__ */ new Map();
|
|
17630
|
-
for (const item of items.filter(
|
|
17919
|
+
for (const item of items.filter(isStair)) {
|
|
17631
17920
|
const key = `${item.link.from}_${item.link.to}`;
|
|
17632
17921
|
if (!flights.has(key) || item.floor === item.link.from) flights.set(key, item);
|
|
17633
17922
|
}
|
|
@@ -19774,6 +20063,34 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19774
20063
|
}
|
|
19775
20064
|
function installDestructionBreach(K, _shared) {
|
|
19776
20065
|
const { THREE, fragmentMaterial, invalidate, invalidateShadow } = K;
|
|
20066
|
+
const paintState = { attached: false };
|
|
20067
|
+
const paintQueues = /* @__PURE__ */ new Set();
|
|
20068
|
+
const paintQueue = {
|
|
20069
|
+
id: DEFERRED_QUEUE_ID.BREACH_PAINT,
|
|
20070
|
+
pending: () => {
|
|
20071
|
+
let n = 0;
|
|
20072
|
+
for (const q of paintQueues) n += q.pending();
|
|
20073
|
+
return n;
|
|
20074
|
+
},
|
|
20075
|
+
run(deadline, clock) {
|
|
20076
|
+
let ran = 0;
|
|
20077
|
+
for (const q of [...paintQueues]) {
|
|
20078
|
+
if (q.pending() === 0) continue;
|
|
20079
|
+
if (ran > 0 && clock() >= deadline) break;
|
|
20080
|
+
ran += q.run(deadline, clock);
|
|
20081
|
+
}
|
|
20082
|
+
return ran;
|
|
20083
|
+
},
|
|
20084
|
+
flush() {
|
|
20085
|
+
for (const q of [...paintQueues]) q.flush();
|
|
20086
|
+
},
|
|
20087
|
+
attach() {
|
|
20088
|
+
paintState.attached = true;
|
|
20089
|
+
},
|
|
20090
|
+
detach() {
|
|
20091
|
+
paintState.attached = false;
|
|
20092
|
+
}
|
|
20093
|
+
};
|
|
19777
20094
|
function createBreachView(opts) {
|
|
19778
20095
|
const { house, structure } = opts;
|
|
19779
20096
|
const views = /* @__PURE__ */ new Map();
|
|
@@ -19979,17 +20296,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19979
20296
|
for (const { c, part, units: units2, thick, mid } of shown) {
|
|
19980
20297
|
if (!near(c)) continue;
|
|
19981
20298
|
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;
|
|
19982
|
-
const
|
|
20299
|
+
const at2 = (s, dy, d, colour) => {
|
|
19983
20300
|
const unit = clipToBox({ x: mask.alongU ? centre : mid, y, z: mask.alongU ? mid : centre, sx: mask.alongU ? s : d, sy: dy, sz: mask.alongU ? d : s, colour }, view.bounds);
|
|
19984
20301
|
if (unit) list2.push(unit);
|
|
19985
20302
|
};
|
|
19986
20303
|
const base = fragmentMaterial(part.material).color.getHex();
|
|
19987
20304
|
const n = noise2(centre * 3.1, y * 2.7, 0.07);
|
|
19988
20305
|
if (units2.mortar === "concrete") {
|
|
19989
|
-
|
|
20306
|
+
at2(len, h, thick - 2 * COVER2, tone(base, 0.9 + 0.04 * n));
|
|
19990
20307
|
} else {
|
|
19991
|
-
|
|
19992
|
-
|
|
20308
|
+
at2(len, h, thick - 2 * COVER2 - 0.012, 10327948);
|
|
20309
|
+
at2(len - 0.012, h - 0.012, thick - 2 * COVER2, tone(base, 0.8 + 0.35 * n));
|
|
19993
20310
|
}
|
|
19994
20311
|
}
|
|
19995
20312
|
if (view.units) {
|
|
@@ -20088,8 +20405,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20088
20405
|
else s.data = collapseRange(s.it.mesh, s.v0, s.it.v1);
|
|
20089
20406
|
}
|
|
20090
20407
|
}
|
|
20091
|
-
function flush(budgetMs
|
|
20408
|
+
function flush(budgetMs) {
|
|
20092
20409
|
if (dirty.size === 0) return 0;
|
|
20410
|
+
if (budgetMs === void 0 && paintState.attached) return dirty.size;
|
|
20411
|
+
budgetMs ?? (budgetMs = paintBudgetMs);
|
|
20093
20412
|
const deadline = performance.now() + budgetMs;
|
|
20094
20413
|
for (const view of dirty) {
|
|
20095
20414
|
dirty.delete(view);
|
|
@@ -20100,6 +20419,34 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20100
20419
|
invalidateShadow();
|
|
20101
20420
|
return dirty.size;
|
|
20102
20421
|
}
|
|
20422
|
+
const queue = {
|
|
20423
|
+
id: DEFERRED_QUEUE_ID.BREACH_PAINT,
|
|
20424
|
+
pending: () => dirty.size,
|
|
20425
|
+
run(deadline, clock) {
|
|
20426
|
+
let ran = 0;
|
|
20427
|
+
for (const view of dirty) {
|
|
20428
|
+
dirty.delete(view);
|
|
20429
|
+
paint(view);
|
|
20430
|
+
ran++;
|
|
20431
|
+
if (clock() >= deadline) break;
|
|
20432
|
+
}
|
|
20433
|
+
if (ran > 0) {
|
|
20434
|
+
invalidate();
|
|
20435
|
+
invalidateShadow();
|
|
20436
|
+
}
|
|
20437
|
+
return ran;
|
|
20438
|
+
},
|
|
20439
|
+
flush() {
|
|
20440
|
+
flush(Infinity);
|
|
20441
|
+
},
|
|
20442
|
+
attach() {
|
|
20443
|
+
paintState.attached = true;
|
|
20444
|
+
},
|
|
20445
|
+
detach() {
|
|
20446
|
+
paintState.attached = false;
|
|
20447
|
+
}
|
|
20448
|
+
};
|
|
20449
|
+
paintQueues.add(queue);
|
|
20103
20450
|
function dispose(view) {
|
|
20104
20451
|
dirty.delete(view);
|
|
20105
20452
|
if (view.units) {
|
|
@@ -20134,6 +20481,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20134
20481
|
*/
|
|
20135
20482
|
claim() {
|
|
20136
20483
|
var _a;
|
|
20484
|
+
paintQueues.add(queue);
|
|
20137
20485
|
for (const q of opts.spec()?.parts ?? []) {
|
|
20138
20486
|
if (!q.units) continue;
|
|
20139
20487
|
const host = hostOf(q.id);
|
|
@@ -20186,6 +20534,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20186
20534
|
dropped.length = 0;
|
|
20187
20535
|
},
|
|
20188
20536
|
flush,
|
|
20537
|
+
/** Takes this house's painting out of the renderer's queue (the house goes away); `claim` puts it back. */
|
|
20538
|
+
release() {
|
|
20539
|
+
paintQueues.delete(queue);
|
|
20540
|
+
},
|
|
20541
|
+
/** The painting of this house alone. */
|
|
20542
|
+
deferredQueue: () => queue,
|
|
20189
20543
|
/** The wall has damage drawn. */
|
|
20190
20544
|
has(partId) {
|
|
20191
20545
|
return views.has(partId);
|
|
@@ -20200,7 +20554,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20200
20554
|
})
|
|
20201
20555
|
};
|
|
20202
20556
|
}
|
|
20203
|
-
Object.assign(K, { createBreachView });
|
|
20557
|
+
Object.assign(K, { createBreachView, breachPaintQueue: paintQueue });
|
|
20204
20558
|
}
|
|
20205
20559
|
|
|
20206
20560
|
// src/destruction/world.ts
|
|
@@ -20268,11 +20622,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20268
20622
|
};
|
|
20269
20623
|
const extract = (it) => {
|
|
20270
20624
|
const g0 = it.mesh.geometry, src = it.mesh.userData._p0 || g0.attributes.position.array, g = new THREE.BufferGeometry();
|
|
20271
|
-
const
|
|
20272
|
-
|
|
20273
|
-
|
|
20274
|
-
|
|
20275
|
-
|
|
20625
|
+
const at2 = (name, k, arr) => g.setAttribute(name, new THREE.BufferAttribute((arr || g0.attributes[name].array).slice(it.v0 * k, it.v1 * k), k));
|
|
20626
|
+
at2("position", 3, src);
|
|
20627
|
+
at2("normal", 3);
|
|
20628
|
+
at2("color", 3);
|
|
20629
|
+
at2("uv", 2);
|
|
20276
20630
|
const ix = g0.index.array.slice(it.i0, it.i1);
|
|
20277
20631
|
for (let k = 0; k < ix.length; k++) ix[k] -= it.v0;
|
|
20278
20632
|
g.setIndex(new THREE.BufferAttribute(ix, 1));
|
|
@@ -20455,6 +20809,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20455
20809
|
if (R && D.id && D.active) R.unbind(D.id);
|
|
20456
20810
|
if (D.active && D.world.has(D.id)) D.world.remove(D.id);
|
|
20457
20811
|
D.active = false;
|
|
20812
|
+
breach.release();
|
|
20458
20813
|
};
|
|
20459
20814
|
D.follow = (world, id, spec) => {
|
|
20460
20815
|
D.spec = spec;
|
|
@@ -20489,6 +20844,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20489
20844
|
return { restore: () => breach.restore(), dispose: () => {
|
|
20490
20845
|
offFollow();
|
|
20491
20846
|
breach.restore();
|
|
20847
|
+
breach.release();
|
|
20492
20848
|
}, update: () => {
|
|
20493
20849
|
breach.flush();
|
|
20494
20850
|
} };
|
|
@@ -20985,9 +21341,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20985
21341
|
shared.vegMaterials.setActors(focus ? [{ x: focus.x, y: focus.y, z: focus.z, radius: 0.9 }] : []);
|
|
20986
21342
|
}
|
|
20987
21343
|
if (focus && cfg.lod !== false) {
|
|
20988
|
-
const L = Object.assign({ interior: 45, hide: 220 }, cfg.lod), d = distance2(focus),
|
|
21344
|
+
const L = Object.assign({ interior: 45, hide: 220 }, cfg.lod), d = distance2(focus), at2 = h.lodCurrent;
|
|
20989
21345
|
let n = d > L.hide ? 2 : d > L.interior ? 1 : 0;
|
|
20990
|
-
if (n <
|
|
21346
|
+
if (n < at2) n = d < (at2 === 2 ? L.hide : L.interior) * 0.92 ? n : at2;
|
|
20991
21347
|
applyLod(Math.max(n, h.lodMin));
|
|
20992
21348
|
}
|
|
20993
21349
|
},
|
|
@@ -21101,7 +21457,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21101
21457
|
|
|
21102
21458
|
// src/build/api.ts
|
|
21103
21459
|
function buildApi(K, shared) {
|
|
21104
|
-
const { cfg, VERSION: VERSION2, ATLAS, TEX, applyPart, carGroup, carModel, props, TYPES, roomLightMask, lighting, newState, build } = K;
|
|
21460
|
+
const { cfg, VERSION: VERSION2, ATLAS, TEX, applyPart, carGroup, carModel, props, TYPES, roomLightMask, lighting, effectLights, newState, build } = K;
|
|
21105
21461
|
return {
|
|
21106
21462
|
version: VERSION2,
|
|
21107
21463
|
build,
|
|
@@ -21116,10 +21472,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21116
21472
|
},
|
|
21117
21473
|
roomLightMask,
|
|
21118
21474
|
lighting,
|
|
21475
|
+
effectLights,
|
|
21119
21476
|
setNight(n) {
|
|
21120
21477
|
shared.mats.glass.emissive.set(n ? 9067040 : 0);
|
|
21121
21478
|
shared.mats.glass.opacity = n ? 0.4 : 0.24;
|
|
21122
21479
|
},
|
|
21480
|
+
/** The chipped-plaster painting of every house of this renderer as a `DeferredQueue` for a frame budget (id `floorplan.breach-paint`); asking for it changes nothing. */
|
|
21481
|
+
deferredQueue: () => K.breachPaintQueue,
|
|
21123
21482
|
cars: { model: carModel, group: carGroup, info: (k, seed) => {
|
|
21124
21483
|
const m = carModel(k, seed);
|
|
21125
21484
|
return m && { parts: m.parts.length, tris: m.tris, L: m.L, W: m.W, H: m.H };
|
|
@@ -21586,6 +21945,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21586
21945
|
return { off, reset: () => navigator.undoChanges(houseId) };
|
|
21587
21946
|
}
|
|
21588
21947
|
|
|
21948
|
+
// ../game-render-three/dist/index.js
|
|
21949
|
+
var DEFAULT_ANGLE = Math.PI / 3;
|
|
21950
|
+
function isLightBudget(value) {
|
|
21951
|
+
const candidate = value;
|
|
21952
|
+
return typeof candidate === "object" && candidate !== null && typeof candidate.acquire === "function" && typeof candidate.addSource === "function" && typeof candidate.lease === "function" && typeof candidate.present === "function";
|
|
21953
|
+
}
|
|
21954
|
+
var EFFECT_STEP_SECONDS = 1 / 50;
|
|
21955
|
+
|
|
21589
21956
|
// src/test-area/text.ts
|
|
21590
21957
|
var TEXT = {
|
|
21591
21958
|
en: {
|
|
@@ -21608,7 +21975,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21608
21975
|
hit: { burst_9mm: "9 mm burst", burst_762: "7.62 burst", sledge: "Sledgehammer", c4: "C4", rpg: "RPG warhead" },
|
|
21609
21976
|
state: { normal: "Normal", fortified: "Fortified", abandoned: "Abandoned" }
|
|
21610
21977
|
},
|
|
21611
|
-
layers: { roof: "Roof", lot: "Lot (ground, wall, gate)", night: "Night (lit windows and lamps)" },
|
|
21978
|
+
layers: { roof: "Roof", lot: "Lot (ground, wall, gate)", night: "Night (lit windows and lamps)", room_lights: "Room lights (one lamp per lit room, stopped by the walls)" },
|
|
21612
21979
|
metrics: { houses: "Houses", parts: "Parts", standing: "Standing", broken: "Broken", holes: "Holes", draw_calls: "Draw calls", triangles: "Triangles", lod: "Level of detail (nearest)", floor: "Your floor", doors_open: "Doors open", target: "You aim at", planned: "Planned draw calls" },
|
|
21613
21980
|
sheet: { kicker: "House", title: "House of the bench", template: "Typology", seed: "Seed", state: "State", floors: "Floors", size: "Size", parts: "Structure parts", look: "You aim at", none: "nothing to use", no_engine: "The page gave no floorplan engine" },
|
|
21614
21981
|
specimens: {
|
|
@@ -21674,7 +22041,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21674
22041
|
hit: { burst_9mm: "Rajada de 9 mm", burst_762: "Rajada de 7,62", sledge: "Marreta", c4: "C4", rpg: "Ogiva de RPG" },
|
|
21675
22042
|
state: { normal: "Normal", fortified: "Fortificada", abandoned: "Abandonada" }
|
|
21676
22043
|
},
|
|
21677
|
-
layers: { roof: "Telhado", lot: "Lote (ch\xE3o, muro, port\xE3o)", night: "Noite (janelas e l\xE2mpadas acesas)" },
|
|
22044
|
+
layers: { roof: "Telhado", lot: "Lote (ch\xE3o, muro, port\xE3o)", night: "Noite (janelas e l\xE2mpadas acesas)", room_lights: "Luz por c\xF4modo (uma l\xE2mpada por c\xF4modo aceso, barrada pelas paredes)" },
|
|
21678
22045
|
metrics: { houses: "Casas", parts: "Pe\xE7as", standing: "De p\xE9", broken: "Quebradas", holes: "Furos", draw_calls: "Draw calls", triangles: "Tri\xE2ngulos", lod: "N\xEDvel de detalhe (a mais perto)", floor: "Seu andar", doors_open: "Portas abertas", target: "Voc\xEA mira em", planned: "Draw calls planejados" },
|
|
21679
22046
|
sheet: { kicker: "Casa", title: "Casa da bancada", template: "Tipologia", seed: "Semente", state: "Estado", floors: "Andares", size: "Tamanho", parts: "Pe\xE7as da estrutura", look: "Voc\xEA mira em", none: "nada para usar", no_engine: "A p\xE1gina n\xE3o deu o motor de plantas" },
|
|
21680
22047
|
specimens: {
|
|
@@ -21727,14 +22094,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21727
22094
|
|
|
21728
22095
|
// src/test-area/scenarios.ts
|
|
21729
22096
|
var SPECIMEN_AT = [-5, 0, -11];
|
|
21730
|
-
function createHouseScenarios(text,
|
|
22097
|
+
function createHouseScenarios(text, at2 = SPECIMEN_AT) {
|
|
21731
22098
|
const T2 = text.steps;
|
|
21732
22099
|
const spawn = (room, item) => {
|
|
21733
|
-
const so = room.spawn(item, [
|
|
22100
|
+
const so = room.spawn(item, [at2[0], at2[1], at2[2]], 0);
|
|
21734
22101
|
const parts = so.root.userData.floorplanSpec.parts;
|
|
21735
22102
|
const centre = (id) => {
|
|
21736
22103
|
const p = parts.find((x) => x.id === id);
|
|
21737
|
-
return [p.position[0] +
|
|
22104
|
+
return [p.position[0] + at2[0], p.position[1] + at2[1], p.position[2] + at2[2]];
|
|
21738
22105
|
};
|
|
21739
22106
|
return { oid: so.objectId, parts, centre };
|
|
21740
22107
|
};
|
|
@@ -21971,6 +22338,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21971
22338
|
let THREE = null;
|
|
21972
22339
|
let houseRenderer = null;
|
|
21973
22340
|
let houseRendererKey = "";
|
|
22341
|
+
let stopPaintQueue;
|
|
22342
|
+
let roomLights = null;
|
|
21974
22343
|
const placed = [];
|
|
21975
22344
|
let time = 0;
|
|
21976
22345
|
let dirty = false;
|
|
@@ -21998,20 +22367,29 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21998
22367
|
const rendererFor = () => {
|
|
21999
22368
|
const key = `${settings.quality}|${locale}`;
|
|
22000
22369
|
if (!houseRenderer || houseRendererKey !== key) {
|
|
22370
|
+
stopPaintQueue?.();
|
|
22371
|
+
dropRoomLights();
|
|
22001
22372
|
houseRenderer?.dispose?.();
|
|
22002
22373
|
houseRenderer = create3(THREE, {
|
|
22003
22374
|
locale,
|
|
22004
22375
|
lod: { interior: 10, hide: 40 },
|
|
22005
22376
|
breachPaintBudgetMs: 4,
|
|
22006
22377
|
...options.house,
|
|
22378
|
+
...options.house?.interactives ? { interactives: { effectSink: () => host?.effects, ...options.house.interactives } } : {},
|
|
22007
22379
|
quality: settings.quality,
|
|
22008
22380
|
...options.world ? { destruction: options.world } : {},
|
|
22009
22381
|
...options.renderer ? { destructionRenderer: options.renderer } : {}
|
|
22010
22382
|
});
|
|
22011
22383
|
houseRendererKey = key;
|
|
22384
|
+
const paintQueue = houseRenderer.deferredQueue?.();
|
|
22385
|
+
stopPaintQueue = paintQueue ? host?.defer?.(paintQueue, DEFERRED_PRIORITY[DEFERRED_QUEUE_ID.BREACH_PAINT]) : void 0;
|
|
22012
22386
|
}
|
|
22013
22387
|
return houseRenderer;
|
|
22014
22388
|
};
|
|
22389
|
+
const dropRoomLights = () => {
|
|
22390
|
+
roomLights?.dispose();
|
|
22391
|
+
roomLights = null;
|
|
22392
|
+
};
|
|
22015
22393
|
const clearHouses = () => {
|
|
22016
22394
|
for (const p of placed) p.house.dispose();
|
|
22017
22395
|
placed.length = 0;
|
|
@@ -22098,9 +22476,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22098
22476
|
};
|
|
22099
22477
|
const eyeOf = (p) => {
|
|
22100
22478
|
const camera = host?.camera;
|
|
22101
|
-
const
|
|
22479
|
+
const at2 = toLocal2(p, camera.position.x, camera.position.y, camera.position.z);
|
|
22102
22480
|
const forward = new THREE.Vector3(0, 0, -1).applyQuaternion(camera.quaternion).transformDirection(new THREE.Matrix4().copy(p.house.group.matrixWorld).invert());
|
|
22103
|
-
return { x:
|
|
22481
|
+
return { x: at2.x, y: at2.y, z: at2.z, floor: floorOf(p, camera.position.y), yaw: Math.atan2(forward.x, forward.z), pitch: Math.asin(Math.max(-1, Math.min(1, forward.y))) };
|
|
22104
22482
|
};
|
|
22105
22483
|
const blocked = (x, z, radius) => {
|
|
22106
22484
|
for (const p of placed) {
|
|
@@ -22168,7 +22546,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22168
22546
|
const doorReach = (p, fo) => {
|
|
22169
22547
|
const g = fo.gs[0];
|
|
22170
22548
|
const pivot = fo.handles[0].pivot;
|
|
22171
|
-
const
|
|
22549
|
+
const at2 = (angle) => {
|
|
22172
22550
|
const c = Math.cos(angle);
|
|
22173
22551
|
const s = Math.sin(angle);
|
|
22174
22552
|
const v = new THREE.Vector3(pivot[0] * c + pivot[2] * s, pivot[1], -pivot[0] * s + pivot[2] * c).add(g.position);
|
|
@@ -22177,8 +22555,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22177
22555
|
const camera = host?.camera;
|
|
22178
22556
|
const eye = new THREE.Vector3(camera.position.x, 0, camera.position.z);
|
|
22179
22557
|
const flat = (v) => Math.hypot(v.x - eye.x, v.z - eye.z);
|
|
22180
|
-
const closed =
|
|
22181
|
-
const open =
|
|
22558
|
+
const closed = at2(0);
|
|
22559
|
+
const open = at2(fo.rot);
|
|
22182
22560
|
const opening = !fo.open;
|
|
22183
22561
|
return {
|
|
22184
22562
|
handle: () => {
|
|
@@ -22249,6 +22627,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22249
22627
|
}
|
|
22250
22628
|
if (change.kind === "layer") {
|
|
22251
22629
|
if (change.id === "roof") showAll();
|
|
22630
|
+
else if (change.id === "room_lights") dropRoomLights();
|
|
22252
22631
|
else if (placed.length > 0) {
|
|
22253
22632
|
dirty = true;
|
|
22254
22633
|
dirtyAt = time;
|
|
@@ -22415,7 +22794,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22415
22794
|
layers: () => [
|
|
22416
22795
|
{ id: "roof", name: text.layers.roof, default: true },
|
|
22417
22796
|
{ id: "lot", name: text.layers.lot, default: false },
|
|
22418
|
-
{ id: "night", name: text.layers.night, default: false }
|
|
22797
|
+
{ id: "night", name: text.layers.night, default: false },
|
|
22798
|
+
{ id: "room_lights", name: text.layers.room_lights, default: false }
|
|
22419
22799
|
],
|
|
22420
22800
|
metrics: () => [
|
|
22421
22801
|
{ id: "houses_built", name: text.metrics.houses, read: () => placed.length },
|
|
@@ -22461,6 +22841,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22461
22841
|
updateSheet();
|
|
22462
22842
|
}
|
|
22463
22843
|
});
|
|
22844
|
+
const stopEffectLights = lent.onFrame(
|
|
22845
|
+
() => {
|
|
22846
|
+
const budget = lent.lights;
|
|
22847
|
+
if (!isLightBudget(budget) || placed.length === 0 || !houseRenderer) return;
|
|
22848
|
+
const houses2 = placed.map((p) => p.house);
|
|
22849
|
+
if (lent.bench?.layer("room_lights") ?? false) {
|
|
22850
|
+
roomLights ?? (roomLights = houseRenderer.lighting({ scene: lent.scene, n: 3, shadows: 0, budget }));
|
|
22851
|
+
roomLights.update(houses2, cameraWorld(), {});
|
|
22852
|
+
return;
|
|
22853
|
+
}
|
|
22854
|
+
dropRoomLights();
|
|
22855
|
+
houseRenderer.effectLights?.({ budget })?.update(houses2);
|
|
22856
|
+
},
|
|
22857
|
+
{ phase: "present", order: 20 }
|
|
22858
|
+
);
|
|
22464
22859
|
const onKey = (event) => {
|
|
22465
22860
|
if (event.code === "KeyE" && !event.repeat && placed.length > 0) useNearest();
|
|
22466
22861
|
};
|
|
@@ -22468,9 +22863,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22468
22863
|
return () => {
|
|
22469
22864
|
stopChange?.();
|
|
22470
22865
|
stopFrame();
|
|
22866
|
+
stopEffectLights();
|
|
22867
|
+
dropRoomLights();
|
|
22471
22868
|
globalThis.removeEventListener?.("keydown", onKey);
|
|
22472
22869
|
for (const remove of removers.splice(0)) remove();
|
|
22473
22870
|
clearHouses();
|
|
22871
|
+
stopPaintQueue?.();
|
|
22872
|
+
stopPaintQueue = void 0;
|
|
22474
22873
|
houseRenderer?.dispose?.();
|
|
22475
22874
|
houseRenderer = null;
|
|
22476
22875
|
host = null;
|
|
@@ -22865,8 +23264,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22865
23264
|
facadeExtra: (f, rng2, w, d, op) => {
|
|
22866
23265
|
f.roof = "slab";
|
|
22867
23266
|
f.finish = rng2() < 0.55 ? "exposed_block" : "partial_plaster";
|
|
22868
|
-
|
|
22869
|
-
|
|
23267
|
+
const slab = { exposedRebar: true, waterTank: { u: r22(0.5 + rng2() * (w - 1.5)), v: r22(1 + rng2() * (d - 2)) }, annex: rng2() < 0.55 ? { rect: [0, 0, r22(w * (0.5 + rng2() * 0.3)), r22(d * 0.4)], state: "exposed_brick" } : null };
|
|
23268
|
+
f.slab = slab;
|
|
23269
|
+
if (floorsOf(op) > 1) slab.exposedRebar = rng2() < 0.6;
|
|
22870
23270
|
}
|
|
22871
23271
|
};
|
|
22872
23272
|
}
|
|
@@ -23578,13 +23978,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23578
23978
|
function apartment(strip, floor, k, from, to, plate, ceiling, win) {
|
|
23579
23979
|
const wide = to - from, depth = strip.depth, facade = r22(depth * 0.56);
|
|
23580
23980
|
const id = (name) => `apt_${floor}_${strip.id}_${k}_${name}`;
|
|
23581
|
-
const
|
|
23981
|
+
const at2 = (f0, f1, b0, b1) => boxOf2(strip, r22(from + wide * f0), r22(from + wide * f1), b0, b1);
|
|
23582
23982
|
const rooms = [
|
|
23583
|
-
{ id: id("living"), type: "living", label: "living", library: "living_tower", rect:
|
|
23584
|
-
{ id: id("bedroom"), type: "bedroom", label: "bedroom", rect:
|
|
23585
|
-
{ id: id("kitchen"), type: "kitchen", label: "kitchen", library: "kitchen_integrated", rect:
|
|
23586
|
-
{ id: id("hall"), type: "hall", label: "hall", rect:
|
|
23587
|
-
{ id: id("bath"), type: "bathroom", label: "bathroom", library: "bathroom_wc", rect:
|
|
23983
|
+
{ id: id("living"), type: "living", label: "living", library: "living_tower", rect: at2(0, 0.58, 0, facade) },
|
|
23984
|
+
{ id: id("bedroom"), type: "bedroom", label: "bedroom", rect: at2(0.58, 1, 0, facade) },
|
|
23985
|
+
{ id: id("kitchen"), type: "kitchen", label: "kitchen", library: "kitchen_integrated", rect: at2(0, 0.4, facade, depth) },
|
|
23986
|
+
{ id: id("hall"), type: "hall", label: "hall", rect: at2(0.4, 0.78, facade, depth) },
|
|
23987
|
+
{ id: id("bath"), type: "bathroom", label: "bathroom", library: "bathroom_wc", rect: at2(0.78, 1, facade, depth) }
|
|
23588
23988
|
];
|
|
23589
23989
|
const doors = [
|
|
23590
23990
|
stripDoor(id("hall"), strip, floor, 0.95),
|
|
@@ -23617,8 +24017,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23617
24017
|
if (strip.id !== "south") return apartments(plan)(strip, context);
|
|
23618
24018
|
const { floor, plate, ceiling } = context;
|
|
23619
24019
|
const lobby = `lobby_${floor}_entrance`, concierge = `concierge_${floor}`, bikes = `bike_room_${floor}`;
|
|
23620
|
-
const
|
|
23621
|
-
const [left, middle, right] = [
|
|
24020
|
+
const at2 = (f0, f1) => boxOf2(strip, r22(strip.length * f0), r22(strip.length * f1), 0, strip.depth);
|
|
24021
|
+
const [left, middle, right] = [at2(0, 0.3), at2(0.3, 0.7), at2(0.7, 1)];
|
|
23622
24022
|
const rooms = [
|
|
23623
24023
|
{ id: concierge, type: "office", label: "concierge", rect: left },
|
|
23624
24024
|
{ id: lobby, type: "hall", label: "lobby_entrance", rect: middle },
|