@adatechnology/game-test-room 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.global.js +11773 -1693
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +153 -13
- package/dist/index.js.map +1 -1
- package/package.json +9 -7
package/dist/index.js
CHANGED
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
import { createDestruction, JOINT_DEFAULTS as JOINT_DEFAULTS2, resolveStrings as resolveDestructionStrings } from "@adatechnology/game-destruction";
|
|
3
3
|
import { createDestructionRenderer, specFromObject3D } from "@adatechnology/game-destruction-three";
|
|
4
4
|
import { createArsenal, DEFAULT_LOADOUT } from "@adatechnology/game-weapons";
|
|
5
|
-
import { createFluids, createItemUse, ITEM_USES, resolveStrings as resolveFluidStrings } from "@adatechnology/game-fluids";
|
|
6
|
-
import { createFluidRenderer } from "@adatechnology/game-fluids-three";
|
|
5
|
+
import { createFilmLcg, createFluids, createItemUse, ITEM_USES, resolveStrings as resolveFluidStrings } from "@adatechnology/game-fluids";
|
|
6
|
+
import { createFilmBridge, createFilmManager, createFluidRenderer } from "@adatechnology/game-fluids-three";
|
|
7
|
+
import { createGroundField, createVfx } from "@adatechnology/game-vfx";
|
|
8
|
+
import { createGroundPatch, createVfxRenderer } from "@adatechnology/game-vfx-three";
|
|
7
9
|
import { checkAnimation, checkBench, checkDestructible, checkSpec } from "@adatechnology/game-contracts";
|
|
8
10
|
|
|
9
11
|
// src/items.ts
|
|
@@ -1255,6 +1257,7 @@ function createBenchStore(module, locale, onListenerError) {
|
|
|
1255
1257
|
const changed = () => {
|
|
1256
1258
|
for (const watcher of watchers) watcher();
|
|
1257
1259
|
};
|
|
1260
|
+
let sheet = null;
|
|
1258
1261
|
const controlOf = (id) => controls.find((control) => control.id === id);
|
|
1259
1262
|
const store = {
|
|
1260
1263
|
moduleId: module.id,
|
|
@@ -1296,6 +1299,11 @@ function createBenchStore(module, locale, onListenerError) {
|
|
|
1296
1299
|
watchers.add(listener);
|
|
1297
1300
|
return () => watchers.delete(listener);
|
|
1298
1301
|
},
|
|
1302
|
+
sheet: () => sheet,
|
|
1303
|
+
setSheet(next) {
|
|
1304
|
+
sheet = next;
|
|
1305
|
+
changed();
|
|
1306
|
+
},
|
|
1299
1307
|
patch(id, patch) {
|
|
1300
1308
|
const index = controls.findIndex((control2) => control2.id === id);
|
|
1301
1309
|
if (index < 0) return;
|
|
@@ -1517,7 +1525,10 @@ function createExplosives(context) {
|
|
|
1517
1525
|
const weaponName = context.toolName(projectile.weapon);
|
|
1518
1526
|
const reach = Math.max(detonation.injuryRadius, detonation.lethalRadius);
|
|
1519
1527
|
const reached = detonation.energy <= 0 ? 0 : detonation.cone ? coneBlast(detonation) : world.explode(detonation.point, detonation.energy, reach, "player").length;
|
|
1520
|
-
if (detonation.energy > 0)
|
|
1528
|
+
if (detonation.energy > 0) {
|
|
1529
|
+
const isPlayed = context.effects.explosion(detonation.explosive, detonation.point, { direction: detonation.direction }) !== null;
|
|
1530
|
+
renderer.explode(detonation.point, detonation.energy, reach, { visual: !isPlayed });
|
|
1531
|
+
}
|
|
1521
1532
|
if (detonation.stunSeconds !== void 0) renderer.emit("flash", detonation.point, [0, 1, 0], 1, 1);
|
|
1522
1533
|
const onPlayer = blastEffect(detonation, toArray(camera.position));
|
|
1523
1534
|
action("explode", translate("act.explode", { weapon: weaponName, energy: format(detonation.energy, 0), radius: format(reach, 1), n: reached }), {
|
|
@@ -1526,7 +1537,7 @@ function createExplosives(context) {
|
|
|
1526
1537
|
if (onPlayer.zone !== "none") {
|
|
1527
1538
|
action("blast_player", translate("act.blast_player", { weapon: weaponName, zone: translate(`blast.zone.${onPlayer.zone}`), distance: format(onPlayer.distance, 1), stun: format(onPlayer.stunSeconds, 1) }), { data: { ...onPlayer } });
|
|
1528
1539
|
}
|
|
1529
|
-
context.emitHost({ type: "explosion", source: projectile.weapon, point: detonation.point, energy: detonation.energy, radius: reach, cause: detonation.cause });
|
|
1540
|
+
context.emitHost({ type: "explosion", source: projectile.weapon, point: detonation.point, energy: detonation.energy, radius: reach, cause: detonation.cause, explosive: detonation.explosive });
|
|
1530
1541
|
if (detonation.fire) context.startFire(projectile.weapon, detonation.point, detonation.fire, detonation.cause === "impact");
|
|
1531
1542
|
};
|
|
1532
1543
|
const detonateBare = (projectile, isImpact) => {
|
|
@@ -1853,9 +1864,10 @@ function createRoomMetrics(sources) {
|
|
|
1853
1864
|
if (!["objects", "fragments", "particles", "decals"].some((id) => wanted.has(id))) return out;
|
|
1854
1865
|
const destruction = sources.destruction.stats();
|
|
1855
1866
|
const fluids = sources.fluids.stats();
|
|
1867
|
+
const effects = sources.effects.stats();
|
|
1856
1868
|
put("objects", destruction.pieces);
|
|
1857
1869
|
put("fragments", destruction.fragments);
|
|
1858
|
-
put("particles", destruction.particles + fluids.particles);
|
|
1870
|
+
put("particles", destruction.particles + fluids.particles + effects.puffs + effects.sparks + effects.glows + effects.chunks);
|
|
1859
1871
|
put("decals", destruction.decals + fluids.stains);
|
|
1860
1872
|
return out;
|
|
1861
1873
|
}
|
|
@@ -2955,7 +2967,7 @@ var mk = (tag, cls, text) => {
|
|
|
2955
2967
|
if (text !== void 0) e.textContent = text;
|
|
2956
2968
|
return e;
|
|
2957
2969
|
};
|
|
2958
|
-
var shapeOf = (view) => JSON.stringify([view.title, view.controls.map((c) => ({ ...c, value: void 0 })), view.layers.map((l) => [l.id, l.name])]);
|
|
2970
|
+
var shapeOf = (view) => JSON.stringify([view.title, view.controls.map((c) => ({ ...c, value: void 0 })), view.layers.map((l) => [l.id, l.name]), view.sheet ?? null]);
|
|
2959
2971
|
function createBenchPanel(o) {
|
|
2960
2972
|
const { t } = o;
|
|
2961
2973
|
const element = mk("div", "tr-panel tr-bench");
|
|
@@ -3010,7 +3022,8 @@ function createBenchPanel(o) {
|
|
|
3010
3022
|
const choiceControl = (control) => {
|
|
3011
3023
|
const wrap = mk("div", "tr-ctl");
|
|
3012
3024
|
wrap.appendChild(mk("span", void 0, control.name));
|
|
3013
|
-
|
|
3025
|
+
const grouped = control.options.some((option) => option.group !== void 0);
|
|
3026
|
+
if (control.options.length <= SEGMENTED_MAX && !grouped) {
|
|
3014
3027
|
const group = mk("div", "tr-seg");
|
|
3015
3028
|
group.setAttribute("role", "group");
|
|
3016
3029
|
const buttons = control.options.map((option) => {
|
|
@@ -3033,10 +3046,22 @@ function createBenchPanel(o) {
|
|
|
3033
3046
|
}
|
|
3034
3047
|
const select = mk("select");
|
|
3035
3048
|
select.disabled = control.disabled;
|
|
3049
|
+
let heading;
|
|
3050
|
+
let section = select;
|
|
3036
3051
|
for (const option of control.options) {
|
|
3052
|
+
if (option.group !== heading) {
|
|
3053
|
+
heading = option.group;
|
|
3054
|
+
section = select;
|
|
3055
|
+
if (heading !== void 0) {
|
|
3056
|
+
const optgroup = mk("optgroup");
|
|
3057
|
+
optgroup.label = heading;
|
|
3058
|
+
select.appendChild(optgroup);
|
|
3059
|
+
section = optgroup;
|
|
3060
|
+
}
|
|
3061
|
+
}
|
|
3037
3062
|
const op = mk("option", void 0, option.name);
|
|
3038
3063
|
op.value = option.id;
|
|
3039
|
-
|
|
3064
|
+
section.appendChild(op);
|
|
3040
3065
|
}
|
|
3041
3066
|
select.onchange = () => o.onControl(control.id, select.value);
|
|
3042
3067
|
wrap.appendChild(select);
|
|
@@ -3074,7 +3099,63 @@ function createBenchPanel(o) {
|
|
|
3074
3099
|
}
|
|
3075
3100
|
return wrap;
|
|
3076
3101
|
};
|
|
3102
|
+
let playhead = null;
|
|
3103
|
+
const sheetCard = (sheet) => {
|
|
3104
|
+
const card = mk("div", "tr-sheet");
|
|
3105
|
+
if (sheet.kicker) card.appendChild(mk("div", "sub", sheet.kicker));
|
|
3106
|
+
card.appendChild(mk("h4", void 0, sheet.title));
|
|
3107
|
+
if (sheet.body) card.appendChild(mk("p", void 0, sheet.body));
|
|
3108
|
+
if (sheet.facts?.length) {
|
|
3109
|
+
const facts = mk("dl", "tr-facts");
|
|
3110
|
+
for (const fact of sheet.facts) facts.append(mk("dt", void 0, fact.label), mk("dd", void 0, fact.value));
|
|
3111
|
+
card.appendChild(facts);
|
|
3112
|
+
}
|
|
3113
|
+
if (sheet.steps?.length) {
|
|
3114
|
+
const steps = mk("ol", "tr-steps");
|
|
3115
|
+
for (const step of sheet.steps) {
|
|
3116
|
+
const li = mk("li");
|
|
3117
|
+
li.append(mk("b", void 0, step.at), document.createTextNode(` ${step.text}`));
|
|
3118
|
+
steps.appendChild(li);
|
|
3119
|
+
}
|
|
3120
|
+
card.appendChild(steps);
|
|
3121
|
+
}
|
|
3122
|
+
if (sheet.swatches?.length) {
|
|
3123
|
+
const row = mk("div", "tr-swatches");
|
|
3124
|
+
for (const swatch of sheet.swatches) {
|
|
3125
|
+
const chip = mk("span", "tr-swatch");
|
|
3126
|
+
const dot = mk("i");
|
|
3127
|
+
dot.style.background = swatch.color;
|
|
3128
|
+
chip.append(dot, document.createTextNode(swatch.name));
|
|
3129
|
+
row.appendChild(chip);
|
|
3130
|
+
}
|
|
3131
|
+
card.appendChild(row);
|
|
3132
|
+
}
|
|
3133
|
+
if (sheet.timeline) {
|
|
3134
|
+
const { segments, ticks, metric } = sheet.timeline;
|
|
3135
|
+
const end = Math.max(1e-3, ...segments.map((segment) => segment.end), ...ticks);
|
|
3136
|
+
const strip = mk("div", "tr-timeline");
|
|
3137
|
+
for (const segment of segments) {
|
|
3138
|
+
const bar = mk("div", "tr-segment", segment.name);
|
|
3139
|
+
bar.style.left = `${segment.start / end * 100}%`;
|
|
3140
|
+
bar.style.width = `${(segment.end - segment.start) / end * 100}%`;
|
|
3141
|
+
bar.style.background = segment.color;
|
|
3142
|
+
strip.appendChild(bar);
|
|
3143
|
+
}
|
|
3144
|
+
for (const tick of ticks) {
|
|
3145
|
+
const mark = mk("u", "tr-tick");
|
|
3146
|
+
mark.style.left = `${tick / end * 100}%`;
|
|
3147
|
+
strip.appendChild(mark);
|
|
3148
|
+
}
|
|
3149
|
+
const head = mk("s", "tr-playhead");
|
|
3150
|
+
strip.appendChild(head);
|
|
3151
|
+
playhead = { node: head, metric, end };
|
|
3152
|
+
card.appendChild(strip);
|
|
3153
|
+
}
|
|
3154
|
+
if (sheet.note) card.appendChild(mk("p", "sub", sheet.note));
|
|
3155
|
+
return card;
|
|
3156
|
+
};
|
|
3077
3157
|
const rebuild = (view) => {
|
|
3158
|
+
playhead = null;
|
|
3078
3159
|
body.textContent = "";
|
|
3079
3160
|
refreshers.length = 0;
|
|
3080
3161
|
body.appendChild(mk("div", "sub", view.title));
|
|
@@ -3082,6 +3163,7 @@ function createBenchPanel(o) {
|
|
|
3082
3163
|
for (const control of view.controls) if (!control.hidden) list.appendChild(controlElement(control));
|
|
3083
3164
|
body.appendChild(list);
|
|
3084
3165
|
if (view.layers.length) body.appendChild(layerList(view.layers));
|
|
3166
|
+
if (view.sheet) body.appendChild(sheetCard(view.sheet));
|
|
3085
3167
|
};
|
|
3086
3168
|
const renderMetrics = (rows) => {
|
|
3087
3169
|
metricList.textContent = "";
|
|
@@ -3112,6 +3194,7 @@ function createBenchPanel(o) {
|
|
|
3112
3194
|
hasBench = view !== null;
|
|
3113
3195
|
syncDisplay();
|
|
3114
3196
|
if (!view) {
|
|
3197
|
+
playhead = null;
|
|
3115
3198
|
shape = "";
|
|
3116
3199
|
body.textContent = "";
|
|
3117
3200
|
refreshers.length = 0;
|
|
@@ -3141,6 +3224,10 @@ function createBenchPanel(o) {
|
|
|
3141
3224
|
node.text.textContent = row.text;
|
|
3142
3225
|
if (node.bar && row.ratio !== void 0) fillBar(node.bar, row.ratio);
|
|
3143
3226
|
}
|
|
3227
|
+
if (playhead) {
|
|
3228
|
+
const at = rows.module.find((row) => row.id === playhead?.metric)?.value;
|
|
3229
|
+
playhead.node.style.left = `${Math.max(0, Math.min(1, (at ?? 0) / playhead.end)) * 100}%`;
|
|
3230
|
+
}
|
|
3144
3231
|
},
|
|
3145
3232
|
get visible() {
|
|
3146
3233
|
if (element.style.display === "none") return false;
|
|
@@ -3173,6 +3260,13 @@ var CSS = `
|
|
|
3173
3260
|
.tr-status{margin-top:4px;min-height:16px;color:#ffd23f;text-shadow:0 1px 2px #000}
|
|
3174
3261
|
.tr-prog{margin:4px auto 0;width:260px;background:rgba(10,12,16,.72);border-radius:6px;padding:4px 8px;display:none}
|
|
3175
3262
|
.tr-prog b{display:block;font-weight:500;margin-bottom:3px}
|
|
3263
|
+
.tr-sheet{margin-top:8px;padding:8px;border:1px solid #2a2e36;border-radius:6px;font-size:12px;line-height:1.4}
|
|
3264
|
+
.tr-sheet h4{margin:2px 0 4px;font-size:13px}.tr-sheet p{margin:4px 0}
|
|
3265
|
+
.tr-facts{display:grid;grid-template-columns:auto 1fr;gap:2px 8px;margin:4px 0}.tr-facts dt{opacity:.7}.tr-facts dd{margin:0}
|
|
3266
|
+
.tr-steps{margin:4px 0;padding-left:16px}.tr-swatches{display:flex;flex-wrap:wrap;gap:6px}.tr-swatch i{display:inline-block;width:10px;height:10px;border-radius:50%;margin-right:4px}
|
|
3267
|
+
.tr-timeline{position:relative;height:22px;margin:8px 0;background:#1b1e24;border-radius:4px;overflow:hidden}
|
|
3268
|
+
.tr-segment{position:absolute;top:0;height:100%;font-size:10px;overflow:hidden;white-space:nowrap;opacity:.85;padding:0 3px;box-sizing:border-box;color:#000}
|
|
3269
|
+
.tr-tick{position:absolute;top:0;bottom:0;width:1px;background:#fff6;text-decoration:none}.tr-playhead{position:absolute;top:0;bottom:0;width:2px;background:#fff;text-decoration:none}
|
|
3176
3270
|
.tr-bar{height:7px;background:#2a2e36;border-radius:4px;overflow:hidden}
|
|
3177
3271
|
.tr-bar i{display:block;height:100%;background:#4fc3f7;width:0}
|
|
3178
3272
|
.tr-bar.hp i{background:#66bb6a}.tr-bar.warn i{background:#ffb300}.tr-bar.bad i{background:#ef5350}
|
|
@@ -3777,9 +3871,29 @@ function createTestRoom(options) {
|
|
|
3777
3871
|
let simTime = 0;
|
|
3778
3872
|
const log = createLog({ exportCancelled: () => t("log.export_cancelled") });
|
|
3779
3873
|
log.setClock(() => simTime);
|
|
3874
|
+
const craterField = options.craters ? createGroundField() : void 0;
|
|
3875
|
+
const craterPatch = craterField ? createGroundPatch(THREE, { field: craterField, material: new THREE.MeshStandardMaterial({ color: 9342602, roughness: 0.95 }) }) : void 0;
|
|
3876
|
+
if (craterPatch) {
|
|
3877
|
+
const floor = arena.group.getObjectByName("floor");
|
|
3878
|
+
if (floor) floor.visible = false;
|
|
3879
|
+
scene.add(craterPatch.mesh);
|
|
3880
|
+
}
|
|
3881
|
+
const vfx = createVfxRenderer(THREE, {
|
|
3882
|
+
scene,
|
|
3883
|
+
camera,
|
|
3884
|
+
overlay: container,
|
|
3885
|
+
quality,
|
|
3886
|
+
pointScale,
|
|
3887
|
+
vfx: createVfx({
|
|
3888
|
+
profile: quality,
|
|
3889
|
+
groundAt: (x, z) => groundAt(x, z) + (craterField?.heightAt(x, z) ?? 0),
|
|
3890
|
+
...craterField ? { ground: craterField } : {}
|
|
3891
|
+
})
|
|
3892
|
+
});
|
|
3780
3893
|
const renderer = createDestructionRenderer(THREE, {
|
|
3781
3894
|
scene,
|
|
3782
3895
|
world,
|
|
3896
|
+
vfx: vfx.world,
|
|
3783
3897
|
quality,
|
|
3784
3898
|
groundAt,
|
|
3785
3899
|
pointScale,
|
|
@@ -3805,7 +3919,17 @@ function createTestRoom(options) {
|
|
|
3805
3919
|
if (best) splitOf.set(piece.objectId, best);
|
|
3806
3920
|
}
|
|
3807
3921
|
});
|
|
3808
|
-
const fluidView = createFluidRenderer(THREE, { scene, fluids, quality, pointScale });
|
|
3922
|
+
const fluidView = createFluidRenderer(THREE, { scene, fluids, quality, pointScale, vfx: vfx.world });
|
|
3923
|
+
const filmRandom = createFilmLcg(1);
|
|
3924
|
+
const film = createFilmManager(THREE, {
|
|
3925
|
+
scene,
|
|
3926
|
+
camera,
|
|
3927
|
+
random: filmRandom,
|
|
3928
|
+
fluids,
|
|
3929
|
+
groundAt,
|
|
3930
|
+
...typeof gl.copyTextureToTexture === "function" ? { gpu: gl } : {}
|
|
3931
|
+
});
|
|
3932
|
+
const filmBridge = createFilmBridge({ fluids, manager: film, random: filmRandom });
|
|
3809
3933
|
const specs = /* @__PURE__ */ new Map();
|
|
3810
3934
|
const loose = [];
|
|
3811
3935
|
const arsenal = options.arsenal ?? createArsenal({ locale, weapons: options.weapons, seed: 1 });
|
|
@@ -3921,7 +4045,7 @@ function createTestRoom(options) {
|
|
|
3921
4045
|
for (const ev of batch) {
|
|
3922
4046
|
if (ev.type === "leak") puncture(ev);
|
|
3923
4047
|
else if (ev.type === "ignite") igniteNear(ev.point, 0.9);
|
|
3924
|
-
else if (ev.type === "explode") emitHost({ type: "explosion", source: ev.object, point: ev.point, energy: ev.energy, radius: ev.radius, cause: "part" });
|
|
4048
|
+
else if (ev.type === "explode") emitHost({ type: "explosion", source: ev.object, point: ev.point, energy: ev.energy, radius: ev.radius, cause: "part", ...ev.effect !== void 0 ? { explosive: ev.effect } : {} });
|
|
3925
4049
|
fire("event", ev);
|
|
3926
4050
|
options.onEvent?.(ev);
|
|
3927
4051
|
}
|
|
@@ -4109,8 +4233,10 @@ function createTestRoom(options) {
|
|
|
4109
4233
|
renderer.restore(e.so.objectId);
|
|
4110
4234
|
}
|
|
4111
4235
|
renderer.clear();
|
|
4236
|
+
vfx.world.clear();
|
|
4112
4237
|
fluids.clearStains([0, 0, 0], 1e4);
|
|
4113
4238
|
fluidView.clear();
|
|
4239
|
+
film.clear();
|
|
4114
4240
|
fluids.setTap(TAP_ID, false);
|
|
4115
4241
|
};
|
|
4116
4242
|
const clear = () => {
|
|
@@ -4501,6 +4627,7 @@ function createTestRoom(options) {
|
|
|
4501
4627
|
camera,
|
|
4502
4628
|
world,
|
|
4503
4629
|
renderer,
|
|
4630
|
+
effects: vfx.world,
|
|
4504
4631
|
arsenal,
|
|
4505
4632
|
objects: () => [...entries.values()].filter((e) => !e.arena).map((e) => e.so.root),
|
|
4506
4633
|
bodies: crossingBodies,
|
|
@@ -4934,7 +5061,7 @@ function createTestRoom(options) {
|
|
|
4934
5061
|
let metricsAcc = 0;
|
|
4935
5062
|
let ownsLoop = false;
|
|
4936
5063
|
const roomMetricIds = options.metrics === false ? [] : options.metrics ?? ROOM_METRICS;
|
|
4937
|
-
const roomMetrics = createRoomMetrics({ gl, destruction: renderer, fluids: fluidView, ids: roomMetricIds });
|
|
5064
|
+
const roomMetrics = createRoomMetrics({ gl, destruction: renderer, fluids: fluidView, effects: vfx.world, ids: roomMetricIds });
|
|
4938
5065
|
let qualityName = quality;
|
|
4939
5066
|
const syncContainers = (sdt) => {
|
|
4940
5067
|
for (const e of entries.values()) {
|
|
@@ -4983,8 +5110,12 @@ function createTestRoom(options) {
|
|
|
4983
5110
|
}
|
|
4984
5111
|
syncLiters();
|
|
4985
5112
|
renderer.update(dt);
|
|
5113
|
+
vfx.update(dt);
|
|
5114
|
+
craterPatch?.sync();
|
|
4986
5115
|
updateImpacts();
|
|
4987
5116
|
fluidView.update(dt);
|
|
5117
|
+
filmBridge.update(dt);
|
|
5118
|
+
film.update(dt);
|
|
4988
5119
|
for (const [id, s] of tools) {
|
|
4989
5120
|
s.update(dt);
|
|
4990
5121
|
flushEvents(id, s);
|
|
@@ -5145,7 +5276,7 @@ function createTestRoom(options) {
|
|
|
5145
5276
|
const benchView = () => {
|
|
5146
5277
|
const store = activeBench ? benches.get(activeBench) : void 0;
|
|
5147
5278
|
if (!store) return null;
|
|
5148
|
-
return { title: modules.get(store.moduleId)?.name ?? store.moduleId, controls: store.controls(), layers: store.layers() };
|
|
5279
|
+
return { title: modules.get(store.moduleId)?.name ?? store.moduleId, controls: store.controls(), layers: store.layers(), sheet: store.sheet() };
|
|
5149
5280
|
};
|
|
5150
5281
|
const METRIC_UNAVAILABLE = "n/a";
|
|
5151
5282
|
const metricText = (value, digits, unit) => typeof value === "number" ? `${num(value, digits)}${unit ? ` ${unit}` : ""}` : value ?? METRIC_UNAVAILABLE;
|
|
@@ -5180,7 +5311,7 @@ function createTestRoom(options) {
|
|
|
5180
5311
|
const module = declared.map((metric) => {
|
|
5181
5312
|
const value = values[metric.id];
|
|
5182
5313
|
const ratio = metric.max && typeof value === "number" ? value / metric.max : void 0;
|
|
5183
|
-
return { id: metric.id, name: metric.name, text: metricText(value, metric.digits ?? 0, metric.unit), ...ratio === void 0 ? {} : { ratio } };
|
|
5314
|
+
return { id: metric.id, name: metric.name, text: metricText(value, metric.digits ?? 0, metric.unit), ...typeof value === "number" ? { value } : {}, ...ratio === void 0 ? {} : { ratio } };
|
|
5184
5315
|
});
|
|
5185
5316
|
return { room: room2, module };
|
|
5186
5317
|
};
|
|
@@ -5241,6 +5372,7 @@ function createTestRoom(options) {
|
|
|
5241
5372
|
camera,
|
|
5242
5373
|
locale,
|
|
5243
5374
|
groundAt,
|
|
5375
|
+
effects: vfx,
|
|
5244
5376
|
tool: () => ({
|
|
5245
5377
|
weapon: toolId,
|
|
5246
5378
|
category: tool.def.category,
|
|
@@ -5294,6 +5426,7 @@ function createTestRoom(options) {
|
|
|
5294
5426
|
layer: store.layer,
|
|
5295
5427
|
onChange: store.onChange,
|
|
5296
5428
|
patch: store.patch,
|
|
5429
|
+
sheet: store.setSheet,
|
|
5297
5430
|
look: (eye, target) => room.look(eye, target)
|
|
5298
5431
|
});
|
|
5299
5432
|
const checkModuleBench = (mod, fail) => {
|
|
@@ -5579,6 +5712,7 @@ function createTestRoom(options) {
|
|
|
5579
5712
|
const id = moduleId ?? activeBench;
|
|
5580
5713
|
return (id ? benches.get(id) : void 0) ?? null;
|
|
5581
5714
|
},
|
|
5715
|
+
applyCamera: () => vfx.applyCamera(),
|
|
5582
5716
|
metrics() {
|
|
5583
5717
|
return { room: roomMetrics.sample(), module: moduleMetrics() };
|
|
5584
5718
|
},
|
|
@@ -5592,7 +5726,11 @@ function createTestRoom(options) {
|
|
|
5592
5726
|
player.dispose();
|
|
5593
5727
|
ui?.dispose();
|
|
5594
5728
|
renderer.dispose();
|
|
5729
|
+
vfx.dispose();
|
|
5730
|
+
craterPatch?.dispose();
|
|
5595
5731
|
fluidView.dispose();
|
|
5732
|
+
filmBridge.dispose();
|
|
5733
|
+
film.dispose();
|
|
5596
5734
|
for (const tr of tracers) tr.line.removeFromParent();
|
|
5597
5735
|
explosives.clear();
|
|
5598
5736
|
if (ownRenderer) {
|
|
@@ -5682,7 +5820,9 @@ function createTestRoom(options) {
|
|
|
5682
5820
|
const dt = Math.min(0.05, realDelta);
|
|
5683
5821
|
last = now;
|
|
5684
5822
|
if (!scenarioRunning) update(dt);
|
|
5823
|
+
const restoreCamera = vfx.applyCamera();
|
|
5685
5824
|
gl.render(scene, camera);
|
|
5825
|
+
restoreCamera();
|
|
5686
5826
|
roomMetrics.rendered();
|
|
5687
5827
|
};
|
|
5688
5828
|
raf = requestAnimationFrame(loop);
|