@adatechnology/game-vehicles-three 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-GAO7ZJP7.js +1456 -0
- package/dist/chunk-GAO7ZJP7.js.map +1 -0
- package/dist/index.d.ts +13 -184
- package/dist/index.global.js +1603 -115
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +25 -1220
- package/dist/index.js.map +1 -1
- package/dist/testing-DmGv7Gpb.d.ts +219 -0
- package/dist/testing.d.ts +3 -0
- package/dist/testing.js +25 -0
- package/dist/testing.js.map +1 -0
- package/package.json +14 -8
package/dist/index.global.js
CHANGED
|
@@ -28,10 +28,12 @@ var GameVehiclesThree = (() => {
|
|
|
28
28
|
PAGE_SCENARIO_ALIASES: () => PAGE_SCENARIO_ALIASES,
|
|
29
29
|
PRUNE_BELOW: () => PRUNE_BELOW,
|
|
30
30
|
VEHICLES_AREA_ID: () => VEHICLES_AREA_ID,
|
|
31
|
+
VEHICLE_LOD_DISTANCE: () => VEHICLE_LOD_DISTANCE,
|
|
31
32
|
VEHICLE_SCENARIO_IDS: () => VEHICLE_SCENARIO_IDS,
|
|
32
33
|
classColor: () => classColor,
|
|
33
34
|
classify: () => classify,
|
|
34
35
|
createCabinSmoke: () => createCabinSmoke,
|
|
36
|
+
createVehicleLod: () => createVehicleLod,
|
|
35
37
|
createVehiclesTestModule: () => createVehiclesTestModule,
|
|
36
38
|
createVehiclesThree: () => createVehiclesThree,
|
|
37
39
|
defaultEffectIds: () => defaultEffectIds,
|
|
@@ -43,6 +45,7 @@ var GameVehiclesThree = (() => {
|
|
|
43
45
|
});
|
|
44
46
|
|
|
45
47
|
// ../game-contracts/dist/index.js
|
|
48
|
+
var DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024;
|
|
46
49
|
var DEFAULT_IGNITION_RULES = {
|
|
47
50
|
fillCurve: [
|
|
48
51
|
[0, 0.6],
|
|
@@ -86,6 +89,38 @@ var GameVehiclesThree = (() => {
|
|
|
86
89
|
const flame = flameBase * (1 - rules.flameFillInfluence * (1 - k));
|
|
87
90
|
return 1 - (1 - Math.min(1, Math.max(0, spark))) * (1 - Math.min(1, Math.max(0, flame)));
|
|
88
91
|
};
|
|
92
|
+
var DEFERRED_QUEUE_ID = {
|
|
93
|
+
DESTRUCTION_EVENTS: "destruction.events",
|
|
94
|
+
BREACH_PAINT: "floorplan.breach-paint",
|
|
95
|
+
AUDIO_VOICES: "audio.voices",
|
|
96
|
+
VEHICLE_CREASE: "vehicles.crease"
|
|
97
|
+
};
|
|
98
|
+
var DEFERRED_PRIORITY = {
|
|
99
|
+
[DEFERRED_QUEUE_ID.DESTRUCTION_EVENTS]: { priority: 300, phase: "present" },
|
|
100
|
+
[DEFERRED_QUEUE_ID.BREACH_PAINT]: { priority: 250, phase: "present" },
|
|
101
|
+
[DEFERRED_QUEUE_ID.AUDIO_VOICES]: { priority: 200, phase: "idle", reserveMs: 1 },
|
|
102
|
+
[DEFERRED_QUEUE_ID.VEHICLE_CREASE]: { priority: 100, phase: "idle" }
|
|
103
|
+
};
|
|
104
|
+
var WARNED_KEY = /* @__PURE__ */ Symbol.for("@adatechnology/game-contracts.warned");
|
|
105
|
+
var warnedKeys = () => {
|
|
106
|
+
const holder = globalThis;
|
|
107
|
+
return holder[WARNED_KEY] ?? (holder[WARNED_KEY] = /* @__PURE__ */ new Set());
|
|
108
|
+
};
|
|
109
|
+
var isProduction = () => {
|
|
110
|
+
try {
|
|
111
|
+
return process.env.NODE_ENV === "production";
|
|
112
|
+
} catch {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
var isQuiet = () => globalThis.__GAME_KIT_QUIET__ === true;
|
|
117
|
+
var warnOnce = (key, message) => {
|
|
118
|
+
if (isQuiet() || isProduction()) return;
|
|
119
|
+
const seen = warnedKeys();
|
|
120
|
+
if (seen.has(key)) return;
|
|
121
|
+
seen.add(key);
|
|
122
|
+
console.warn(`[game-kit] ${message}`);
|
|
123
|
+
};
|
|
89
124
|
var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
90
125
|
var isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
|
|
91
126
|
var deepMerge = (base, patch) => {
|
|
@@ -107,10 +142,13 @@ var GameVehiclesThree = (() => {
|
|
|
107
142
|
for (const [id, patch] of Object.entries(patches ?? {})) {
|
|
108
143
|
const entry = entries.get(id);
|
|
109
144
|
if (entry) entries.set(id, deepMerge(entry, patch));
|
|
145
|
+
else warnOnce(`registry.patch.${id}`, `patch for "${id}" ignored: no entry has that id`);
|
|
110
146
|
}
|
|
111
147
|
};
|
|
112
148
|
var removeIds = (entries, ids) => {
|
|
113
|
-
for (const id of ids ?? [])
|
|
149
|
+
for (const id of ids ?? []) {
|
|
150
|
+
if (!entries.delete(id)) warnOnce(`registry.remove.${id}`, `remove of "${id}" ignored: no entry has that id`);
|
|
151
|
+
}
|
|
114
152
|
};
|
|
115
153
|
var KIT_ORIGIN_KEY = "kitOrigin";
|
|
116
154
|
function markKitOrigin(object2, origin) {
|
|
@@ -135,6 +173,43 @@ var GameVehiclesThree = (() => {
|
|
|
135
173
|
return lx > fp.minX - radius && lx < fp.maxX + radius && lz > fp.minZ - radius && lz < fp.maxZ + radius;
|
|
136
174
|
};
|
|
137
175
|
}
|
|
176
|
+
var SURFACE_IDS = ["concrete", "asphalt", "wood", "tile", "dirt", "grass", "gravel", "sand", "metal", "water", "glass", "carpet"];
|
|
177
|
+
var GAIT_IDS = ["walk", "run"];
|
|
178
|
+
var LANDING_IDS = ["light", "heavy"];
|
|
179
|
+
var BODY_SOUND_IDS = [
|
|
180
|
+
"jump",
|
|
181
|
+
"cloth_rustle",
|
|
182
|
+
"body_fall",
|
|
183
|
+
"fall_damage",
|
|
184
|
+
"player_hurt",
|
|
185
|
+
"player_breath_run",
|
|
186
|
+
"player_death",
|
|
187
|
+
"bite",
|
|
188
|
+
"grab",
|
|
189
|
+
"punch_swing",
|
|
190
|
+
"punch_hit_body",
|
|
191
|
+
"punch_hit_face",
|
|
192
|
+
"punch_hit_object",
|
|
193
|
+
"kick_swing",
|
|
194
|
+
"kick_hit",
|
|
195
|
+
"kick_hit_object",
|
|
196
|
+
"shove_two_hands",
|
|
197
|
+
"knife_swing",
|
|
198
|
+
"knife_stab",
|
|
199
|
+
"knife_slash",
|
|
200
|
+
"knife_hit_object",
|
|
201
|
+
"blunt_swing",
|
|
202
|
+
"blunt_hit",
|
|
203
|
+
"blunt_hit_object",
|
|
204
|
+
"axe_swing",
|
|
205
|
+
"axe_chop",
|
|
206
|
+
"axe_hit_object"
|
|
207
|
+
];
|
|
208
|
+
var footstepSoundId = (surface, gait) => `footstep_${surface}_${gait}`;
|
|
209
|
+
var FOOTSTEP_SOUND_IDS = SURFACE_IDS.flatMap((surface) => GAIT_IDS.map((gait) => footstepSoundId(surface, gait)));
|
|
210
|
+
var LAND_SOUND_IDS = SURFACE_IDS.flatMap((surface) => LANDING_IDS.map((landing2) => `land_${surface}_${landing2}`));
|
|
211
|
+
var BODY_FOLEY_IDS = [...FOOTSTEP_SOUND_IDS, ...LAND_SOUND_IDS, ...BODY_SOUND_IDS];
|
|
212
|
+
var SWING_LEAD_SECONDS = { punch: 0.07, kick: 0.09, shove: 0, blade: 0.05, blunt: 0.1, chop: 0.11 };
|
|
138
213
|
|
|
139
214
|
// ../game-vehicles-fleet/dist/index.js
|
|
140
215
|
var military = [
|
|
@@ -24324,7 +24399,7 @@ var GameVehiclesThree = (() => {
|
|
|
24324
24399
|
c2.cylinder(0.03, 0.04, 0.08, MT.chrome, sx + 2.35, fl + 0.99, -0.75);
|
|
24325
24400
|
c2.part("fuel_tank", trl("labels.oxygen_cylinder"), null, new V3(sx + 2.35, fl + 0.5, -0.75), 0.5);
|
|
24326
24401
|
c2.roundBox(0.04, 0.26, 0.34, 0.02, MT.screen, 0.1, 1.7, 0.5);
|
|
24327
|
-
const
|
|
24402
|
+
const lightPanel = c2.roundBox(
|
|
24328
24403
|
2.3,
|
|
24329
24404
|
0.02,
|
|
24330
24405
|
W - 0.3,
|
|
@@ -24334,7 +24409,7 @@ var GameVehiclesThree = (() => {
|
|
|
24334
24409
|
m.top - 0.06,
|
|
24335
24410
|
0
|
|
24336
24411
|
);
|
|
24337
|
-
|
|
24412
|
+
lightPanel.castShadow = false;
|
|
24338
24413
|
m.roofItems = beaconBar;
|
|
24339
24414
|
}
|
|
24340
24415
|
});
|
|
@@ -27893,15 +27968,17 @@ var GameVehiclesThree = (() => {
|
|
|
27893
27968
|
}
|
|
27894
27969
|
function createVehiclesThree(THREE, options) {
|
|
27895
27970
|
const kit = options.kit;
|
|
27971
|
+
const fleet = options.fleet ?? { colorFromSeed, fleetDims, paintPalettes, paletteOf };
|
|
27972
|
+
const { colorFromSeed: colorFromSeed2, fleetDims: fleetDims2, paintPalettes: paintPalettes2, paletteOf: paletteOf2 } = fleet;
|
|
27896
27973
|
const groupOf = options.groupOf || ((key) => kit.find(key)?.group === kit.config.defaultGroup ? "cars" : String(kit.find(key)?.group));
|
|
27897
27974
|
const militaryKeys = /* @__PURE__ */ new Set();
|
|
27898
|
-
const isMilitary = (key) => militaryKeys.has(key) ||
|
|
27975
|
+
const isMilitary = (key) => militaryKeys.has(key) || paletteOf2(groupOf(key)) === paintPalettes2.military;
|
|
27899
27976
|
const build = (key, o = {}) => {
|
|
27900
27977
|
const quality = o.quality === "lite" ? "lite" : "high";
|
|
27901
27978
|
const spec = kit.find(key);
|
|
27902
27979
|
if (!spec) throw new Error(`createVehiclesThree: unknown vehicle "${key}"`);
|
|
27903
27980
|
const seed = o.seed == null ? null : o.seed;
|
|
27904
|
-
const color2 = o.color || (seed != null ?
|
|
27981
|
+
const color2 = o.color || (seed != null ? colorFromSeed2(seed, isMilitary(key) ? paintPalettes2.military : paintPalettes2.civil) : null);
|
|
27905
27982
|
const c = kit.build(key, o.state || "intact", void 0, { lod: quality === "lite" });
|
|
27906
27983
|
c.root.updateMatrixWorld(true);
|
|
27907
27984
|
const primary = primaryPaint(c);
|
|
@@ -27967,7 +28044,7 @@ var GameVehiclesThree = (() => {
|
|
|
27967
28044
|
width: +size.x.toFixed(3),
|
|
27968
28045
|
height: +size.y.toFixed(3),
|
|
27969
28046
|
pruned,
|
|
27970
|
-
expected:
|
|
28047
|
+
expected: fleetDims2(key),
|
|
27971
28048
|
context: quality === "high" ? c : null,
|
|
27972
28049
|
dispose() {
|
|
27973
28050
|
group.traverse((m) => {
|
|
@@ -27992,7 +28069,7 @@ var GameVehiclesThree = (() => {
|
|
|
27992
28069
|
}
|
|
27993
28070
|
}
|
|
27994
28071
|
|
|
27995
|
-
// ../game-shapes/dist/chunk-
|
|
28072
|
+
// ../game-shapes/dist/chunk-IFXQIDSA.js
|
|
27996
28073
|
function canonicalJson(value) {
|
|
27997
28074
|
if (value === null) return "null";
|
|
27998
28075
|
if (typeof value === "number") return Object.is(value, -0) ? "-0" : Number.isFinite(value) ? String(value) : JSON.stringify(String(value));
|
|
@@ -29287,10 +29364,10 @@ var GameVehiclesThree = (() => {
|
|
|
29287
29364
|
return cached;
|
|
29288
29365
|
}
|
|
29289
29366
|
stats.misses++;
|
|
29290
|
-
const
|
|
29291
|
-
templates.set(key,
|
|
29367
|
+
const built2 = make(node.kind, parameters);
|
|
29368
|
+
templates.set(key, built2);
|
|
29292
29369
|
if (templates.size > templateLimit) templates.delete(templates.keys().next().value);
|
|
29293
|
-
return
|
|
29370
|
+
return built2;
|
|
29294
29371
|
}
|
|
29295
29372
|
var num = (v) => typeof v === "number" && Number.isFinite(v) ? null : "expected a finite number";
|
|
29296
29373
|
var bool = (v) => typeof v === "boolean" ? null : "expected a boolean";
|
|
@@ -30468,7 +30545,7 @@ var GameVehiclesThree = (() => {
|
|
|
30468
30545
|
}
|
|
30469
30546
|
return ti.builtBlocks === total;
|
|
30470
30547
|
}
|
|
30471
|
-
function start(geo) {
|
|
30548
|
+
function start(geo, store = cache) {
|
|
30472
30549
|
const pos = geo.attributes.position;
|
|
30473
30550
|
const triangles = trianglesOf(geo);
|
|
30474
30551
|
const ti = {
|
|
@@ -30481,7 +30558,7 @@ var GameVehiclesThree = (() => {
|
|
|
30481
30558
|
blocks: new Float64Array(blockCount(triangles) * 6),
|
|
30482
30559
|
builtBlocks: 0
|
|
30483
30560
|
};
|
|
30484
|
-
|
|
30561
|
+
store.set(geo, ti);
|
|
30485
30562
|
return ti;
|
|
30486
30563
|
}
|
|
30487
30564
|
function triIndexOf(geo) {
|
|
@@ -30533,6 +30610,106 @@ var GameVehiclesThree = (() => {
|
|
|
30533
30610
|
}
|
|
30534
30611
|
return { box: box2, version: ti.positionVersion };
|
|
30535
30612
|
}
|
|
30613
|
+
var rayCache = /* @__PURE__ */ new WeakMap();
|
|
30614
|
+
function rayIndexOf(geo) {
|
|
30615
|
+
const shared2 = cache.get(geo);
|
|
30616
|
+
if (shared2 && isCurrent(geo, shared2) && shared2.builtBlocks === blockCount(shared2.triangles)) return shared2;
|
|
30617
|
+
let ti = rayCache.get(geo);
|
|
30618
|
+
if (!ti || !isCurrent(geo, ti)) ti = start(geo, rayCache);
|
|
30619
|
+
advance(geo, ti, Infinity);
|
|
30620
|
+
return ti;
|
|
30621
|
+
}
|
|
30622
|
+
var BLOCK_SLACK = 1e-6;
|
|
30623
|
+
var scratch = /* @__PURE__ */ new WeakMap();
|
|
30624
|
+
function scratchOf(THREE) {
|
|
30625
|
+
let s = scratch.get(THREE);
|
|
30626
|
+
if (!s) {
|
|
30627
|
+
s = {
|
|
30628
|
+
inverse: new THREE.Matrix4(),
|
|
30629
|
+
local: new THREE.Ray(),
|
|
30630
|
+
box: new THREE.Box3(),
|
|
30631
|
+
a: new THREE.Vector3(),
|
|
30632
|
+
b: new THREE.Vector3(),
|
|
30633
|
+
c: new THREE.Vector3(),
|
|
30634
|
+
point: new THREE.Vector3(),
|
|
30635
|
+
world: new THREE.Vector3(),
|
|
30636
|
+
sphere: new THREE.Sphere()
|
|
30637
|
+
};
|
|
30638
|
+
scratch.set(THREE, s);
|
|
30639
|
+
}
|
|
30640
|
+
return s;
|
|
30641
|
+
}
|
|
30642
|
+
function indexable(THREE, mesh2) {
|
|
30643
|
+
const geo = mesh2.geometry;
|
|
30644
|
+
if (mesh2.raycast !== THREE.Mesh.prototype.raycast) return false;
|
|
30645
|
+
if (!mesh2.isMesh || mesh2.isSkinnedMesh || mesh2.isInstancedMesh || mesh2.isBatchedMesh || !geo || !geo.isBufferGeometry) return false;
|
|
30646
|
+
if (!mesh2.material || Array.isArray(mesh2.material)) return false;
|
|
30647
|
+
if (geo.morphAttributes && geo.morphAttributes.position && geo.morphAttributes.position.length) return false;
|
|
30648
|
+
return supports(geo);
|
|
30649
|
+
}
|
|
30650
|
+
function raycastMesh(THREE, raycaster, mesh2, out) {
|
|
30651
|
+
const geo = mesh2.geometry;
|
|
30652
|
+
const s = scratchOf(THREE);
|
|
30653
|
+
if (geo.boundingSphere === null) geo.computeBoundingSphere();
|
|
30654
|
+
s.sphere.copy(geo.boundingSphere).applyMatrix4(mesh2.matrixWorld);
|
|
30655
|
+
if (!raycaster.ray.intersectsSphere(s.sphere)) return;
|
|
30656
|
+
const ti = rayIndexOf(geo);
|
|
30657
|
+
if (!ti) return;
|
|
30658
|
+
s.inverse.copy(mesh2.matrixWorld).invert();
|
|
30659
|
+
s.local.copy(raycaster.ray).applyMatrix4(s.inverse);
|
|
30660
|
+
const material = mesh2.material;
|
|
30661
|
+
const back = material.side === THREE.BackSide;
|
|
30662
|
+
const cull = material.side === THREE.FrontSide;
|
|
30663
|
+
const P = geo.attributes.position;
|
|
30664
|
+
const ix = geo.index;
|
|
30665
|
+
const count2 = ix ? ix.count : P.count;
|
|
30666
|
+
const first = Math.max(0, geo.drawRange.start);
|
|
30667
|
+
const last = Math.min(count2, geo.drawRange.start + geo.drawRange.count);
|
|
30668
|
+
const t0 = Math.ceil(first / 3);
|
|
30669
|
+
const t1 = Math.floor(last / 3);
|
|
30670
|
+
const B = ti.boxes;
|
|
30671
|
+
const K = ti.blocks;
|
|
30672
|
+
for (let blk = Math.floor(t0 / TRI_BLOCK); blk * TRI_BLOCK < t1; blk++) {
|
|
30673
|
+
const o = blk * 6;
|
|
30674
|
+
s.box.min.set(K[o] - BLOCK_SLACK, K[o + 1] - BLOCK_SLACK, K[o + 2] - BLOCK_SLACK);
|
|
30675
|
+
s.box.max.set(K[o + 3] + BLOCK_SLACK, K[o + 4] + BLOCK_SLACK, K[o + 5] + BLOCK_SLACK);
|
|
30676
|
+
if (!s.local.intersectsBox(s.box)) continue;
|
|
30677
|
+
const end = Math.min(t1, (blk + 1) * TRI_BLOCK);
|
|
30678
|
+
for (let t = Math.max(t0, blk * TRI_BLOCK); t < end; t++) {
|
|
30679
|
+
const j = t * 6;
|
|
30680
|
+
s.box.min.set(B[j] - BLOCK_SLACK, B[j + 1] - BLOCK_SLACK, B[j + 2] - BLOCK_SLACK);
|
|
30681
|
+
s.box.max.set(B[j + 3] + BLOCK_SLACK, B[j + 4] + BLOCK_SLACK, B[j + 5] + BLOCK_SLACK);
|
|
30682
|
+
if (!s.local.intersectsBox(s.box)) continue;
|
|
30683
|
+
const a = ix ? ix.getX(t * 3) : t * 3;
|
|
30684
|
+
const b = ix ? ix.getX(t * 3 + 1) : t * 3 + 1;
|
|
30685
|
+
const c = ix ? ix.getX(t * 3 + 2) : t * 3 + 2;
|
|
30686
|
+
s.a.fromBufferAttribute(P, a);
|
|
30687
|
+
s.b.fromBufferAttribute(P, b);
|
|
30688
|
+
s.c.fromBufferAttribute(P, c);
|
|
30689
|
+
const hit = back ? s.local.intersectTriangle(s.c, s.b, s.a, true, s.point) : s.local.intersectTriangle(s.a, s.b, s.c, cull, s.point);
|
|
30690
|
+
if (hit === null) continue;
|
|
30691
|
+
s.world.copy(s.point).applyMatrix4(mesh2.matrixWorld);
|
|
30692
|
+
const distance = raycaster.ray.origin.distanceTo(s.world);
|
|
30693
|
+
if (distance < raycaster.near || distance > raycaster.far) continue;
|
|
30694
|
+
const normal = new THREE.Vector3();
|
|
30695
|
+
THREE.Triangle.getNormal(s.a, s.b, s.c, normal);
|
|
30696
|
+
out.push({ distance, point: s.world.clone(), object: mesh2, face: { a, b, c, normal, materialIndex: 0 }, faceIndex: Math.floor(t) });
|
|
30697
|
+
}
|
|
30698
|
+
}
|
|
30699
|
+
}
|
|
30700
|
+
function collect2(THREE, raycaster, object2, recursive, out) {
|
|
30701
|
+
if (object2.layers.test(raycaster.layers)) {
|
|
30702
|
+
if (indexable(THREE, object2)) raycastMesh(THREE, raycaster, object2, out);
|
|
30703
|
+
else object2.raycast(raycaster, out);
|
|
30704
|
+
}
|
|
30705
|
+
if (recursive) for (const child of object2.children) collect2(THREE, raycaster, child, true, out);
|
|
30706
|
+
}
|
|
30707
|
+
function raycastIndexed(THREE, raycaster, objects, recursive = false) {
|
|
30708
|
+
const out = [];
|
|
30709
|
+
for (const object2 of objects) collect2(THREE, raycaster, object2, recursive, out);
|
|
30710
|
+
out.sort((x, y) => x.distance - y.distance);
|
|
30711
|
+
return out;
|
|
30712
|
+
}
|
|
30536
30713
|
function installGeometry(kit) {
|
|
30537
30714
|
const THREE = kit.THREE;
|
|
30538
30715
|
const V3 = THREE.Vector3;
|
|
@@ -31857,6 +32034,7 @@ var GameVehiclesThree = (() => {
|
|
|
31857
32034
|
}
|
|
31858
32035
|
kit.profX = profX;
|
|
31859
32036
|
const _sr = new THREE.Raycaster();
|
|
32037
|
+
_sr.layers.enableAll();
|
|
31860
32038
|
kit.surfaceAt = function(c, org, dir, o) {
|
|
31861
32039
|
o = o || {};
|
|
31862
32040
|
c.root.updateMatrixWorld(true);
|
|
@@ -31873,7 +32051,7 @@ var GameVehiclesThree = (() => {
|
|
|
31873
32051
|
_sr.set(p0.clone().applyMatrix4(Mw), d.clone().transformDirection(Mw));
|
|
31874
32052
|
_sr.near = 0;
|
|
31875
32053
|
_sr.far = o.max || 20;
|
|
31876
|
-
const h =
|
|
32054
|
+
const h = raycastIndexed(THREE, _sr, cands)[0];
|
|
31877
32055
|
if (!h) return null;
|
|
31878
32056
|
const n = h.face ? h.face.normal.clone().transformDirection(h.object.matrixWorld).transformDirection(inv) : d.clone().negate();
|
|
31879
32057
|
if (n.dot(d) > 0) n.negate();
|
|
@@ -31893,6 +32071,7 @@ var GameVehiclesThree = (() => {
|
|
|
31893
32071
|
const V3 = THREE.Vector3;
|
|
31894
32072
|
const I = kit._;
|
|
31895
32073
|
const { MATERIALS, crease, cutGeometry, pathShape, subdivide, tumble, uvProject } = I;
|
|
32074
|
+
I.paneSeals = /* @__PURE__ */ new WeakMap();
|
|
31896
32075
|
kit.addGlass = function(c, geo, label, type, o) {
|
|
31897
32076
|
o = o || {};
|
|
31898
32077
|
if (!geo.attributes.uv || o.reuv) o.aspect = uvProject(geo, o.uvAxes);
|
|
@@ -31959,7 +32138,7 @@ var GameVehiclesThree = (() => {
|
|
|
31959
32138
|
cy /= poly.length;
|
|
31960
32139
|
const base = I.resolveLabel(label ? label(i, polys.length) : { key: "window" });
|
|
31961
32140
|
const lab = { key: base.key, label: kit.t("parts.glass_side", { label: base.label, s }) };
|
|
31962
|
-
kit.addGlass(c, geo, lab, o.type || "tempered", {
|
|
32141
|
+
const pane = kit.addGlass(c, geo, lab, o.type || "tempered", {
|
|
31963
32142
|
mat: o.mat || (o.see === false ? MATERIALS.glassDark : MATERIALS.glass),
|
|
31964
32143
|
pos: new V3(cx, cy, s * I.halfAt(Wg, T, cy)),
|
|
31965
32144
|
outline: shp.getSpacedPoints(56),
|
|
@@ -31975,6 +32154,7 @@ var GameVehiclesThree = (() => {
|
|
|
31975
32154
|
pts.pop();
|
|
31976
32155
|
const seal = c.tube(pts, 0.011, MATERIALS.trim, { closed: true, seg: 72, rs: 5 });
|
|
31977
32156
|
seal.castShadow = false;
|
|
32157
|
+
I.paneSeals.set(pane, seal);
|
|
31978
32158
|
});
|
|
31979
32159
|
});
|
|
31980
32160
|
};
|
|
@@ -33671,6 +33851,42 @@ var GameVehiclesThree = (() => {
|
|
|
33671
33851
|
};
|
|
33672
33852
|
Object.assign(I, {});
|
|
33673
33853
|
}
|
|
33854
|
+
var ROUTED_PARTICLE_TYPES = { smoke: "particle_puff", dust: "particle_puff", fire: "particle_glow" };
|
|
33855
|
+
var PUFF_LOOKS = {
|
|
33856
|
+
smokewhite: [10133927, 0.42],
|
|
33857
|
+
smokeblack: [1776412, 0.62],
|
|
33858
|
+
smokegray: [5593436, 0.5],
|
|
33859
|
+
smokesteam: [11975873, 0.3],
|
|
33860
|
+
dust: [7235160, 0.34],
|
|
33861
|
+
fire: [16777215, 0.9]
|
|
33862
|
+
};
|
|
33863
|
+
var LIFE = { dust: 1.6, smoke: 2.8, fire: 0.7 };
|
|
33864
|
+
var FIRE_COLOR = 16753968;
|
|
33865
|
+
var SMOKE_START_SCALE = 0.18;
|
|
33866
|
+
function routedParticleRequest(input) {
|
|
33867
|
+
const { type } = input;
|
|
33868
|
+
const look = PUFF_LOOKS[type + (input.variant ?? "")] ?? PUFF_LOOKS[type] ?? PUFF_LOOKS.smokewhite;
|
|
33869
|
+
const life = input.life ?? LIFE[type] ?? 99;
|
|
33870
|
+
const size = (input.size ?? 1) * (input.grow ?? 1);
|
|
33871
|
+
const isFire = type === "fire";
|
|
33872
|
+
const growth = isFire ? 1 : (SMOKE_START_SCALE + 1.5 * (1 - Math.exp(-life * 1.1)) + life * 0.12) / SMOKE_START_SCALE;
|
|
33873
|
+
return {
|
|
33874
|
+
effect: ROUTED_PARTICLE_TYPES[type],
|
|
33875
|
+
point: input.position,
|
|
33876
|
+
values: {
|
|
33877
|
+
vx: input.velocity[0],
|
|
33878
|
+
vy: input.velocity[1],
|
|
33879
|
+
vz: input.velocity[2],
|
|
33880
|
+
life,
|
|
33881
|
+
size: isFire ? size * 0.85 : size * SMOKE_START_SCALE,
|
|
33882
|
+
grow: growth,
|
|
33883
|
+
color: input.color ?? (isFire ? FIRE_COLOR : look[0]),
|
|
33884
|
+
alpha: input.alpha ?? look[1],
|
|
33885
|
+
gravity: isFire ? 0 : type === "dust" ? 0 : -0.08,
|
|
33886
|
+
drag: type === "dust" ? 2.5 : isFire ? 1.5 : 0.9
|
|
33887
|
+
}
|
|
33888
|
+
};
|
|
33889
|
+
}
|
|
33674
33890
|
function installParticles(kit) {
|
|
33675
33891
|
const THREE = kit.THREE;
|
|
33676
33892
|
const V3 = THREE.Vector3;
|
|
@@ -33761,7 +33977,7 @@ var GameVehiclesThree = (() => {
|
|
|
33761
33977
|
});
|
|
33762
33978
|
}
|
|
33763
33979
|
const list2 = fire ? FIRE_TEXTURES : SMOKE_TEXTURES;
|
|
33764
|
-
const
|
|
33980
|
+
const build = () => new THREE.SpriteMaterial({
|
|
33765
33981
|
map: list2[Math.floor(Math.random() * list2.length)],
|
|
33766
33982
|
color: new THREE.Color(col),
|
|
33767
33983
|
transparent: true,
|
|
@@ -33769,6 +33985,7 @@ var GameVehiclesThree = (() => {
|
|
|
33769
33985
|
opacity: op,
|
|
33770
33986
|
blending: fire ? THREE.AdditiveBlending : THREE.NormalBlending
|
|
33771
33987
|
});
|
|
33988
|
+
const mat = kit.particleMaterials ? kit.particleMaterials.own(build) : build();
|
|
33772
33989
|
const dis = { value: 0 };
|
|
33773
33990
|
mat.userData.dis = dis;
|
|
33774
33991
|
mat.onBeforeCompile = function(sh) {
|
|
@@ -33796,11 +34013,37 @@ var GameVehiclesThree = (() => {
|
|
|
33796
34013
|
function killParticle(c, i) {
|
|
33797
34014
|
const P = c.particles[i];
|
|
33798
34015
|
c.effects.remove(P.m);
|
|
33799
|
-
if (P.own)
|
|
34016
|
+
if (P.own) {
|
|
34017
|
+
if (kit.particleMaterials) kit.particleMaterials.release(P.m.material);
|
|
34018
|
+
else P.m.material.dispose();
|
|
34019
|
+
}
|
|
33800
34020
|
c.particles.splice(i, 1);
|
|
33801
34021
|
}
|
|
34022
|
+
function routeParticle(c, effects, type, pos, vel, o) {
|
|
34023
|
+
c.effects.updateWorldMatrix(true, false);
|
|
34024
|
+
const at = pos.clone().applyMatrix4(c.effects.matrixWorld);
|
|
34025
|
+
const to = vel.clone().transformDirection(c.effects.matrixWorld).multiplyScalar(vel.length());
|
|
34026
|
+
const colour = o.col == null ? void 0 : new THREE.Color(o.col).getHex();
|
|
34027
|
+
effects.play(
|
|
34028
|
+
routedParticleRequest({
|
|
34029
|
+
type,
|
|
34030
|
+
position: [at.x, at.y, at.z],
|
|
34031
|
+
velocity: [to.x, to.y, to.z],
|
|
34032
|
+
...o.variant ? { variant: o.variant } : {},
|
|
34033
|
+
...colour !== void 0 ? { color: colour } : {},
|
|
34034
|
+
...o.op != null ? { alpha: o.op } : {},
|
|
34035
|
+
...o.s ? { size: o.s } : {},
|
|
34036
|
+
...o.life ? { life: o.life } : {},
|
|
34037
|
+
...o.grow ? { grow: o.grow } : {}
|
|
34038
|
+
})
|
|
34039
|
+
);
|
|
34040
|
+
return null;
|
|
34041
|
+
}
|
|
33802
34042
|
kit.spawn = function(c, type, pos, vel, o) {
|
|
33803
34043
|
o = o || {};
|
|
34044
|
+
const effects = ROUTED_PARTICLE_TYPES[type] ? kit.effects?.() : void 0;
|
|
34045
|
+
if (effects) return routeParticle(c, effects, type, pos, vel, o);
|
|
34046
|
+
if (ROUTED_PARTICLE_TYPES[type] && !kit.effects) warnOnce("game-vehicles.own-particles", "game-vehicles drew its smoke, fire and dust with sprites of its own because the host lent no effects world (options.effects); pass the host effects so the puffs share one budget");
|
|
33804
34047
|
if (c.particles.length >= PARTICLE_LIMIT) {
|
|
33805
34048
|
const idx = c.particles.findIndex(function(q) {
|
|
33806
34049
|
return TRANSIENT_TYPES[q.type];
|
|
@@ -34070,6 +34313,7 @@ var GameVehiclesThree = (() => {
|
|
|
34070
34313
|
};
|
|
34071
34314
|
kit.defineFluid("stain", { fresh: "#4a4a44", dry: "#26241f", wipeable: false });
|
|
34072
34315
|
const _fr = new THREE.Raycaster();
|
|
34316
|
+
_fr.layers.enableAll();
|
|
34073
34317
|
kit.splat = function(c, p, n, r, o) {
|
|
34074
34318
|
o = o || {};
|
|
34075
34319
|
n = n.clone().normalize();
|
|
@@ -34509,31 +34753,55 @@ var GameVehiclesThree = (() => {
|
|
|
34509
34753
|
};
|
|
34510
34754
|
Object.assign(I, { _fr, buildDrip, DOWNHILL, PN, puddleGeometry, rimGeometry, puddle, shapePuddle, updateFluids });
|
|
34511
34755
|
}
|
|
34756
|
+
function crackedGlassMaterial(THREE, texture) {
|
|
34757
|
+
return new THREE.MeshStandardMaterial({
|
|
34758
|
+
color: 16777215,
|
|
34759
|
+
map: texture,
|
|
34760
|
+
emissive: 6976118,
|
|
34761
|
+
emissiveMap: texture,
|
|
34762
|
+
transparent: true,
|
|
34763
|
+
roughness: 0.25,
|
|
34764
|
+
metalness: 0.1,
|
|
34765
|
+
side: THREE.DoubleSide,
|
|
34766
|
+
depthWrite: false
|
|
34767
|
+
});
|
|
34768
|
+
}
|
|
34512
34769
|
function installGlassDamage(kit) {
|
|
34513
34770
|
const THREE = kit.THREE;
|
|
34514
34771
|
const V3 = THREE.Vector3;
|
|
34515
34772
|
const PI = Math.PI;
|
|
34516
34773
|
const I = kit._;
|
|
34517
34774
|
const document2 = kit.document;
|
|
34518
|
-
const {
|
|
34519
|
-
function glassUV(msh, pLocal) {
|
|
34775
|
+
const { MATERIALS, crease, cutGeometry, mergeGeometries, subdivide, tumble } = I;
|
|
34776
|
+
function glassUV(c, msh, pLocal) {
|
|
34520
34777
|
const pos = msh.geometry.attributes.position;
|
|
34521
34778
|
const uv = msh.geometry.attributes.uv;
|
|
34522
34779
|
if (!uv) return [0.5, 0.5];
|
|
34523
|
-
|
|
34524
|
-
const q = pLocal.clone()
|
|
34525
|
-
|
|
34526
|
-
|
|
34527
|
-
const
|
|
34528
|
-
|
|
34529
|
-
|
|
34530
|
-
|
|
34531
|
-
|
|
34532
|
-
|
|
34533
|
-
|
|
34534
|
-
|
|
34780
|
+
c.root.updateMatrixWorld(true);
|
|
34781
|
+
const q = msh.worldToLocal(c.vehicle.localToWorld(pLocal.clone()));
|
|
34782
|
+
const idx = msh.geometry.index;
|
|
34783
|
+
const tri = new THREE.Triangle();
|
|
34784
|
+
const near = new V3();
|
|
34785
|
+
const bary = new V3();
|
|
34786
|
+
let best = Infinity;
|
|
34787
|
+
const out = [0.5, 0.5];
|
|
34788
|
+
const count2 = idx ? idx.count : pos.count;
|
|
34789
|
+
for (let f = 0; f + 2 < count2; f += 3) {
|
|
34790
|
+
const ia = idx ? idx.getX(f) : f;
|
|
34791
|
+
const ib = idx ? idx.getX(f + 1) : f + 1;
|
|
34792
|
+
const ic = idx ? idx.getX(f + 2) : f + 2;
|
|
34793
|
+
tri.a.fromBufferAttribute(pos, ia);
|
|
34794
|
+
tri.b.fromBufferAttribute(pos, ib);
|
|
34795
|
+
tri.c.fromBufferAttribute(pos, ic);
|
|
34796
|
+
tri.closestPointToPoint(q, near);
|
|
34797
|
+
const d = near.distanceToSquared(q);
|
|
34798
|
+
if (d >= best) continue;
|
|
34799
|
+
best = d;
|
|
34800
|
+
tri.getBarycoord(near, bary);
|
|
34801
|
+
out[0] = uv.getX(ia) * bary.x + uv.getX(ib) * bary.y + uv.getX(ic) * bary.z;
|
|
34802
|
+
out[1] = uv.getY(ia) * bary.x + uv.getY(ib) * bary.y + uv.getY(ic) * bary.z;
|
|
34535
34803
|
}
|
|
34536
|
-
return
|
|
34804
|
+
return out;
|
|
34537
34805
|
}
|
|
34538
34806
|
function drawWeb(x, cx, cy, s, ax, rnd) {
|
|
34539
34807
|
const n = 16 + Math.floor(rnd() * 8);
|
|
@@ -34610,19 +34878,9 @@ var GameVehiclesThree = (() => {
|
|
|
34610
34878
|
x0.fillStyle = "rgba(48,66,72,0.5)";
|
|
34611
34879
|
x0.fillRect(0, 0, 256, 256);
|
|
34612
34880
|
G2.tex = new THREE.CanvasTexture(G2.cv);
|
|
34613
|
-
msh.material =
|
|
34614
|
-
color: 16777215,
|
|
34615
|
-
map: G2.tex,
|
|
34616
|
-
emissive: 6976118,
|
|
34617
|
-
emissiveMap: G2.tex,
|
|
34618
|
-
transparent: true,
|
|
34619
|
-
roughness: 0.25,
|
|
34620
|
-
metalness: 0.1,
|
|
34621
|
-
side: DOUBLE_SIDE,
|
|
34622
|
-
depthWrite: false
|
|
34623
|
-
});
|
|
34881
|
+
msh.material = crackedGlassMaterial(THREE, G2.tex);
|
|
34624
34882
|
}
|
|
34625
|
-
const uv = glassUV(msh, p);
|
|
34883
|
+
const uv = glassUV(c, msh, p);
|
|
34626
34884
|
const x = G2.cv.getContext("2d");
|
|
34627
34885
|
drawWeb(x, uv[0] * 256, (1 - uv[1]) * 256, sc != null ? sc : 0.6 + force * 0.5, Math.max(0.4, G2.aspect || 1), c.rand);
|
|
34628
34886
|
G2.tex.needsUpdate = true;
|
|
@@ -34767,6 +35025,13 @@ var GameVehiclesThree = (() => {
|
|
|
34767
35025
|
}
|
|
34768
35026
|
const seatGeo = [];
|
|
34769
35027
|
const d = dir.clone().normalize();
|
|
35028
|
+
if (msh.parent && msh.parent !== c.vehicle) {
|
|
35029
|
+
c.root.updateMatrixWorld(true);
|
|
35030
|
+
const toVehicle = new THREE.Matrix4().copy(c.vehicle.matrixWorld).invert().multiply(msh.parent.matrixWorld);
|
|
35031
|
+
cubesAt.forEach(function(q) {
|
|
35032
|
+
q.applyMatrix4(toVehicle);
|
|
35033
|
+
});
|
|
35034
|
+
}
|
|
34770
35035
|
cubesAt.forEach(function(p, i) {
|
|
34771
35036
|
if (i % 3 === 0 && c.seatTops.length && !c.rollState && !c.flipped) {
|
|
34772
35037
|
let best = null;
|
|
@@ -34967,6 +35232,7 @@ var GameVehiclesThree = (() => {
|
|
|
34967
35232
|
polygonOffsetUnits: -2
|
|
34968
35233
|
});
|
|
34969
35234
|
const _ray = new THREE.Raycaster();
|
|
35235
|
+
_ray.layers.enableAll();
|
|
34970
35236
|
function findSurface(c, p, dir) {
|
|
34971
35237
|
c.root.updateMatrixWorld(true);
|
|
34972
35238
|
const Mw = c.vehicle.matrixWorld;
|
|
@@ -35048,6 +35314,7 @@ var GameVehiclesThree = (() => {
|
|
|
35048
35314
|
const v0 = new V3();
|
|
35049
35315
|
const w = new V3();
|
|
35050
35316
|
const sc = new V3();
|
|
35317
|
+
const local = new V3();
|
|
35051
35318
|
const cab = m.cabin && !c.flipped && !c.rollState ? m.cabin : null;
|
|
35052
35319
|
c.deform.forEach(function(msh) {
|
|
35053
35320
|
if (!msh.parent || !msh.visible) return;
|
|
@@ -35062,7 +35329,15 @@ var GameVehiclesThree = (() => {
|
|
|
35062
35329
|
irel.copy(rel).invert();
|
|
35063
35330
|
if (!g.userData.p0) g.userData.p0 = new Float32Array(pos.array);
|
|
35064
35331
|
const p0 = g.userData.p0;
|
|
35332
|
+
local.copy(p).applyMatrix4(irel);
|
|
35333
|
+
const reach = H.R / Math.max(1e-6, Math.min(sc.x, sc.y, sc.z));
|
|
35334
|
+
const reach2 = reach * reach;
|
|
35335
|
+
const arr = pos.array;
|
|
35065
35336
|
for (let i = 0; i < pos.count; i++) {
|
|
35337
|
+
const dx = arr[3 * i] - local.x;
|
|
35338
|
+
const dy = arr[3 * i + 1] - local.y;
|
|
35339
|
+
const dz = arr[3 * i + 2] - local.z;
|
|
35340
|
+
if (dx * dx + dy * dy + dz * dz >= reach2) continue;
|
|
35066
35341
|
v.fromBufferAttribute(pos, i).applyMatrix4(rel);
|
|
35067
35342
|
const a = dentField(v, H);
|
|
35068
35343
|
if (a <= 0) continue;
|
|
@@ -35078,10 +35353,15 @@ var GameVehiclesThree = (() => {
|
|
|
35078
35353
|
}
|
|
35079
35354
|
if (changed) {
|
|
35080
35355
|
pos.needsUpdate = true;
|
|
35081
|
-
if (g.userData.crease)
|
|
35356
|
+
if (g.userData.crease && c.smoothLater) c.smoothLater(msh);
|
|
35357
|
+
else if (g.userData.crease) crease(g, 42);
|
|
35082
35358
|
else g.computeVertexNormals();
|
|
35083
|
-
g.computeBoundingSphere();
|
|
35084
35359
|
g.computeBoundingBox();
|
|
35360
|
+
const sphere2 = g.boundingSphere ?? (g.boundingSphere = new THREE.Sphere());
|
|
35361
|
+
g.boundingBox.getCenter(sphere2.center);
|
|
35362
|
+
let far2 = 0;
|
|
35363
|
+
for (let i = 0; i < pos.count; i++) far2 = Math.max(far2, sphere2.center.distanceToSquared(v.fromBufferAttribute(pos, i)));
|
|
35364
|
+
sphere2.radius = Math.sqrt(far2);
|
|
35085
35365
|
}
|
|
35086
35366
|
});
|
|
35087
35367
|
const dset = new Set(c.deform);
|
|
@@ -35165,13 +35445,14 @@ var GameVehiclesThree = (() => {
|
|
|
35165
35445
|
kit.impact = impact;
|
|
35166
35446
|
kit.partEffects = {};
|
|
35167
35447
|
const _pr = new THREE.Raycaster();
|
|
35448
|
+
_pr.layers.enableAll();
|
|
35168
35449
|
function probe(c, o, d, far) {
|
|
35169
35450
|
c.root.updateMatrixWorld(true);
|
|
35170
35451
|
const Mw = c.vehicle.matrixWorld;
|
|
35171
35452
|
const inv = new THREE.Matrix4().copy(Mw).invert();
|
|
35172
35453
|
_pr.set(o.clone().applyMatrix4(Mw), d.clone().transformDirection(Mw));
|
|
35173
35454
|
_pr.far = far || 10;
|
|
35174
|
-
const hits = _pr
|
|
35455
|
+
const hits = raycastIndexed(THREE, _pr, [c.vehicle], true);
|
|
35175
35456
|
for (let i = 0; i < hits.length; i++) {
|
|
35176
35457
|
const h = hits[i];
|
|
35177
35458
|
const ob = h.object;
|
|
@@ -36525,6 +36806,7 @@ var GameVehiclesThree = (() => {
|
|
|
36525
36806
|
return hole;
|
|
36526
36807
|
}
|
|
36527
36808
|
const _zr = new THREE.Raycaster();
|
|
36809
|
+
_zr.layers.enableAll();
|
|
36528
36810
|
const PROXY_MIN_TRIANGLES = 500;
|
|
36529
36811
|
const STROKE_REACH = 0.6;
|
|
36530
36812
|
const _pv = new V3();
|
|
@@ -36759,6 +37041,7 @@ var GameVehiclesThree = (() => {
|
|
|
36759
37041
|
return out;
|
|
36760
37042
|
}
|
|
36761
37043
|
const _rt = new THREE.Raycaster();
|
|
37044
|
+
_rt.layers.enableAll();
|
|
36762
37045
|
function scratchPath(c, s, len, ang, cands, B) {
|
|
36763
37046
|
const n = s.n.clone().normalize();
|
|
36764
37047
|
const t = Math.abs(n.y) < 0.9 ? new V3().crossVectors(new V3(0, 1, 0), n) : new V3().crossVectors(new V3(1, 0, 0), n);
|
|
@@ -40018,6 +40301,8 @@ var GameVehiclesThree = (() => {
|
|
|
40018
40301
|
V3: THREE.Vector3,
|
|
40019
40302
|
PI: Math.PI,
|
|
40020
40303
|
document: doc,
|
|
40304
|
+
particleMaterials: opts.particleMaterials,
|
|
40305
|
+
effects: opts.effects,
|
|
40021
40306
|
strings,
|
|
40022
40307
|
t,
|
|
40023
40308
|
matchers: createMatchers(strings),
|
|
@@ -40273,7 +40558,9 @@ var GameVehiclesThree = (() => {
|
|
|
40273
40558
|
assignDeep(strings, resolveStrings(opts.locale));
|
|
40274
40559
|
return kit;
|
|
40275
40560
|
};
|
|
40276
|
-
const { THREE: _three, lod: _lod, locale: _locale, document: _document, plugins, ...config } = opts;
|
|
40561
|
+
const { THREE: _three, lod: _lod, locale: _locale, document: _document, particleMaterials: _particleMaterials, effects: _effects, plugins, ...config } = opts;
|
|
40562
|
+
void _particleMaterials;
|
|
40563
|
+
void _effects;
|
|
40277
40564
|
void _three;
|
|
40278
40565
|
void _lod;
|
|
40279
40566
|
void _locale;
|
|
@@ -40367,6 +40654,14 @@ var GameVehiclesThree = (() => {
|
|
|
40367
40654
|
center: [b.center[0], b.center[1] - b.size[1] / 2 + Math.min(0.14, b.size[1]) / 2 + 0.04, b.center[2]],
|
|
40368
40655
|
size: [b.size[0] * 0.5, Math.min(0.14, b.size[1]), b.size[2] * 0.95]
|
|
40369
40656
|
});
|
|
40657
|
+
function paneBox(c, pane, inverse) {
|
|
40658
|
+
pane.geometry.computeBoundingBox();
|
|
40659
|
+
const box2 = pane.geometry.boundingBox.clone().applyMatrix4(pane.matrixWorld);
|
|
40660
|
+
box2.applyMatrix4(inverse);
|
|
40661
|
+
const center = [(box2.min.x + box2.max.x) / 2, (box2.min.y + box2.max.y) / 2, (box2.min.z + box2.max.z) / 2];
|
|
40662
|
+
const size = [box2.max.x - box2.min.x, box2.max.y - box2.min.y, box2.max.z - box2.min.z];
|
|
40663
|
+
return { center, size };
|
|
40664
|
+
}
|
|
40370
40665
|
function buildVehicleModel(kit, c, options = {}) {
|
|
40371
40666
|
const kind = kindOf(c);
|
|
40372
40667
|
const m = c.meta;
|
|
@@ -40507,6 +40802,16 @@ var GameVehiclesThree = (() => {
|
|
|
40507
40802
|
tags: [role, ...tags]
|
|
40508
40803
|
});
|
|
40509
40804
|
}
|
|
40805
|
+
const claimed = new Set(zones.filter((z) => roleOfZone(z) === "glass").flatMap((z) => z.glass ?? []));
|
|
40806
|
+
c.root.updateMatrixWorld(true);
|
|
40807
|
+
const inverse = c.vehicle.matrixWorld.clone().invert();
|
|
40808
|
+
for (const pane of c.glass ?? []) {
|
|
40809
|
+
if (claimed.has(pane)) continue;
|
|
40810
|
+
const G2 = pane.userData.glass;
|
|
40811
|
+
const bb = paneBox(c, pane, inverse);
|
|
40812
|
+
const laminated = G2?.type === "laminated" || m.bullet;
|
|
40813
|
+
add2({ id: `pane_${G2?.key ?? "glass"}`, role: "glass", name: String(G2?.label ?? G2?.key ?? "glass"), material: "glass", box: bb, mass: 10 * areaOf(bb.size), hp: laminated ? 4e3 : 450, panes: [pane], visual: false, tags: ["glass"] });
|
|
40814
|
+
}
|
|
40510
40815
|
if (!hubZone) {
|
|
40511
40816
|
const h = Math.max(0.15, belt - clearance);
|
|
40512
40817
|
add2({
|
|
@@ -40840,6 +41145,76 @@ var GameVehiclesThree = (() => {
|
|
|
40840
41145
|
void has;
|
|
40841
41146
|
return { parts, joints, hub: hubId, hitch };
|
|
40842
41147
|
}
|
|
41148
|
+
var HOLE_DECAL_SCALE = 2.4;
|
|
41149
|
+
var DOOR_DEPTH = 0.07;
|
|
41150
|
+
var DOOR_EDGE_PIECES = 16;
|
|
41151
|
+
var DOOR_CARD_COLOR = "#3b3e42";
|
|
41152
|
+
var DOOR_LINER_COLOR = "#5a5e64";
|
|
41153
|
+
var DOOR_LINER_DARK = 0.15;
|
|
41154
|
+
var DOOR_STRIP_THIN = 0.05;
|
|
41155
|
+
var DOOR_STRIP_NEAR = 0.04;
|
|
41156
|
+
var DOOR_STRIP_OVER = 0.3;
|
|
41157
|
+
var DOOR_TOP_OVER_PANE = 0.03;
|
|
41158
|
+
var DOOR_STRIP_SUB = 0.02;
|
|
41159
|
+
var HOLE_TEXTURE_SIZE = 64;
|
|
41160
|
+
var DOOR_HANDLE_INSET = 0.12;
|
|
41161
|
+
var DOOR_HANDLE_MIN = 0.07;
|
|
41162
|
+
var DOOR_HANDLE_MAX = 0.24;
|
|
41163
|
+
var DOOR_HANDLE_THIN = 0.07;
|
|
41164
|
+
var DOOR_HANDLE_OUTSIDE = 0.1;
|
|
41165
|
+
var PANE_SEAT_OUT = 0.05;
|
|
41166
|
+
var PANE_SEAT_IN = -0.05;
|
|
41167
|
+
var PANE_SEAT_REACH = 0.14;
|
|
41168
|
+
var PANE_SEAT_SAMPLES = 24;
|
|
41169
|
+
var PANE_SEAT_LIFT = 4e-3;
|
|
41170
|
+
var PANE_FRAME_NEAR = 0.07;
|
|
41171
|
+
var DRAWN_MIRROR_SIZE = 0.3;
|
|
41172
|
+
var DRAWN_MIRROR_REACH = 0.4;
|
|
41173
|
+
var DRAWN_MIRROR_MOUNT = 0.2;
|
|
41174
|
+
var MIRROR_GLASS_FIT = 0.76;
|
|
41175
|
+
var MIRROR_GLASS_THIN = 0.04;
|
|
41176
|
+
var MIRROR_GLASS_MIN = 0.05;
|
|
41177
|
+
var MIRROR_GLASS_COLOR = "#59636a";
|
|
41178
|
+
var HOLE_RIM = { steel: "#b7bcc0", aluminium: "#d3d6d8", plastic: "#d9d6cc", rubber: "#141414", glass: "#eef3f5" };
|
|
41179
|
+
var holeMaterials = /* @__PURE__ */ new WeakMap();
|
|
41180
|
+
var holeDisc = null;
|
|
41181
|
+
function holeDiscGeometry(THREE) {
|
|
41182
|
+
holeDisc = holeDisc ?? new THREE.CircleGeometry(1, 12);
|
|
41183
|
+
return holeDisc;
|
|
41184
|
+
}
|
|
41185
|
+
function holeMaterial(kit, material) {
|
|
41186
|
+
const key = kit;
|
|
41187
|
+
const cache2 = holeMaterials.get(key) ?? /* @__PURE__ */ new Map();
|
|
41188
|
+
holeMaterials.set(key, cache2);
|
|
41189
|
+
const known = cache2.get(material);
|
|
41190
|
+
if (known) return known;
|
|
41191
|
+
const I = kit._;
|
|
41192
|
+
const THREE = kit.THREE;
|
|
41193
|
+
const canvas = kit.document?.createElement?.("canvas");
|
|
41194
|
+
const x = canvas?.getContext?.("2d");
|
|
41195
|
+
let made = I.MATERIALS.dark;
|
|
41196
|
+
if (x) {
|
|
41197
|
+
canvas.width = canvas.height = HOLE_TEXTURE_SIZE;
|
|
41198
|
+
const mid = HOLE_TEXTURE_SIZE / 2;
|
|
41199
|
+
x.fillStyle = HOLE_RIM[material] ?? HOLE_RIM.steel;
|
|
41200
|
+
x.beginPath();
|
|
41201
|
+
for (let i = 0; i < 18; i++) {
|
|
41202
|
+
const a = i / 18 * Math.PI * 2;
|
|
41203
|
+
const r = mid * (i % 2 ? 0.98 : 0.76);
|
|
41204
|
+
x.lineTo(mid + Math.cos(a) * r, mid + Math.sin(a) * r);
|
|
41205
|
+
}
|
|
41206
|
+
x.closePath();
|
|
41207
|
+
x.fill();
|
|
41208
|
+
x.fillStyle = "#050505";
|
|
41209
|
+
x.beginPath();
|
|
41210
|
+
x.arc(mid, mid, mid * 0.42, 0, Math.PI * 2);
|
|
41211
|
+
x.fill();
|
|
41212
|
+
const map = new THREE.CanvasTexture(canvas);
|
|
41213
|
+
made = new THREE.MeshStandardMaterial({ map, transparent: true, depthWrite: false, polygonOffset: true, polygonOffsetFactor: -2, roughness: 0.55, metalness: material === "steel" || material === "aluminium" ? 0.6 : 0 });
|
|
41214
|
+
}
|
|
41215
|
+
cache2.set(material, made);
|
|
41216
|
+
return made;
|
|
41217
|
+
}
|
|
40843
41218
|
var VehicleVisuals = class {
|
|
40844
41219
|
constructor(kit, c, model) {
|
|
40845
41220
|
__publicField(this, "kit");
|
|
@@ -40853,11 +41228,17 @@ var GameVehiclesThree = (() => {
|
|
|
40853
41228
|
__publicField(this, "gone", /* @__PURE__ */ new Set());
|
|
40854
41229
|
__publicField(this, "syncPlates", /* @__PURE__ */ new Map());
|
|
40855
41230
|
__publicField(this, "skins", /* @__PURE__ */ new Map());
|
|
41231
|
+
__publicField(this, "doorTops", /* @__PURE__ */ new Map());
|
|
40856
41232
|
__publicField(this, "lightsOn", true);
|
|
40857
41233
|
__publicField(this, "warming");
|
|
40858
41234
|
__publicField(this, "tornThisFrame", false);
|
|
41235
|
+
__publicField(this, "queued", false);
|
|
41236
|
+
__publicField(this, "holdArmed", false);
|
|
41237
|
+
__publicField(this, "holdFrame", -1);
|
|
40859
41238
|
__publicField(this, "smoothing", /* @__PURE__ */ new Map());
|
|
40860
41239
|
__publicField(this, "hood");
|
|
41240
|
+
;
|
|
41241
|
+
c.smoothLater = (mesh2) => this.smoothLater(mesh2);
|
|
40861
41242
|
this.kit = kit;
|
|
40862
41243
|
this.c = c;
|
|
40863
41244
|
this.model = model;
|
|
@@ -40866,6 +41247,8 @@ var GameVehiclesThree = (() => {
|
|
|
40866
41247
|
for (const p of model.parts) this.byId.set(p.id, p);
|
|
40867
41248
|
c.root.updateMatrixWorld(true);
|
|
40868
41249
|
this.hood = this.nameHood();
|
|
41250
|
+
this.seatPanes();
|
|
41251
|
+
this.seatDoorHandles();
|
|
40869
41252
|
this.warming = c.deform.filter((msh) => msh.geometry && msh.geometry.attributes.position && msh.geometry.attributes.position.count >= 1500);
|
|
40870
41253
|
if (!this.warming.length) this.warming = null;
|
|
40871
41254
|
for (const p of model.parts) {
|
|
@@ -40886,6 +41269,7 @@ var GameVehiclesThree = (() => {
|
|
|
40886
41269
|
const id = z ? z.id : this.model.parts.find((p) => p.role === "hood")?.id;
|
|
40887
41270
|
if (!id) return null;
|
|
40888
41271
|
c.hood.piv.name = id;
|
|
41272
|
+
c.hood.piv.userData.plateOf = id;
|
|
40889
41273
|
return { id, open: c.hood.open, sign: c.hood.sign || 1 };
|
|
40890
41274
|
}
|
|
40891
41275
|
mirrorObjects(p) {
|
|
@@ -40973,6 +41357,7 @@ var GameVehiclesThree = (() => {
|
|
|
40973
41357
|
recess.userData.noFollow = true;
|
|
40974
41358
|
const piv = new THREE.Group();
|
|
40975
41359
|
piv.name = p.id;
|
|
41360
|
+
piv.userData.plateOf = p.id;
|
|
40976
41361
|
piv.position.set(hx, cy, sk + s * 0.016);
|
|
40977
41362
|
piv.userData.rigid = true;
|
|
40978
41363
|
this.c.vehicle.add(piv);
|
|
@@ -40989,6 +41374,7 @@ var GameVehiclesThree = (() => {
|
|
|
40989
41374
|
recess.userData.noFollow = true;
|
|
40990
41375
|
const piv = new THREE.Group();
|
|
40991
41376
|
piv.name = p.id;
|
|
41377
|
+
piv.userData.plateOf = p.id;
|
|
40992
41378
|
piv.position.set(sk - 0.016, B.y1 - 0.05, 0);
|
|
40993
41379
|
piv.userData.rigid = true;
|
|
40994
41380
|
this.c.vehicle.add(piv);
|
|
@@ -41052,10 +41438,19 @@ var GameVehiclesThree = (() => {
|
|
|
41052
41438
|
try {
|
|
41053
41439
|
if (p.role === "door") {
|
|
41054
41440
|
const dirty = /* @__PURE__ */ new Set();
|
|
41055
|
-
const
|
|
41056
|
-
const
|
|
41441
|
+
const glassBox = new this.THREE.Box3();
|
|
41442
|
+
for (const g of I.windowsOver(this.c, z, inv)) glassBox.union(I.localBox(this.c, g, inv));
|
|
41443
|
+
const top = glassBox.isEmpty() ? B.y1 - 0.02 : Math.max(B.y1 - 0.02, glassBox.min.y + DOOR_TOP_OVER_PANE);
|
|
41444
|
+
this.doorTops.set(id, top);
|
|
41445
|
+
const rect = [B.x0 + 0.03, B.x1 - 0.03, B.y0 + Math.min(0.08, (B.y1 - B.y0) * 0.1), top];
|
|
41446
|
+
const pcs = I.cutPanel(this.c, z, rect, true, dirty, { anyN: true }).map((x) => x.mesh).filter((m) => !!m);
|
|
41057
41447
|
this.mend(dirty);
|
|
41058
|
-
if (pcs.length)
|
|
41448
|
+
if (pcs.length) {
|
|
41449
|
+
const panes = I.windowsOver(this.c, z, inv);
|
|
41450
|
+
const seals = panes.map((g) => I.paneSeals.get(g)).filter((s) => !!s);
|
|
41451
|
+
const mirrors = this.mirrorsOn(z);
|
|
41452
|
+
objs = [...pcs, ...this.doorCards(pcs, z), ...I.followersIn(this.c, z, inv), ...panes, ...seals, ...mirrors];
|
|
41453
|
+
}
|
|
41059
41454
|
} else {
|
|
41060
41455
|
const pcs = this.cutZone(z);
|
|
41061
41456
|
if (pcs.length) objs = [...pcs, ...I.followersIn(this.c, z, inv)];
|
|
@@ -41073,10 +41468,124 @@ var GameVehiclesThree = (() => {
|
|
|
41073
41468
|
const di = deform.indexOf(o);
|
|
41074
41469
|
if (di >= 0) deform.splice(di, 1);
|
|
41075
41470
|
}
|
|
41471
|
+
if (p.role === "door" && objs.length > 0) {
|
|
41472
|
+
this.doorEdges(piv, z, this.doorTops.get(id) ?? B.y1 - 0.02);
|
|
41473
|
+
this.liftDoorTrim(objs, z);
|
|
41474
|
+
this.cutStripsAcross(piv, z, inv);
|
|
41475
|
+
}
|
|
41076
41476
|
piv.quaternion.copy(q);
|
|
41077
41477
|
this.c.root.updateMatrixWorld(true);
|
|
41078
41478
|
return objs.length > 0;
|
|
41079
41479
|
}
|
|
41480
|
+
/** A door has edges: a band that follows the skin all round closes it to its card and hides where the cut followed the triangles of the shell; the same band, in the same paint as on a real car, lines the opening. */
|
|
41481
|
+
doorEdges(piv, z, y1) {
|
|
41482
|
+
const THREE = this.THREE;
|
|
41483
|
+
const B = z.box;
|
|
41484
|
+
const side2 = z.side < 0 ? -1 : 1;
|
|
41485
|
+
const flat = piv.position.z - side2 * 0.016;
|
|
41486
|
+
const x0 = B.x0 + 0.03;
|
|
41487
|
+
const x1 = B.x1 - 0.03;
|
|
41488
|
+
const y0 = B.y0 + Math.min(0.08, (B.y1 - B.y0) * 0.1);
|
|
41489
|
+
const loop = [];
|
|
41490
|
+
const run = (ax, ay, bx, by) => {
|
|
41491
|
+
for (let i = 0; i < DOOR_EDGE_PIECES; i++) loop.push([ax + (bx - ax) * i / DOOR_EDGE_PIECES, ay + (by - ay) * i / DOOR_EDGE_PIECES]);
|
|
41492
|
+
};
|
|
41493
|
+
run(x0, y0, x1, y0);
|
|
41494
|
+
run(x1, y0, x1, y1);
|
|
41495
|
+
run(x1, y1, x0, y1);
|
|
41496
|
+
run(x0, y1, x0, y0);
|
|
41497
|
+
const heights = loop.map(([x, y]) => this.surface("z", side2, B, [[x, y]]) ?? flat);
|
|
41498
|
+
const band = (lift) => {
|
|
41499
|
+
const position = [];
|
|
41500
|
+
const index = [];
|
|
41501
|
+
loop.forEach(([x, y], i) => {
|
|
41502
|
+
position.push(x, y, heights[i] + side2 * lift, x, y, heights[i] + side2 * (lift - DOOR_DEPTH));
|
|
41503
|
+
const a = i * 2;
|
|
41504
|
+
const b = (i + 1) % loop.length * 2;
|
|
41505
|
+
index.push(a, a + 1, b, b, a + 1, b + 1);
|
|
41506
|
+
});
|
|
41507
|
+
const g = new THREE.BufferGeometry();
|
|
41508
|
+
g.setAttribute("position", new THREE.Float32BufferAttribute(position, 3));
|
|
41509
|
+
g.setIndex(index);
|
|
41510
|
+
g.computeVertexNormals();
|
|
41511
|
+
return g;
|
|
41512
|
+
};
|
|
41513
|
+
const paint = this.paint().clone();
|
|
41514
|
+
paint.side = THREE.DoubleSide;
|
|
41515
|
+
const edges = new THREE.Mesh(band(2e-3), paint);
|
|
41516
|
+
const lining = new THREE.Mesh(band(2e-3), paint);
|
|
41517
|
+
for (const m of [edges, lining]) {
|
|
41518
|
+
m.userData.noFollow = true;
|
|
41519
|
+
m.castShadow = false;
|
|
41520
|
+
this.c.vehicle.add(m);
|
|
41521
|
+
}
|
|
41522
|
+
piv.attach(edges);
|
|
41523
|
+
}
|
|
41524
|
+
/** A front door carries the mirror drawn at its corner. */
|
|
41525
|
+
mirrorsOn(z) {
|
|
41526
|
+
if (!z.mirror) return [];
|
|
41527
|
+
const own = (z.mirrors ?? []).filter((o) => o.parent);
|
|
41528
|
+
if (own.length) return own;
|
|
41529
|
+
const part = this.model.parts.find((q) => q.role === "mirror" && Math.sign(q.box.center[2]) === Math.sign(z.side));
|
|
41530
|
+
return part ? (this.extra.get(part.id) ?? []).filter((o) => o.parent) : [];
|
|
41531
|
+
}
|
|
41532
|
+
/** The panel drawn inside the door is lit like the rest of a cabin, not a black slab from end to end. */
|
|
41533
|
+
liftDoorTrim(objs, z) {
|
|
41534
|
+
const card = this.I.makeMaterial(DOOR_LINER_COLOR, { roughness: 0.85 });
|
|
41535
|
+
const inv = this.I.worldInverseOf(this.c);
|
|
41536
|
+
for (const o of objs) {
|
|
41537
|
+
if (!o.isMesh || o.userData.glass) continue;
|
|
41538
|
+
const box2 = this.I.localBox(this.c, o, inv);
|
|
41539
|
+
const size = box2.getSize(new this.THREE.Vector3());
|
|
41540
|
+
if (size.x > (z.box.x1 - z.box.x0) * 0.4 && size.y > (z.box.y1 - z.box.y0) * 0.3 && size.z < DOOR_DEPTH * 1.5 && o.material?.color?.getHSL({ h: 0, s: 0, l: 0 }).l < DOOR_LINER_DARK) o.material = card;
|
|
41541
|
+
}
|
|
41542
|
+
}
|
|
41543
|
+
/** A long strip drawn along the side of the car (the chrome of the belt): the part over the door goes with the door, and nothing stays across the opening. */
|
|
41544
|
+
cutStripsAcross(piv, z, inv) {
|
|
41545
|
+
const THREE = this.THREE;
|
|
41546
|
+
const B = z.box;
|
|
41547
|
+
const x0 = B.x0 + 0.03;
|
|
41548
|
+
const x1 = B.x1 - 0.03;
|
|
41549
|
+
const y0 = B.y0 - DOOR_STRIP_NEAR;
|
|
41550
|
+
const y1 = B.y1 + DOOR_STRIP_NEAR;
|
|
41551
|
+
const deform = this.c.deform ?? [];
|
|
41552
|
+
for (const o of [...this.c.vehicle.children]) {
|
|
41553
|
+
if (!o.isMesh || o === piv || deform.includes(o) || o.userData.glass || o.userData.decal || !o.visible) continue;
|
|
41554
|
+
const box2 = this.I.localBox(this.c, o, inv);
|
|
41555
|
+
const size = box2.getSize(new THREE.Vector3());
|
|
41556
|
+
const mid = box2.getCenter(new THREE.Vector3());
|
|
41557
|
+
if (Math.sign(mid.z) !== Math.sign(z.side) || size.z > DOOR_STRIP_THIN || size.y > DOOR_STRIP_THIN || Math.min(box2.max.x, x1) - Math.max(box2.min.x, x0) < (x1 - x0) * DOOR_STRIP_OVER || mid.y < y0 || mid.y > y1) continue;
|
|
41558
|
+
const toVehicle = new THREE.Matrix4().multiplyMatrices(inv, o.matrixWorld);
|
|
41559
|
+
const v = new THREE.Vector3();
|
|
41560
|
+
const sdf = (x, y, zz) => {
|
|
41561
|
+
v.set(x, y, zz).applyMatrix4(toVehicle);
|
|
41562
|
+
return Math.max(x0 - v.x, v.x - x1);
|
|
41563
|
+
};
|
|
41564
|
+
this.kit.cutMesh(o, [{ sdf }], 42, { sub: DOOR_STRIP_SUB });
|
|
41565
|
+
const from = Math.max(box2.min.x, x0);
|
|
41566
|
+
const to = Math.min(box2.max.x, x1);
|
|
41567
|
+
const piece = this.box(to - from, size.y, size.z, o.material, (from + to) / 2, mid.y, mid.z);
|
|
41568
|
+
piece.userData.noFollow = true;
|
|
41569
|
+
piv.attach(piece);
|
|
41570
|
+
}
|
|
41571
|
+
}
|
|
41572
|
+
/** The inside of a door: its skin brought in by the depth of the door, in the trim's dark plastic, so the open door is a door and not one sheet of paint. */
|
|
41573
|
+
doorCards(skins, z) {
|
|
41574
|
+
const cardMaterial = this.I.makeMaterial(DOOR_CARD_COLOR, { roughness: 0.8 });
|
|
41575
|
+
return skins.map((skin) => {
|
|
41576
|
+
const card = new this.THREE.Mesh(skin.geometry, cardMaterial);
|
|
41577
|
+
card.position.copy(skin.position);
|
|
41578
|
+
card.quaternion.copy(skin.quaternion);
|
|
41579
|
+
card.scale.copy(skin.scale);
|
|
41580
|
+
const side2 = z.side < 0 ? -1 : 1;
|
|
41581
|
+
const inward = -side2 * DOOR_DEPTH;
|
|
41582
|
+
card.position.z += inward;
|
|
41583
|
+
card.userData.noFollow = true;
|
|
41584
|
+
card.castShadow = false;
|
|
41585
|
+
this.c.vehicle.add(card);
|
|
41586
|
+
return card;
|
|
41587
|
+
});
|
|
41588
|
+
}
|
|
41080
41589
|
mend(dirty) {
|
|
41081
41590
|
dirty.forEach((msh) => {
|
|
41082
41591
|
const g = msh.geometry;
|
|
@@ -41086,7 +41595,191 @@ var GameVehiclesThree = (() => {
|
|
|
41086
41595
|
g.computeBoundingBox();
|
|
41087
41596
|
});
|
|
41088
41597
|
}
|
|
41598
|
+
/**
|
|
41599
|
+
* A windshield or rear window is drawn as a flat quad, and the body under its edge is curved: the pane and its frame stand off the shell or rise past the roof. Each one
|
|
41600
|
+
* comes to the shell along its own normal, by how far the shell is just outside each of its vertices.
|
|
41601
|
+
*/
|
|
41602
|
+
seatPanes() {
|
|
41603
|
+
const THREE = this.THREE;
|
|
41604
|
+
const c = this.c;
|
|
41605
|
+
c.root.updateMatrixWorld(true);
|
|
41606
|
+
const shell = c.deform.filter((o) => o.isMesh && !o.userData.glass && c.paints?.has(o.material));
|
|
41607
|
+
if (!shell.length) return;
|
|
41608
|
+
const ray = new THREE.Raycaster();
|
|
41609
|
+
ray.layers.enableAll();
|
|
41610
|
+
for (const pane of c.glass) {
|
|
41611
|
+
if (pane.userData.glass?.outline) continue;
|
|
41612
|
+
const seat = this.paneSeat(pane, shell, ray);
|
|
41613
|
+
if (!seat) continue;
|
|
41614
|
+
const near = c.vehicle.children.filter((o) => o.isMesh && o !== pane && !o.userData.glass && !shell.includes(o) && this.onPane(o, pane, seat));
|
|
41615
|
+
for (const m of [pane, ...near]) this.movePane(m, seat);
|
|
41616
|
+
const past = this.shellPast(pane, shell, ray, seat.normal);
|
|
41617
|
+
if (past > 0) for (const m of [pane, ...near]) this.movePane(m, { normal: seat.normal, samples: [{ at: seat.samples[0].at, by: past }] });
|
|
41618
|
+
}
|
|
41619
|
+
}
|
|
41620
|
+
/** The outward normal of a pane and how far the shell is at each sampled point (world). */
|
|
41621
|
+
paneSeat(pane, shell, ray) {
|
|
41622
|
+
const THREE = this.THREE;
|
|
41623
|
+
const pos = pane.geometry.attributes.position;
|
|
41624
|
+
const box2 = new THREE.Box3().setFromObject(pane);
|
|
41625
|
+
const centre = box2.getCenter(new THREE.Vector3());
|
|
41626
|
+
const vehicleCentre = new THREE.Box3().setFromObject(this.c.root).getCenter(new THREE.Vector3());
|
|
41627
|
+
const tri = new THREE.Triangle();
|
|
41628
|
+
const normal = new THREE.Vector3();
|
|
41629
|
+
let largest = 0;
|
|
41630
|
+
const idx = pane.geometry.index;
|
|
41631
|
+
const count2 = idx ? idx.count : pos.count;
|
|
41632
|
+
for (let f = 0; f + 2 < count2; f += 3) {
|
|
41633
|
+
tri.a.fromBufferAttribute(pos, idx ? idx.getX(f) : f);
|
|
41634
|
+
tri.b.fromBufferAttribute(pos, idx ? idx.getX(f + 1) : f + 1);
|
|
41635
|
+
tri.c.fromBufferAttribute(pos, idx ? idx.getX(f + 2) : f + 2);
|
|
41636
|
+
if (tri.getArea() > largest) {
|
|
41637
|
+
largest = tri.getArea();
|
|
41638
|
+
tri.getNormal(normal);
|
|
41639
|
+
}
|
|
41640
|
+
}
|
|
41641
|
+
normal.transformDirection(pane.matrixWorld);
|
|
41642
|
+
if (normal.dot(centre.clone().sub(vehicleCentre)) < 0) normal.negate();
|
|
41643
|
+
const samples = [];
|
|
41644
|
+
const seen = /* @__PURE__ */ new Set();
|
|
41645
|
+
const v = new THREE.Vector3();
|
|
41646
|
+
const step = Math.max(1, Math.floor(pos.count / PANE_SEAT_SAMPLES));
|
|
41647
|
+
for (let i = 0; i < pos.count; i += step) {
|
|
41648
|
+
v.fromBufferAttribute(pos, i).applyMatrix4(pane.matrixWorld);
|
|
41649
|
+
const key = `${Math.round(v.x * 100)},${Math.round(v.y * 100)},${Math.round(v.z * 100)}`;
|
|
41650
|
+
if (seen.has(key)) continue;
|
|
41651
|
+
seen.add(key);
|
|
41652
|
+
const away = v.clone().sub(centre);
|
|
41653
|
+
away.addScaledVector(normal, -away.dot(normal)).normalize();
|
|
41654
|
+
let by = -Infinity;
|
|
41655
|
+
for (const off of [PANE_SEAT_OUT, PANE_SEAT_IN, PANE_SEAT_IN * 3]) {
|
|
41656
|
+
const at = v.clone().addScaledVector(away, off);
|
|
41657
|
+
ray.set(at.addScaledVector(normal, PANE_SEAT_REACH), normal.clone().negate());
|
|
41658
|
+
ray.far = PANE_SEAT_REACH * 2;
|
|
41659
|
+
const hit = raycastIndexed(THREE, ray, shell)[0];
|
|
41660
|
+
if (hit) by = Math.max(by, PANE_SEAT_REACH - hit.distance);
|
|
41661
|
+
}
|
|
41662
|
+
if (by > -Infinity) samples.push({ at: v.clone(), by });
|
|
41663
|
+
}
|
|
41664
|
+
return samples.length >= 3 ? { normal, samples } : null;
|
|
41665
|
+
}
|
|
41666
|
+
/** How far the shell still stands past a seated pane, over its triangles. */
|
|
41667
|
+
shellPast(pane, shell, ray, normal) {
|
|
41668
|
+
const THREE = this.THREE;
|
|
41669
|
+
const pos = pane.geometry.attributes.position;
|
|
41670
|
+
const idx = pane.geometry.index;
|
|
41671
|
+
const count2 = idx ? idx.count : pos.count;
|
|
41672
|
+
const tri = new THREE.Triangle();
|
|
41673
|
+
const step = Math.max(1, Math.floor(count2 / 3 / PANE_SEAT_SAMPLES)) * 3;
|
|
41674
|
+
let past = 0;
|
|
41675
|
+
for (let f = 0; f + 2 < count2; f += step) {
|
|
41676
|
+
tri.a.fromBufferAttribute(pos, idx ? idx.getX(f) : f);
|
|
41677
|
+
tri.b.fromBufferAttribute(pos, idx ? idx.getX(f + 1) : f + 1);
|
|
41678
|
+
tri.c.fromBufferAttribute(pos, idx ? idx.getX(f + 2) : f + 2);
|
|
41679
|
+
const mid = tri.getMidpoint(new THREE.Vector3()).applyMatrix4(pane.matrixWorld);
|
|
41680
|
+
ray.set(mid.addScaledVector(normal, PANE_SEAT_REACH), normal.clone().negate());
|
|
41681
|
+
ray.far = PANE_SEAT_REACH;
|
|
41682
|
+
const hit = raycastIndexed(THREE, ray, shell)[0];
|
|
41683
|
+
if (hit) past = Math.max(past, PANE_SEAT_REACH - hit.distance + PANE_SEAT_LIFT);
|
|
41684
|
+
}
|
|
41685
|
+
return past;
|
|
41686
|
+
}
|
|
41687
|
+
/** A frame or a seal drawn on the pane: small, and close to its plane. */
|
|
41688
|
+
onPane(o, pane, seat) {
|
|
41689
|
+
const THREE = this.THREE;
|
|
41690
|
+
const box2 = new THREE.Box3().setFromObject(o);
|
|
41691
|
+
if (box2.isEmpty() || !new THREE.Box3().setFromObject(pane).expandByScalar(PANE_FRAME_NEAR).containsBox(box2)) return false;
|
|
41692
|
+
const at = box2.getCenter(new THREE.Vector3());
|
|
41693
|
+
return Math.abs(at.clone().sub(seat.samples[0].at).dot(seat.normal)) < PANE_SEAT_REACH;
|
|
41694
|
+
}
|
|
41695
|
+
movePane(mesh2, seat) {
|
|
41696
|
+
const THREE = this.THREE;
|
|
41697
|
+
const g = mesh2.geometry.clone();
|
|
41698
|
+
const pos = g.attributes.position;
|
|
41699
|
+
const inverse = mesh2.matrixWorld.clone().invert();
|
|
41700
|
+
const v = new THREE.Vector3();
|
|
41701
|
+
for (let i = 0; i < pos.count; i++) {
|
|
41702
|
+
v.fromBufferAttribute(pos, i).applyMatrix4(mesh2.matrixWorld);
|
|
41703
|
+
let weight = 0;
|
|
41704
|
+
let by = 0;
|
|
41705
|
+
for (const s of seat.samples) {
|
|
41706
|
+
const w = 1 / (s.at.distanceToSquared(v) + 1e-4);
|
|
41707
|
+
weight += w;
|
|
41708
|
+
by += s.by * w;
|
|
41709
|
+
}
|
|
41710
|
+
v.addScaledVector(seat.normal, by / weight + PANE_SEAT_LIFT).applyMatrix4(inverse);
|
|
41711
|
+
pos.setXYZ(i, v.x, v.y, v.z);
|
|
41712
|
+
}
|
|
41713
|
+
pos.needsUpdate = true;
|
|
41714
|
+
g.computeBoundingBox();
|
|
41715
|
+
g.computeBoundingSphere();
|
|
41716
|
+
mesh2.geometry = g;
|
|
41717
|
+
}
|
|
41718
|
+
/** A handle is at the free edge of its door, the end away from the hinge. */
|
|
41719
|
+
seatDoorHandles() {
|
|
41720
|
+
const THREE = this.THREE;
|
|
41721
|
+
const c = this.c;
|
|
41722
|
+
const inv = this.I.worldInverseOf(c);
|
|
41723
|
+
for (const p of this.model.parts) {
|
|
41724
|
+
if (p.role !== "door") continue;
|
|
41725
|
+
const z = this.zone(p);
|
|
41726
|
+
if (!z) continue;
|
|
41727
|
+
const B = z.box;
|
|
41728
|
+
const free = z.hinge === "rear" ? B.x1 - DOOR_HANDLE_INSET : B.x0 + DOOR_HANDLE_INSET;
|
|
41729
|
+
for (const o of c.vehicle.children) {
|
|
41730
|
+
if (!o.isMesh || o.material !== this.I.MATERIALS.chrome || o.userData.glass) continue;
|
|
41731
|
+
const box2 = this.I.localBox(c, o, inv);
|
|
41732
|
+
const size = box2.getSize(new THREE.Vector3());
|
|
41733
|
+
const at = box2.getCenter(new THREE.Vector3());
|
|
41734
|
+
const isHandle = size.x > DOOR_HANDLE_MIN && size.x < DOOR_HANDLE_MAX && size.y < DOOR_HANDLE_THIN && size.z < DOOR_HANDLE_THIN;
|
|
41735
|
+
if (!isHandle || Math.sign(at.z) !== Math.sign(z.side) || at.x < B.x0 || at.x > B.x1 || at.y < B.y0 || at.y > B.y1) continue;
|
|
41736
|
+
const here = this.surface("z", z.side < 0 ? -1 : 1, B, [[at.x, at.y]]);
|
|
41737
|
+
if (here != null && Math.abs(here - at.z) > DOOR_HANDLE_OUTSIDE) continue;
|
|
41738
|
+
const skin = this.surface("z", z.side < 0 ? -1 : 1, B, [[free, at.y]]);
|
|
41739
|
+
o.position.x += free - at.x;
|
|
41740
|
+
if (skin != null) o.position.z += skin + (z.side < 0 ? -1 : 1) * (size.z / 2) - at.z;
|
|
41741
|
+
}
|
|
41742
|
+
}
|
|
41743
|
+
c.root.updateMatrixWorld(true);
|
|
41744
|
+
}
|
|
41745
|
+
/** The glass of a drawn mirror sits inside its rounded housing, without corners standing past it. */
|
|
41746
|
+
seatMirrorGlass(glass) {
|
|
41747
|
+
const g = glass.geometry.clone();
|
|
41748
|
+
g.computeBoundingBox();
|
|
41749
|
+
const mid = g.boundingBox.getCenter(new this.THREE.Vector3());
|
|
41750
|
+
g.translate(-mid.x, -mid.y, -mid.z);
|
|
41751
|
+
g.scale(MIRROR_GLASS_FIT, MIRROR_GLASS_FIT, MIRROR_GLASS_FIT);
|
|
41752
|
+
g.translate(mid.x, mid.y, mid.z);
|
|
41753
|
+
glass.geometry = g;
|
|
41754
|
+
glass.material = this.I.makeMaterial(MIRROR_GLASS_COLOR, { metalness: 0.95, roughness: 0.12 });
|
|
41755
|
+
}
|
|
41756
|
+
/** The mirror the model already draws around where the part says, if it draws one. */
|
|
41757
|
+
drawnMirror(p) {
|
|
41758
|
+
const THREE = this.THREE;
|
|
41759
|
+
const [cx, cy, cz] = p.box.center;
|
|
41760
|
+
this.c.root.updateMatrixWorld(true);
|
|
41761
|
+
const inv = this.I.worldInverseOf(this.c);
|
|
41762
|
+
const small = this.c.vehicle.children.flatMap((o) => {
|
|
41763
|
+
if (o.userData.glass || o.userData.decal || !(o.isMesh || o.isGroup) || !o.visible || this.c.deform?.includes(o)) return [];
|
|
41764
|
+
const box2 = this.I.localBox(this.c, o, inv);
|
|
41765
|
+
if (box2.isEmpty()) return [];
|
|
41766
|
+
const size = box2.getSize(new THREE.Vector3());
|
|
41767
|
+
return Math.max(size.x, size.y, size.z) < DRAWN_MIRROR_SIZE ? [{ o, at: box2.getCenter(new THREE.Vector3()) }] : [];
|
|
41768
|
+
});
|
|
41769
|
+
const housing = small.filter(({ at }) => Math.hypot(at.x - cx, at.y - cy, at.z - cz) < DRAWN_MIRROR_REACH && Math.abs(at.z) > Math.abs(cz) - DRAWN_MIRROR_REACH / 2);
|
|
41770
|
+
return small.filter(({ at }) => housing.some((h) => h.at.distanceTo(at) < DRAWN_MIRROR_MOUNT)).map(({ o }) => o);
|
|
41771
|
+
}
|
|
41089
41772
|
makeMirror(p) {
|
|
41773
|
+
const drawn = this.drawnMirror(p);
|
|
41774
|
+
if (drawn.length) {
|
|
41775
|
+
for (const o of drawn) {
|
|
41776
|
+
if (!o.isMesh || o.material !== this.I.MATERIALS.chrome) continue;
|
|
41777
|
+
const size = new this.THREE.Box3().setFromObject(o).getSize(new this.THREE.Vector3());
|
|
41778
|
+
if (size.x < MIRROR_GLASS_THIN && size.y > MIRROR_GLASS_MIN && size.z > MIRROR_GLASS_MIN) this.seatMirrorGlass(o);
|
|
41779
|
+
}
|
|
41780
|
+
this.extra.set(p.id, drawn);
|
|
41781
|
+
return;
|
|
41782
|
+
}
|
|
41090
41783
|
const [cx, cy, cz] = p.box.center;
|
|
41091
41784
|
const s = cz < 0 ? -1 : 1;
|
|
41092
41785
|
const mats = this.I.MATERIALS;
|
|
@@ -41127,17 +41820,28 @@ var GameVehiclesThree = (() => {
|
|
|
41127
41820
|
}
|
|
41128
41821
|
// ---- marks -------------------------------------------------------------------------------------------------------------------------------
|
|
41129
41822
|
/** A bullet hole: a dark disc lying on the surface at `point` (`c.vehicle` coordinates). */
|
|
41130
|
-
holeDecal(point, normal, diameter) {
|
|
41823
|
+
holeDecal(point, normal, diameter, part) {
|
|
41131
41824
|
const THREE = this.THREE;
|
|
41132
|
-
const
|
|
41825
|
+
const pane = part?.role === "glass" ? this.panesOf(part).find((g) => g.visible) : void 0;
|
|
41826
|
+
if (part?.role === "glass" && (!pane || pane.userData.glass?.broken)) return;
|
|
41827
|
+
const radius = Math.max(6e-3, diameter / 2) * HOLE_DECAL_SCALE;
|
|
41828
|
+
const m = new THREE.Mesh(holeDiscGeometry(THREE), holeMaterial(this.kit, part?.material ?? "steel"));
|
|
41829
|
+
m.scale.set(radius, radius, 1);
|
|
41133
41830
|
const n = new THREE.Vector3(...normal);
|
|
41134
|
-
m.position.set(...point).addScaledVector(n,
|
|
41135
|
-
|
|
41831
|
+
m.position.set(...point).addScaledVector(n, 3e-3);
|
|
41832
|
+
this.c.vehicle.add(m);
|
|
41833
|
+
m.lookAt(this.c.vehicle.localToWorld(m.position.clone().add(n)));
|
|
41136
41834
|
m.userData.decal = true;
|
|
41137
41835
|
m.userData.noFollow = true;
|
|
41836
|
+
m.renderOrder = 3;
|
|
41138
41837
|
m.raycast = () => {
|
|
41139
41838
|
};
|
|
41140
|
-
this.c.vehicle.
|
|
41839
|
+
const carrier = (part && (this.plates.get(part.id) ?? (part.id === this.hood?.id ? this.c.hood?.piv : void 0))) ?? (pane && pane.parent !== this.c.vehicle ? pane.parent : null);
|
|
41840
|
+
if (carrier) carrier.attach(m);
|
|
41841
|
+
}
|
|
41842
|
+
/** The door or lid a hinge group stands for. */
|
|
41843
|
+
plateIdOf(o) {
|
|
41844
|
+
return o.userData.plateOf;
|
|
41141
41845
|
}
|
|
41142
41846
|
spark(point, dir, count2 = 8) {
|
|
41143
41847
|
const V3 = this.THREE.Vector3;
|
|
@@ -41177,10 +41881,8 @@ var GameVehiclesThree = (() => {
|
|
|
41177
41881
|
}
|
|
41178
41882
|
/** Glass: cracks (laminated) or shatters (tempered); returns whether it broke. */
|
|
41179
41883
|
hitGlass(p, point, dir, force) {
|
|
41180
|
-
const z = this.zone(p);
|
|
41181
|
-
if (!z) return false;
|
|
41182
41884
|
const V3 = this.THREE.Vector3;
|
|
41183
|
-
const list2 =
|
|
41885
|
+
const list2 = this.panesOf(p).filter((g) => g.parent && g.visible);
|
|
41184
41886
|
if (!list2.length) return false;
|
|
41185
41887
|
const pt = new V3(...point);
|
|
41186
41888
|
let best = list2[0];
|
|
@@ -41197,9 +41899,16 @@ var GameVehiclesThree = (() => {
|
|
|
41197
41899
|
this.kit.hitGlass(this.c, best, pt, new V3(...dir), force);
|
|
41198
41900
|
return !!best.userData.glass?.broken;
|
|
41199
41901
|
}
|
|
41902
|
+
panesOf(p) {
|
|
41903
|
+
return p.panes ?? this.zone(p)?.glass ?? [];
|
|
41904
|
+
}
|
|
41200
41905
|
glassBreak(p) {
|
|
41201
41906
|
const z = this.zone(p);
|
|
41202
|
-
if (!z)
|
|
41907
|
+
if (!z) {
|
|
41908
|
+
for (const g of p.panes ?? []) if (g.parent && g.visible) this.kit.hitGlass(this.c, g, g.position.clone(), new this.THREE.Vector3(0, -1, 0), 0.6);
|
|
41909
|
+
this.gone.add(p.id);
|
|
41910
|
+
return;
|
|
41911
|
+
}
|
|
41203
41912
|
for (const g of z.glass) if (g.parent && g.visible) this.I.glassBand(this.c, z, g, 4);
|
|
41204
41913
|
this.gone.add(p.id);
|
|
41205
41914
|
}
|
|
@@ -41227,6 +41936,7 @@ var GameVehiclesThree = (() => {
|
|
|
41227
41936
|
smoothLater(msh) {
|
|
41228
41937
|
this.smoothing.set(msh, this.I.creaseTask(msh.geometry, 42));
|
|
41229
41938
|
this.tornThisFrame = true;
|
|
41939
|
+
this.holdArmed = true;
|
|
41230
41940
|
}
|
|
41231
41941
|
/** Spends at most `budgetMs` finishing the pending normal smoothing. Call once per frame. */
|
|
41232
41942
|
pump(budgetMs = 2.5) {
|
|
@@ -41234,6 +41944,7 @@ var GameVehiclesThree = (() => {
|
|
|
41234
41944
|
this.tornThisFrame = false;
|
|
41235
41945
|
return;
|
|
41236
41946
|
}
|
|
41947
|
+
if (this.queued) return;
|
|
41237
41948
|
if (!this.smoothing.size && !this.warming) return;
|
|
41238
41949
|
const deadline = performance.now() + budgetMs;
|
|
41239
41950
|
for (const [msh, task] of this.smoothing) {
|
|
@@ -41242,6 +41953,34 @@ var GameVehiclesThree = (() => {
|
|
|
41242
41953
|
}
|
|
41243
41954
|
this.warmIndexes(deadline);
|
|
41244
41955
|
}
|
|
41956
|
+
setQueued(isQueued) {
|
|
41957
|
+
this.queued = isQueued;
|
|
41958
|
+
}
|
|
41959
|
+
/** Units the shared queue may run now: 0 in the frame of the cut (the first ask after it holds the work for that frame, or `pump` closes it when there is no frame). */
|
|
41960
|
+
pendingUnits(frame) {
|
|
41961
|
+
if (this.holdArmed && frame !== void 0) {
|
|
41962
|
+
this.holdArmed = false;
|
|
41963
|
+
this.holdFrame = frame;
|
|
41964
|
+
}
|
|
41965
|
+
if (frame !== void 0 && frame === this.holdFrame) return 0;
|
|
41966
|
+
if (frame === void 0 && this.tornThisFrame) return 0;
|
|
41967
|
+
return this.smoothing.size + (this.warming ? 1 : 0);
|
|
41968
|
+
}
|
|
41969
|
+
/** One slice of the pending work, for the shared queue. */
|
|
41970
|
+
runStep(deadline) {
|
|
41971
|
+
const next = this.smoothing.entries().next();
|
|
41972
|
+
if (!next.done) {
|
|
41973
|
+
const [msh, task] = next.value;
|
|
41974
|
+
if (msh.geometry !== task.geo || task.step(deadline)) this.smoothing.delete(msh);
|
|
41975
|
+
return true;
|
|
41976
|
+
}
|
|
41977
|
+
if (!this.warming) return false;
|
|
41978
|
+
this.warmIndexes(deadline);
|
|
41979
|
+
return true;
|
|
41980
|
+
}
|
|
41981
|
+
finishAll() {
|
|
41982
|
+
while (this.runStep(Infinity)) ;
|
|
41983
|
+
}
|
|
41245
41984
|
/** Measures the triangles of the heavy body meshes once, a slice per frame, so the first panel torn off finds them ready (see `triIndexOf`). */
|
|
41246
41985
|
warmIndexes(deadline) {
|
|
41247
41986
|
if (!this.warming) return;
|
|
@@ -41413,6 +42152,7 @@ var GameVehiclesThree = (() => {
|
|
|
41413
42152
|
}
|
|
41414
42153
|
pieceTasks.forEach((task, mesh2) => this.smoothing.set(mesh2, task));
|
|
41415
42154
|
this.tornThisFrame = true;
|
|
42155
|
+
this.holdArmed = true;
|
|
41416
42156
|
dirty.forEach((msh) => {
|
|
41417
42157
|
const g = msh.geometry;
|
|
41418
42158
|
if (g.userData.crease || !g.index) this.smoothLater(msh);
|
|
@@ -41515,6 +42255,7 @@ var GameVehiclesThree = (() => {
|
|
|
41515
42255
|
let clock = 0;
|
|
41516
42256
|
let model;
|
|
41517
42257
|
let vis = null;
|
|
42258
|
+
let releaseCrease;
|
|
41518
42259
|
const ps = /* @__PURE__ */ new Map();
|
|
41519
42260
|
let js = [];
|
|
41520
42261
|
let leaks = /* @__PURE__ */ new Map();
|
|
@@ -41599,7 +42340,9 @@ var GameVehiclesThree = (() => {
|
|
|
41599
42340
|
rand = rng(seedBase);
|
|
41600
42341
|
igniteRand = rng(strHash(`${c.key}|${id}|ignition|${options.seed ?? 0}`));
|
|
41601
42342
|
steerSign = rand() < 0.5 ? -1 : 1;
|
|
42343
|
+
releaseCrease?.();
|
|
41602
42344
|
vis = headless ? null : new VehicleVisuals(kit, c, model);
|
|
42345
|
+
releaseCrease = vis && options.creaseQueue ? options.creaseQueue.track(vis) : void 0;
|
|
41603
42346
|
recomputeGroups();
|
|
41604
42347
|
};
|
|
41605
42348
|
const recomputeGroups = () => {
|
|
@@ -41910,13 +42653,13 @@ var GameVehiclesThree = (() => {
|
|
|
41910
42653
|
sync();
|
|
41911
42654
|
const M = toFrameMatrix();
|
|
41912
42655
|
const v = toLocal(h.point);
|
|
41913
|
-
const p = locate(v, 0.2);
|
|
42656
|
+
const p = (h.part ? ps.get(h.part) : void 0) ?? locate(v, 0.2);
|
|
41914
42657
|
if (!p) return;
|
|
41915
42658
|
const d = p.def;
|
|
41916
42659
|
const E = h.energy ?? 0;
|
|
41917
42660
|
const cal = h.caliber ?? 9;
|
|
41918
42661
|
const dir = dirToLocal(h.direction ?? [0, 0, -1]).normalize();
|
|
41919
|
-
const n = normalOf(d, v);
|
|
42662
|
+
const n = h.normal ? dirToLocal(h.normal).normalize() : normalOf(d, v);
|
|
41920
42663
|
const res = resist(d, p);
|
|
41921
42664
|
const through = E >= res;
|
|
41922
42665
|
const cosInc = Math.abs(dir.dot(n));
|
|
@@ -41935,7 +42678,7 @@ var GameVehiclesThree = (() => {
|
|
|
41935
42678
|
const hp = { point: r3(fromVehicle(v, M)), normal: r3(fromVehicle(n, new THREE.Matrix4().extractRotation(M))), diameter: r2(holeDiam), through };
|
|
41936
42679
|
p.holes.push(hp);
|
|
41937
42680
|
out.push(ev({ type: "hole", part: d.id, hole: hp, worldPoint, ...through ? { exitPoint: add3(worldPoint, r3(dirToWorld(dir.clone().multiplyScalar(Math.max(0.02, Math.min(d.box.size[0], d.box.size[1], d.box.size[2])))))) } : {} }));
|
|
41938
|
-
vis?.holeDecal([v.x, v.y, v.z], [n.x, n.y, n.z], holeDiam);
|
|
42681
|
+
vis?.holeDecal([v.x, v.y, v.z], [n.x, n.y, n.z], holeDiam, d);
|
|
41939
42682
|
startLeak(p, v, cal, out, dir);
|
|
41940
42683
|
};
|
|
41941
42684
|
switch (d.material) {
|
|
@@ -42236,6 +42979,46 @@ var GameVehiclesThree = (() => {
|
|
|
42236
42979
|
for (const p of ps.values()) if (!p.lost && (p.burning || p.temp > AMBIENT)) return true;
|
|
42237
42980
|
return false;
|
|
42238
42981
|
};
|
|
42982
|
+
const surfaceRays = new THREE.Raycaster();
|
|
42983
|
+
surfaceRays.layers.enableAll();
|
|
42984
|
+
surfaceRays.camera = new THREE.PerspectiveCamera();
|
|
42985
|
+
let meshParts = null;
|
|
42986
|
+
const paneParts = () => {
|
|
42987
|
+
if (meshParts) return meshParts;
|
|
42988
|
+
meshParts = /* @__PURE__ */ new Map();
|
|
42989
|
+
for (const d of model.parts) {
|
|
42990
|
+
if (d.role !== "glass") continue;
|
|
42991
|
+
const z = kit.zonesOf(c).find((q) => q.id === d.zoneId);
|
|
42992
|
+
for (const g of z?.glass ?? d.panes ?? []) meshParts.set(g, d.id);
|
|
42993
|
+
}
|
|
42994
|
+
return meshParts;
|
|
42995
|
+
};
|
|
42996
|
+
const isDrawnSurface = (o) => {
|
|
42997
|
+
for (let q = o; q && q !== c.vehicle; q = q.parent) if (!q.visible || q.userData.decal || q.userData.ghost) return false;
|
|
42998
|
+
return true;
|
|
42999
|
+
};
|
|
43000
|
+
const partOfSurface = (o, v) => {
|
|
43001
|
+
const pane = paneParts().get(o);
|
|
43002
|
+
if (pane) return ps.get(pane) ?? null;
|
|
43003
|
+
for (let q = o; q && q !== c.vehicle; q = q.parent) {
|
|
43004
|
+
if (vis?.plateIdOf(q)) return ps.get(vis.plateIdOf(q)) ?? null;
|
|
43005
|
+
}
|
|
43006
|
+
return locate(v, 0.08, (p) => p.def.role === "glass");
|
|
43007
|
+
};
|
|
43008
|
+
const surfaceRay = (ray) => {
|
|
43009
|
+
sync();
|
|
43010
|
+
surfaceRays.set(new V3(ray.origin[0], ray.origin[1], ray.origin[2]), new V3(ray.direction[0], ray.direction[1], ray.direction[2]));
|
|
43011
|
+
surfaceRays.far = ray.maxDistance;
|
|
43012
|
+
for (const h of surfaceRays.intersectObject(c.vehicle, true)) {
|
|
43013
|
+
if (!h.face || !isDrawnSurface(h.object)) continue;
|
|
43014
|
+
const p = partOfSurface(h.object, c.vehicle.worldToLocal(h.point.clone()));
|
|
43015
|
+
if (!p || p.lost || ray.ignored?.(p.def.id)) continue;
|
|
43016
|
+
const n = h.face.normal.clone().transformDirection(h.object.matrixWorld);
|
|
43017
|
+
if (n.dot(surfaceRays.ray.direction) > 0) n.negate();
|
|
43018
|
+
return { part: p.def.id, point: [h.point.x, h.point.y, h.point.z], normal: [n.x, n.y, n.z], distance: h.distance, pathLen: 0.02 };
|
|
43019
|
+
}
|
|
43020
|
+
return null;
|
|
43021
|
+
};
|
|
42239
43022
|
const hit = (h) => {
|
|
42240
43023
|
stateCache = void 0;
|
|
42241
43024
|
const out = [];
|
|
@@ -42358,9 +43141,14 @@ var GameVehiclesThree = (() => {
|
|
|
42358
43141
|
},
|
|
42359
43142
|
describe,
|
|
42360
43143
|
hit,
|
|
43144
|
+
surfaceRay,
|
|
42361
43145
|
update,
|
|
42362
43146
|
state,
|
|
42363
43147
|
reset,
|
|
43148
|
+
dispose: () => {
|
|
43149
|
+
releaseCrease?.();
|
|
43150
|
+
releaseCrease = void 0;
|
|
43151
|
+
},
|
|
42364
43152
|
disassemble,
|
|
42365
43153
|
extinguish,
|
|
42366
43154
|
serialize: () => ({
|
|
@@ -42396,6 +43184,59 @@ var GameVehiclesThree = (() => {
|
|
|
42396
43184
|
root.userData.vehicle = vehicle;
|
|
42397
43185
|
return { root, vehicle };
|
|
42398
43186
|
}
|
|
43187
|
+
function createCreaseQueue() {
|
|
43188
|
+
const tracked = [];
|
|
43189
|
+
let cursor = 0;
|
|
43190
|
+
let lastFrame;
|
|
43191
|
+
let attached = false;
|
|
43192
|
+
const deferred = {
|
|
43193
|
+
id: DEFERRED_QUEUE_ID.VEHICLE_CREASE,
|
|
43194
|
+
pending(frame) {
|
|
43195
|
+
lastFrame = frame;
|
|
43196
|
+
let units = 0;
|
|
43197
|
+
for (const work of tracked) units += work.pendingUnits(frame);
|
|
43198
|
+
return units;
|
|
43199
|
+
},
|
|
43200
|
+
run(deadline, clock) {
|
|
43201
|
+
let ran = 0;
|
|
43202
|
+
let skipped = 0;
|
|
43203
|
+
while (tracked.length > 0 && skipped < tracked.length) {
|
|
43204
|
+
if (ran > 0 && clock() >= deadline) break;
|
|
43205
|
+
const work = tracked[cursor % tracked.length];
|
|
43206
|
+
cursor = (cursor + 1) % tracked.length;
|
|
43207
|
+
if (work.pendingUnits(lastFrame) > 0 && work.runStep(deadline)) {
|
|
43208
|
+
ran++;
|
|
43209
|
+
skipped = 0;
|
|
43210
|
+
} else skipped++;
|
|
43211
|
+
}
|
|
43212
|
+
return ran;
|
|
43213
|
+
},
|
|
43214
|
+
flush() {
|
|
43215
|
+
for (const work of tracked) work.finishAll();
|
|
43216
|
+
},
|
|
43217
|
+
attach() {
|
|
43218
|
+
attached = true;
|
|
43219
|
+
for (const work of tracked) work.setQueued(true);
|
|
43220
|
+
},
|
|
43221
|
+
detach() {
|
|
43222
|
+
attached = false;
|
|
43223
|
+
for (const work of tracked) work.setQueued(false);
|
|
43224
|
+
}
|
|
43225
|
+
};
|
|
43226
|
+
return {
|
|
43227
|
+
deferredQueue: () => deferred,
|
|
43228
|
+
track(work) {
|
|
43229
|
+
tracked.push(work);
|
|
43230
|
+
work.setQueued(attached);
|
|
43231
|
+
return () => {
|
|
43232
|
+
const at = tracked.indexOf(work);
|
|
43233
|
+
if (at < 0) return;
|
|
43234
|
+
tracked.splice(at, 1);
|
|
43235
|
+
work.setQueued(false);
|
|
43236
|
+
};
|
|
43237
|
+
}
|
|
43238
|
+
};
|
|
43239
|
+
}
|
|
42399
43240
|
var CABIN_LEAK = 0.02;
|
|
42400
43241
|
var HOLE_RATE_PER_AREA = 3e3;
|
|
42401
43242
|
var CRACK_GAP_PER_METRE = 0.5;
|
|
@@ -42514,6 +43355,217 @@ var GameVehiclesThree = (() => {
|
|
|
42514
43355
|
};
|
|
42515
43356
|
}
|
|
42516
43357
|
|
|
43358
|
+
// ../game-render-three/dist/index.js
|
|
43359
|
+
var DEFAULT_ANGLE = Math.PI / 3;
|
|
43360
|
+
var EFFECT_STEP_SECONDS = 1 / 50;
|
|
43361
|
+
function isRenderPools(value) {
|
|
43362
|
+
const candidate = value;
|
|
43363
|
+
return typeof candidate === "object" && candidate !== null && typeof candidate.geometries?.acquire === "function" && typeof candidate.materials?.acquire === "function";
|
|
43364
|
+
}
|
|
43365
|
+
var BATCHED_LAYER = 30;
|
|
43366
|
+
var MATRIX_EPSILON = 1e-6;
|
|
43367
|
+
var ATTRIBUTES = ["position", "normal", "uv", "color"];
|
|
43368
|
+
var isShown = (object2, root) => {
|
|
43369
|
+
for (let node = object2; node; node = node.parent) {
|
|
43370
|
+
if (node === root) return true;
|
|
43371
|
+
if (!node.visible) return false;
|
|
43372
|
+
}
|
|
43373
|
+
return false;
|
|
43374
|
+
};
|
|
43375
|
+
var isBatchable = (mesh2) => {
|
|
43376
|
+
const flags = mesh2;
|
|
43377
|
+
if (flags.isInstancedMesh === true || flags.isSkinnedMesh === true || Array.isArray(mesh2.material)) return false;
|
|
43378
|
+
const geometry = mesh2.geometry;
|
|
43379
|
+
return geometry.attributes.position !== void 0 && Object.keys(geometry.morphAttributes).length === 0;
|
|
43380
|
+
};
|
|
43381
|
+
var signatureOf = (mesh2) => {
|
|
43382
|
+
const { attributes } = mesh2.geometry;
|
|
43383
|
+
const present = ATTRIBUTES.filter((name) => attributes[name] !== void 0).map((name) => `${name}${attributes[name].itemSize}`);
|
|
43384
|
+
return `${mesh2.material.uuid}|${present.join(",")}|${mesh2.castShadow ? 1 : 0}${mesh2.receiveShadow ? 1 : 0}`;
|
|
43385
|
+
};
|
|
43386
|
+
var sameMatrix = (a, b) => a.elements.every((value, index) => Math.abs(value - b.elements[index]) < MATRIX_EPSILON);
|
|
43387
|
+
function createStaticBatcher(THREE, root, options = {}) {
|
|
43388
|
+
const include = options.include ?? (() => true);
|
|
43389
|
+
const follow = options.followMeshes === true;
|
|
43390
|
+
root.updateMatrixWorld(true);
|
|
43391
|
+
const inverse = new THREE.Matrix4().copy(root.matrixWorld).invert();
|
|
43392
|
+
const groups = /* @__PURE__ */ new Map();
|
|
43393
|
+
root.traverse((object2) => {
|
|
43394
|
+
const mesh2 = object2;
|
|
43395
|
+
if (!mesh2.isMesh || !isShown(mesh2, root) || !isBatchable(mesh2) || !include(mesh2)) return;
|
|
43396
|
+
const key = signatureOf(mesh2);
|
|
43397
|
+
groups.set(key, [...groups.get(key) ?? [], mesh2]);
|
|
43398
|
+
});
|
|
43399
|
+
const group = new THREE.Group();
|
|
43400
|
+
group.name = "static-batches";
|
|
43401
|
+
const sources = [];
|
|
43402
|
+
const pending = [...groups.values()].filter((meshes) => meshes.length >= 2);
|
|
43403
|
+
const mergeSome = (deadline) => {
|
|
43404
|
+
while (pending.length > 0) {
|
|
43405
|
+
const meshes = pending.shift();
|
|
43406
|
+
if (meshes.every((mesh2) => isShown(mesh2, root))) sources.push(...mergeGroup(THREE, { meshes, inverse: new THREE.Matrix4().copy(root.matrixWorld).invert(), group, follow }));
|
|
43407
|
+
if (performance.now() >= deadline) return;
|
|
43408
|
+
}
|
|
43409
|
+
};
|
|
43410
|
+
if (options.budgetMs === void 0) mergeSome(Number.POSITIVE_INFINITY);
|
|
43411
|
+
root.add(group);
|
|
43412
|
+
const scratch2 = new THREE.Matrix4();
|
|
43413
|
+
let released = 0;
|
|
43414
|
+
const release = (source) => {
|
|
43415
|
+
source.released = true;
|
|
43416
|
+
source.mesh.layers.mask = source.mask;
|
|
43417
|
+
const { index } = source.batch;
|
|
43418
|
+
const first = index.array[source.start];
|
|
43419
|
+
for (let at = source.start; at < source.start + source.count; at++) index.array[at] = first;
|
|
43420
|
+
index.needsUpdate = true;
|
|
43421
|
+
if (--source.batch.live === 0) source.batch.mesh.visible = false;
|
|
43422
|
+
released++;
|
|
43423
|
+
};
|
|
43424
|
+
const hasChanged = (source) => {
|
|
43425
|
+
const { mesh: mesh2 } = source;
|
|
43426
|
+
if (mesh2.geometry !== source.geometry || mesh2.material !== source.material || !isShown(mesh2, root)) return true;
|
|
43427
|
+
if (mesh2.geometry.attributes.position.version !== source.version) return true;
|
|
43428
|
+
if (follow || sameMatrix(mesh2.matrixWorld, source.world)) return false;
|
|
43429
|
+
if (!sameMatrix(scratch2.multiplyMatrices(inverse, mesh2.matrixWorld), source.local)) return true;
|
|
43430
|
+
source.world.copy(mesh2.matrixWorld);
|
|
43431
|
+
return false;
|
|
43432
|
+
};
|
|
43433
|
+
return {
|
|
43434
|
+
group,
|
|
43435
|
+
update() {
|
|
43436
|
+
if (pending.length > 0) mergeSome(performance.now() + (options.budgetMs ?? Number.POSITIVE_INFINITY));
|
|
43437
|
+
const before = released;
|
|
43438
|
+
inverse.copy(root.matrixWorld).invert();
|
|
43439
|
+
for (const source of sources) if (!source.released && hasChanged(source)) release(source);
|
|
43440
|
+
return released - before;
|
|
43441
|
+
},
|
|
43442
|
+
stats: () => ({ batches: group.children.length, batched: sources.filter((source) => !source.released).length, released }),
|
|
43443
|
+
dispose() {
|
|
43444
|
+
for (const source of sources) if (!source.released) source.mesh.layers.mask = source.mask;
|
|
43445
|
+
group.removeFromParent();
|
|
43446
|
+
for (const child of group.children) {
|
|
43447
|
+
;
|
|
43448
|
+
child.geometry.dispose();
|
|
43449
|
+
child.skeleton?.dispose();
|
|
43450
|
+
}
|
|
43451
|
+
}
|
|
43452
|
+
};
|
|
43453
|
+
}
|
|
43454
|
+
function copyAttribute(name, attribute, target, offset, matrix, normalMatrix2) {
|
|
43455
|
+
const size = attribute.itemSize;
|
|
43456
|
+
const source = attribute.array;
|
|
43457
|
+
const flat = !attribute.isInterleavedBufferAttribute && source.length === attribute.count * size;
|
|
43458
|
+
if (name !== "position" && name !== "normal") {
|
|
43459
|
+
if (flat) target.set(source, offset * size);
|
|
43460
|
+
else for (let at = 0; at < attribute.count; at++) for (let k = 0; k < size; k++) target[(offset + at) * size + k] = attribute.getComponent(at, k);
|
|
43461
|
+
return;
|
|
43462
|
+
}
|
|
43463
|
+
const e = (name === "position" ? matrix : normalMatrix2).elements;
|
|
43464
|
+
const isNormal = name === "normal";
|
|
43465
|
+
for (let at = 0; at < attribute.count; at++) {
|
|
43466
|
+
const x = attribute.getX(at);
|
|
43467
|
+
const y = attribute.getY(at);
|
|
43468
|
+
const z = attribute.getZ(at);
|
|
43469
|
+
const out = (offset + at) * 3;
|
|
43470
|
+
if (isNormal) {
|
|
43471
|
+
const nx = e[0] * x + e[3] * y + e[6] * z;
|
|
43472
|
+
const ny = e[1] * x + e[4] * y + e[7] * z;
|
|
43473
|
+
const nz = e[2] * x + e[5] * y + e[8] * z;
|
|
43474
|
+
const length = Math.hypot(nx, ny, nz) || 1;
|
|
43475
|
+
target[out] = nx / length;
|
|
43476
|
+
target[out + 1] = ny / length;
|
|
43477
|
+
target[out + 2] = nz / length;
|
|
43478
|
+
} else {
|
|
43479
|
+
target[out] = e[0] * x + e[4] * y + e[8] * z + e[12];
|
|
43480
|
+
target[out + 1] = e[1] * x + e[5] * y + e[9] * z + e[13];
|
|
43481
|
+
target[out + 2] = e[2] * x + e[6] * y + e[10] * z + e[14];
|
|
43482
|
+
}
|
|
43483
|
+
}
|
|
43484
|
+
}
|
|
43485
|
+
function skinnedBatch(THREE, merged, material, meshes) {
|
|
43486
|
+
const vertices = merged.attributes.position.count;
|
|
43487
|
+
const skinIndex = new Uint16Array(vertices * 4);
|
|
43488
|
+
const skinWeight = new Float32Array(vertices * 4);
|
|
43489
|
+
let at = 0;
|
|
43490
|
+
meshes.forEach((mesh22, bone) => {
|
|
43491
|
+
for (let k = 0; k < mesh22.geometry.attributes.position.count; k++, at++) {
|
|
43492
|
+
skinIndex[at * 4] = bone;
|
|
43493
|
+
skinWeight[at * 4] = 1;
|
|
43494
|
+
}
|
|
43495
|
+
});
|
|
43496
|
+
merged.setAttribute("skinIndex", new THREE.BufferAttribute(skinIndex, 4));
|
|
43497
|
+
merged.setAttribute("skinWeight", new THREE.BufferAttribute(skinWeight, 4));
|
|
43498
|
+
const mesh2 = new THREE.SkinnedMesh(merged, material);
|
|
43499
|
+
const identities = meshes.map(() => new THREE.Matrix4());
|
|
43500
|
+
mesh2.bind(new THREE.Skeleton(meshes, identities), new THREE.Matrix4());
|
|
43501
|
+
mesh2.frustumCulled = false;
|
|
43502
|
+
return mesh2;
|
|
43503
|
+
}
|
|
43504
|
+
function mergeGroup(THREE, { meshes, inverse: rootInverse, group, follow }) {
|
|
43505
|
+
const identity = new THREE.Matrix4();
|
|
43506
|
+
const inverse = follow ? identity : rootInverse;
|
|
43507
|
+
const first = meshes[0];
|
|
43508
|
+
const names = ATTRIBUTES.filter((name) => first.geometry.attributes[name] !== void 0);
|
|
43509
|
+
const pieces = meshes.map((mesh22) => {
|
|
43510
|
+
const local = new THREE.Matrix4().multiplyMatrices(inverse, mesh22.matrixWorld);
|
|
43511
|
+
const vertices = mesh22.geometry.attributes.position.count;
|
|
43512
|
+
const indexCount = mesh22.geometry.index ? mesh22.geometry.index.count : vertices;
|
|
43513
|
+
return { mesh: mesh22, local, vertices, indexCount };
|
|
43514
|
+
});
|
|
43515
|
+
const totalVertices = pieces.reduce((sum, piece) => sum + piece.vertices, 0);
|
|
43516
|
+
const totalIndices = pieces.reduce((sum, piece) => sum + piece.indexCount, 0);
|
|
43517
|
+
const merged = new THREE.BufferGeometry();
|
|
43518
|
+
const normalMatrix2 = new THREE.Matrix3();
|
|
43519
|
+
for (const name of names) {
|
|
43520
|
+
const size = first.geometry.attributes[name].itemSize;
|
|
43521
|
+
const array = new Float32Array(totalVertices * size);
|
|
43522
|
+
let offset = 0;
|
|
43523
|
+
for (const piece of pieces) {
|
|
43524
|
+
const matrix = follow ? identity : piece.local;
|
|
43525
|
+
copyAttribute(name, piece.mesh.geometry.attributes[name], array, offset, matrix, normalMatrix2.getNormalMatrix(matrix));
|
|
43526
|
+
offset += piece.vertices;
|
|
43527
|
+
}
|
|
43528
|
+
merged.setAttribute(name, new THREE.BufferAttribute(array, size));
|
|
43529
|
+
}
|
|
43530
|
+
const indexArray2 = totalVertices > 65535 ? new Uint32Array(totalIndices) : new Uint16Array(totalIndices);
|
|
43531
|
+
const indexAttribute = new THREE.BufferAttribute(indexArray2, 1);
|
|
43532
|
+
merged.setIndex(indexAttribute);
|
|
43533
|
+
const mesh2 = follow ? skinnedBatch(THREE, merged, first.material, meshes) : new THREE.Mesh(merged, first.material);
|
|
43534
|
+
mesh2.name = `batch:${first.material.name || first.material.type}`;
|
|
43535
|
+
mesh2.castShadow = first.castShadow;
|
|
43536
|
+
mesh2.receiveShadow = first.receiveShadow;
|
|
43537
|
+
mesh2.raycast = () => void 0;
|
|
43538
|
+
merged.computeBoundingBox();
|
|
43539
|
+
merged.computeBoundingSphere();
|
|
43540
|
+
group.add(mesh2);
|
|
43541
|
+
const batch = { mesh: mesh2, live: pieces.length, index: indexAttribute };
|
|
43542
|
+
const sources = [];
|
|
43543
|
+
let vertexOffset = 0;
|
|
43544
|
+
let indexOffset = 0;
|
|
43545
|
+
for (const piece of pieces) {
|
|
43546
|
+
const index = piece.mesh.geometry.index;
|
|
43547
|
+
if (index) for (let at = 0; at < piece.indexCount; at++) indexArray2[indexOffset + at] = index.getX(at) + vertexOffset;
|
|
43548
|
+
else for (let at = 0; at < piece.indexCount; at++) indexArray2[indexOffset + at] = at + vertexOffset;
|
|
43549
|
+
sources.push({
|
|
43550
|
+
mesh: piece.mesh,
|
|
43551
|
+
geometry: piece.mesh.geometry,
|
|
43552
|
+
material: piece.mesh.material,
|
|
43553
|
+
version: piece.mesh.geometry.attributes.position.version,
|
|
43554
|
+
local: piece.local,
|
|
43555
|
+
world: piece.mesh.matrixWorld.clone(),
|
|
43556
|
+
mask: piece.mesh.layers.mask,
|
|
43557
|
+
batch,
|
|
43558
|
+
start: indexOffset,
|
|
43559
|
+
count: piece.indexCount,
|
|
43560
|
+
released: false
|
|
43561
|
+
});
|
|
43562
|
+
piece.mesh.layers.set(BATCHED_LAYER);
|
|
43563
|
+
vertexOffset += piece.vertices;
|
|
43564
|
+
indexOffset += piece.indexCount;
|
|
43565
|
+
}
|
|
43566
|
+
return sources;
|
|
43567
|
+
}
|
|
43568
|
+
|
|
42517
43569
|
// ../game-vehicles-driving/dist/index.js
|
|
42518
43570
|
var defaultArcadeSpec = {
|
|
42519
43571
|
length: 4.3,
|
|
@@ -42929,6 +43981,169 @@ var GameVehiclesThree = (() => {
|
|
|
42929
43981
|
return driver;
|
|
42930
43982
|
}
|
|
42931
43983
|
|
|
43984
|
+
// src/vehicle-lod.ts
|
|
43985
|
+
var VEHICLE_LOD_DISTANCE = 14;
|
|
43986
|
+
var BATCH_BUDGET_MS = 2;
|
|
43987
|
+
var isShown2 = (object2, top) => {
|
|
43988
|
+
for (let node = object2; node && node !== top; node = node.parent) if (node.visible === false) return false;
|
|
43989
|
+
return true;
|
|
43990
|
+
};
|
|
43991
|
+
function createVehicleLod(kit, context, root, full) {
|
|
43992
|
+
const THREE = kit.THREE;
|
|
43993
|
+
let isUploaded = false;
|
|
43994
|
+
let modelKey = "";
|
|
43995
|
+
const culled = /* @__PURE__ */ new Map();
|
|
43996
|
+
const keyOf = () => full.children.filter((child) => child.name !== "static-batches").map((child) => child.uuid).join();
|
|
43997
|
+
const armUpload = () => {
|
|
43998
|
+
for (const [mesh2, wasCulled] of culled) mesh2.frustumCulled = wasCulled;
|
|
43999
|
+
culled.clear();
|
|
44000
|
+
modelKey = keyOf();
|
|
44001
|
+
isUploaded = false;
|
|
44002
|
+
full.traverse((object2) => {
|
|
44003
|
+
if (!object2.isMesh || culled.has(object2)) return;
|
|
44004
|
+
culled.set(object2, object2.frustumCulled);
|
|
44005
|
+
object2.frustumCulled = false;
|
|
44006
|
+
});
|
|
44007
|
+
const probe = [...culled.keys()][0];
|
|
44008
|
+
if (!probe) {
|
|
44009
|
+
isUploaded = true;
|
|
44010
|
+
return;
|
|
44011
|
+
}
|
|
44012
|
+
const before = probe.onAfterRender;
|
|
44013
|
+
probe.onAfterRender = function(...args) {
|
|
44014
|
+
isUploaded = true;
|
|
44015
|
+
probe.onAfterRender = before;
|
|
44016
|
+
before?.apply(this, args);
|
|
44017
|
+
};
|
|
44018
|
+
};
|
|
44019
|
+
armUpload();
|
|
44020
|
+
let lite = null;
|
|
44021
|
+
let isFused = false;
|
|
44022
|
+
let isLocked = false;
|
|
44023
|
+
let batcher = null;
|
|
44024
|
+
let shadow = null;
|
|
44025
|
+
const castsShadow = /* @__PURE__ */ new Set();
|
|
44026
|
+
const shadowProxyOf = (fused) => {
|
|
44027
|
+
const positions = [];
|
|
44028
|
+
const indices = [];
|
|
44029
|
+
for (const mesh2 of fused.children) {
|
|
44030
|
+
if (!mesh2.isMesh || !mesh2.castShadow) continue;
|
|
44031
|
+
const geometry2 = mesh2.geometry.clone().applyMatrix4(mesh2.matrix);
|
|
44032
|
+
const offset = positions.length / 3;
|
|
44033
|
+
const position = geometry2.attributes.position;
|
|
44034
|
+
for (let at = 0; at < position.count; at++) positions.push(position.getX(at), position.getY(at), position.getZ(at));
|
|
44035
|
+
const index = geometry2.index ? Array.from(geometry2.index.array) : Array.from({ length: position.count }, (_, at) => at);
|
|
44036
|
+
for (const vertex of index) indices.push(vertex + offset);
|
|
44037
|
+
geometry2.dispose();
|
|
44038
|
+
}
|
|
44039
|
+
const geometry = new THREE.BufferGeometry();
|
|
44040
|
+
geometry.setAttribute("position", new THREE.Float32BufferAttribute(positions, 3));
|
|
44041
|
+
geometry.setIndex(indices);
|
|
44042
|
+
geometry.computeBoundingSphere();
|
|
44043
|
+
const proxy = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ colorWrite: false, depthWrite: false }));
|
|
44044
|
+
proxy.name = "vehicle-shadow";
|
|
44045
|
+
markKitOrigin(proxy, { owner: "game-vehicles-three", kind: "vehicle", id: root.name });
|
|
44046
|
+
proxy.castShadow = true;
|
|
44047
|
+
proxy.userData.skipLite = true;
|
|
44048
|
+
proxy.raycast = () => void 0;
|
|
44049
|
+
root.add(proxy);
|
|
44050
|
+
return proxy;
|
|
44051
|
+
};
|
|
44052
|
+
const drawFull = () => {
|
|
44053
|
+
if (!batcher && isLocked) return;
|
|
44054
|
+
if (!batcher) {
|
|
44055
|
+
lite ?? (lite = build());
|
|
44056
|
+
lite.visible = isFused;
|
|
44057
|
+
shadow ?? (shadow = shadowProxyOf(lite));
|
|
44058
|
+
shadow.visible = !isFused;
|
|
44059
|
+
full.traverse((object2) => {
|
|
44060
|
+
if (!object2.isMesh || !object2.castShadow) return;
|
|
44061
|
+
castsShadow.add(object2);
|
|
44062
|
+
object2.castShadow = false;
|
|
44063
|
+
});
|
|
44064
|
+
batcher = createStaticBatcher(THREE, full, { budgetMs: BATCH_BUDGET_MS });
|
|
44065
|
+
batcher.group.traverse((object2) => object2.userData.skipLite = true);
|
|
44066
|
+
markKitOrigin(batcher.group, { owner: "game-vehicles-three", kind: "vehicle", id: root.name });
|
|
44067
|
+
return;
|
|
44068
|
+
}
|
|
44069
|
+
batcher.update();
|
|
44070
|
+
if (!isLocked && batcher.stats().batched === 0 && batcher.stats().released > 0) {
|
|
44071
|
+
batcher.dispose();
|
|
44072
|
+
batcher = null;
|
|
44073
|
+
}
|
|
44074
|
+
};
|
|
44075
|
+
const build = () => {
|
|
44076
|
+
root.updateMatrixWorld(true);
|
|
44077
|
+
const inverse = new THREE.Matrix4().copy(root.matrixWorld).invert();
|
|
44078
|
+
const textured = [];
|
|
44079
|
+
full.traverse((object2) => {
|
|
44080
|
+
if (!object2.isMesh || object2.userData.skipLite || !isShown2(object2, full)) return;
|
|
44081
|
+
const materials = Array.isArray(object2.material) ? object2.material : [object2.material];
|
|
44082
|
+
if (materials.some((material) => material?.map && !/plate/i.test(material.name ?? "")) && !/plate/i.test(object2.name ?? "")) textured.push(object2);
|
|
44083
|
+
});
|
|
44084
|
+
for (const mesh2 of textured) mesh2.userData.skipLite = true;
|
|
44085
|
+
const fusion = fuse(THREE, { ...context, vehicle: full }, inverse, null, primaryPaint(context), kit.lodHiddenMaterials());
|
|
44086
|
+
for (const mesh2 of textured) delete mesh2.userData.skipLite;
|
|
44087
|
+
const group = new THREE.Group();
|
|
44088
|
+
group.name = "vehicle-lite";
|
|
44089
|
+
markKitOrigin(group, { owner: "game-vehicles-three", kind: "vehicle", id: root.name });
|
|
44090
|
+
for (const mesh2 of liteMeshes(THREE, fusion, liteMaterials(THREE, kit.studioEnvironment()))) group.add(mesh2);
|
|
44091
|
+
for (const mesh2 of textured) {
|
|
44092
|
+
const copy = new THREE.Mesh(mesh2.geometry, mesh2.material);
|
|
44093
|
+
copy.matrixAutoUpdate = false;
|
|
44094
|
+
copy.matrix.multiplyMatrices(inverse, mesh2.matrixWorld);
|
|
44095
|
+
copy.castShadow = mesh2.castShadow;
|
|
44096
|
+
copy.receiveShadow = mesh2.receiveShadow;
|
|
44097
|
+
group.add(copy);
|
|
44098
|
+
}
|
|
44099
|
+
root.add(group);
|
|
44100
|
+
return group;
|
|
44101
|
+
};
|
|
44102
|
+
const show = (shouldFuse) => {
|
|
44103
|
+
if (shouldFuse === isFused) return;
|
|
44104
|
+
isFused = shouldFuse;
|
|
44105
|
+
full.visible = !shouldFuse;
|
|
44106
|
+
if (lite) lite.visible = shouldFuse;
|
|
44107
|
+
if (shadow) shadow.visible = !shouldFuse;
|
|
44108
|
+
};
|
|
44109
|
+
const api = {
|
|
44110
|
+
update(distance, touched, posed = false) {
|
|
44111
|
+
isLocked || (isLocked = touched);
|
|
44112
|
+
if (keyOf() !== modelKey) {
|
|
44113
|
+
api.dispose();
|
|
44114
|
+
armUpload();
|
|
44115
|
+
}
|
|
44116
|
+
if (!isUploaded) return show(false);
|
|
44117
|
+
if (culled.size > 0) {
|
|
44118
|
+
for (const [mesh2, wasCulled] of culled) mesh2.frustumCulled = wasCulled;
|
|
44119
|
+
culled.clear();
|
|
44120
|
+
}
|
|
44121
|
+
const shouldFuse = !isLocked && !posed && distance > (isFused ? VEHICLE_LOD_DISTANCE * 0.9 : VEHICLE_LOD_DISTANCE);
|
|
44122
|
+
if (shouldFuse && !lite) lite = build();
|
|
44123
|
+
show(shouldFuse);
|
|
44124
|
+
if (!shouldFuse) drawFull();
|
|
44125
|
+
},
|
|
44126
|
+
get fused() {
|
|
44127
|
+
return isFused;
|
|
44128
|
+
},
|
|
44129
|
+
dispose() {
|
|
44130
|
+
show(false);
|
|
44131
|
+
batcher?.dispose();
|
|
44132
|
+
batcher = null;
|
|
44133
|
+
for (const mesh2 of castsShadow) mesh2.castShadow = true;
|
|
44134
|
+
castsShadow.clear();
|
|
44135
|
+
shadow?.removeFromParent();
|
|
44136
|
+
shadow?.geometry.dispose();
|
|
44137
|
+
shadow = null;
|
|
44138
|
+
if (!lite) return;
|
|
44139
|
+
lite.removeFromParent();
|
|
44140
|
+
lite.traverse((object2) => object2.geometry?.dispose());
|
|
44141
|
+
lite = null;
|
|
44142
|
+
}
|
|
44143
|
+
};
|
|
44144
|
+
return api;
|
|
44145
|
+
}
|
|
44146
|
+
|
|
42932
44147
|
// src/test-area/text.ts
|
|
42933
44148
|
var scenarioIds = [
|
|
42934
44149
|
"vehicles_9mm_windshield",
|
|
@@ -43320,7 +44535,7 @@ var GameVehiclesThree = (() => {
|
|
|
43320
44535
|
];
|
|
43321
44536
|
};
|
|
43322
44537
|
|
|
43323
|
-
// ../game-audio/dist/
|
|
44538
|
+
// ../game-audio/dist/chunk-DZITVFMJ.js
|
|
43324
44539
|
var DISTANCE_CURVES = {
|
|
43325
44540
|
/** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
|
|
43326
44541
|
game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
|
|
@@ -43335,31 +44550,6 @@ var GameVehiclesThree = (() => {
|
|
|
43335
44550
|
/** The game's animal calls: `max(0, 1 − d / 70) × 0.25`, silent at or below 0.005 (jogo L66627–66628). */
|
|
43336
44551
|
animals: { model: "linear", range: 70, scale: 0.25, minGain: 5e-3 }
|
|
43337
44552
|
};
|
|
43338
|
-
var mix_profiles_default = [
|
|
43339
|
-
{
|
|
43340
|
-
id: "game",
|
|
43341
|
-
master: 0.5,
|
|
43342
|
-
noise: { seconds: 1.5, create: "lazy" },
|
|
43343
|
-
sources: ["jogo:L62077-62081 master 0.5 to the output", "jogo:L62082-62088 noise 1.5 s made by the first sound that needs it"]
|
|
43344
|
-
},
|
|
43345
|
-
{
|
|
43346
|
-
id: "art_scene",
|
|
43347
|
-
master: 0.85,
|
|
43348
|
-
compressor: { threshold: -12, ratio: 5 },
|
|
43349
|
-
reverb: { seconds: 2.2, decay: 3.4, wet: 0.4 },
|
|
43350
|
-
noise: { seconds: 2, create: "eager" },
|
|
43351
|
-
sources: [
|
|
43352
|
-
"cena:L1308 compressor -12 dB, ratio 5",
|
|
43353
|
-
"cena:L1309 master 0.85",
|
|
43354
|
-
"cena:L1310 convolver, impulse 2.2 s of (1 - i/len)^3.4",
|
|
43355
|
-
"cena:L1311 wet 0.4",
|
|
43356
|
-
"cena:L1312 noise 2 s made with the chain"
|
|
43357
|
-
]
|
|
43358
|
-
}
|
|
43359
|
-
];
|
|
43360
|
-
var MIX_PROFILES = Object.fromEntries(
|
|
43361
|
-
mix_profiles_default.map((profile) => [profile.id, profile])
|
|
43362
|
-
);
|
|
43363
44553
|
var game_sfx_default = {
|
|
43364
44554
|
sources: ["jogo:L62089-62107"],
|
|
43365
44555
|
note: "The game's sfx table P: [lowpass cutoff Hz, peak gain, seconds]. Played as a noise burst with the game's distance curve (falloff game_sfx) and a 0.05 s tail. Team names in `team`.",
|
|
@@ -43492,6 +44682,31 @@ var GameVehiclesThree = (() => {
|
|
|
43492
44682
|
var LIBRARY_SOUNDS = [horn_default, radio_static_default, siren_default];
|
|
43493
44683
|
var LIBRARY_LOOPS = [engine_saw_default, rotor_blades_default, crowd_rumble_default];
|
|
43494
44684
|
var LIBRARY_BANK = { id: "library", sounds: LIBRARY_SOUNDS, loops: LIBRARY_LOOPS };
|
|
44685
|
+
var mix_profiles_default = [
|
|
44686
|
+
{
|
|
44687
|
+
id: "game",
|
|
44688
|
+
master: 0.5,
|
|
44689
|
+
noise: { seconds: 1.5, create: "lazy" },
|
|
44690
|
+
sources: ["jogo:L62077-62081 master 0.5 to the output", "jogo:L62082-62088 noise 1.5 s made by the first sound that needs it"]
|
|
44691
|
+
},
|
|
44692
|
+
{
|
|
44693
|
+
id: "art_scene",
|
|
44694
|
+
master: 0.85,
|
|
44695
|
+
compressor: { threshold: -12, ratio: 5 },
|
|
44696
|
+
reverb: { seconds: 2.2, decay: 3.4, wet: 0.4 },
|
|
44697
|
+
noise: { seconds: 2, create: "eager" },
|
|
44698
|
+
sources: [
|
|
44699
|
+
"cena:L1308 compressor -12 dB, ratio 5",
|
|
44700
|
+
"cena:L1309 master 0.85",
|
|
44701
|
+
"cena:L1310 convolver, impulse 2.2 s of (1 - i/len)^3.4",
|
|
44702
|
+
"cena:L1311 wet 0.4",
|
|
44703
|
+
"cena:L1312 noise 2 s made with the chain"
|
|
44704
|
+
]
|
|
44705
|
+
}
|
|
44706
|
+
];
|
|
44707
|
+
var MIX_PROFILES = Object.fromEntries(
|
|
44708
|
+
mix_profiles_default.map((profile) => [profile.id, profile])
|
|
44709
|
+
);
|
|
43495
44710
|
var BENCH_BANK = {
|
|
43496
44711
|
id: "audio_bench",
|
|
43497
44712
|
sounds: [
|
|
@@ -43538,6 +44753,236 @@ var GameVehiclesThree = (() => {
|
|
|
43538
44753
|
]
|
|
43539
44754
|
};
|
|
43540
44755
|
|
|
44756
|
+
// ../game-audio/dist/index.js
|
|
44757
|
+
var ATTACK = 2e-3;
|
|
44758
|
+
function lengthOf(d, attack) {
|
|
44759
|
+
if (typeof d === "number") return attack + d;
|
|
44760
|
+
if (Array.isArray(d)) return [attack + d[0], attack + d[1]];
|
|
44761
|
+
return { ...d, add: (d.add ?? 0) + attack };
|
|
44762
|
+
}
|
|
44763
|
+
var envelope = (attack) => [
|
|
44764
|
+
[0, 1e-4, "set", "fixed"],
|
|
44765
|
+
[attack, 1, "exp"],
|
|
44766
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
44767
|
+
];
|
|
44768
|
+
function sceneNoise(o) {
|
|
44769
|
+
const a = o.a ?? ATTACK;
|
|
44770
|
+
const over = typeof o.d === "number" ? o.d : 0;
|
|
44771
|
+
return {
|
|
44772
|
+
filters: {
|
|
44773
|
+
mode: "serial",
|
|
44774
|
+
bank: [{ type: o.type ?? "lowpass", frequency: o.f2 === void 0 ? { set: o.f } : { set: o.f, to: o.f2, curve: "exp", over }, q: o.q ?? 0.7 }]
|
|
44775
|
+
},
|
|
44776
|
+
duration: lengthOf(o.d, a),
|
|
44777
|
+
gain: o.vol,
|
|
44778
|
+
...o.delay === void 0 ? {} : { at: o.delay },
|
|
44779
|
+
...o.wet === void 0 ? {} : { wet: o.wet },
|
|
44780
|
+
source: { kind: "noise", offset: "random", offsetScale: 1.5, loop: true },
|
|
44781
|
+
envelope: envelope(a)
|
|
44782
|
+
};
|
|
44783
|
+
}
|
|
44784
|
+
function sceneTone(o) {
|
|
44785
|
+
return {
|
|
44786
|
+
source: { kind: "osc", wave: o.wave ?? "sine", frequency: { from: o.f, to: o.f2 ?? "from", curve: "exp", over: "duration" } },
|
|
44787
|
+
duration: lengthOf(o.d, ATTACK),
|
|
44788
|
+
gain: o.vol,
|
|
44789
|
+
...o.delay === void 0 ? {} : { at: o.delay },
|
|
44790
|
+
...o.wet === void 0 ? {} : { wet: o.wet },
|
|
44791
|
+
envelope: envelope(ATTACK)
|
|
44792
|
+
};
|
|
44793
|
+
}
|
|
44794
|
+
function sceneVoice(o) {
|
|
44795
|
+
return {
|
|
44796
|
+
duration: lengthOf(o.d, 0),
|
|
44797
|
+
gain: o.vol,
|
|
44798
|
+
wet: 0.45,
|
|
44799
|
+
source: {
|
|
44800
|
+
kind: "formant_voice",
|
|
44801
|
+
wave: o.wave ?? "sawtooth",
|
|
44802
|
+
frequency: { from: o.f0, to: o.f1, curve: "linear", over: "duration" },
|
|
44803
|
+
vibrato: { rate: [4, 10], depth: 0.08 },
|
|
44804
|
+
formants: [
|
|
44805
|
+
{ frequency: o.fA, q: 4 },
|
|
44806
|
+
{ frequency: o.fB, q: 6 }
|
|
44807
|
+
],
|
|
44808
|
+
breath: { frequency: o.fB, q: 1.1, gain: o.noise },
|
|
44809
|
+
mix: 3.2
|
|
44810
|
+
},
|
|
44811
|
+
envelope: [
|
|
44812
|
+
[0, 1e-4, "set", "fixed"],
|
|
44813
|
+
[0.1, 1, "exp"],
|
|
44814
|
+
["0.6d", 1, "set"],
|
|
44815
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
44816
|
+
]
|
|
44817
|
+
};
|
|
44818
|
+
}
|
|
44819
|
+
var TAKES = [
|
|
44820
|
+
{ f: 1, t: 1, v: 1 },
|
|
44821
|
+
{ f: 1.08, t: 0.9, v: 0.92 },
|
|
44822
|
+
{ f: 0.93, t: 1.12, v: 1.05 },
|
|
44823
|
+
{ f: 1.03, t: 1.05, v: 0.88 }
|
|
44824
|
+
];
|
|
44825
|
+
var FOOTSTEP_FALLOFF = { model: "inverse_square", k: 0.03, cutoffK: 0.03, minGain: 4e-3 };
|
|
44826
|
+
var BODY_FALLOFF = { model: "inverse_square", k: 0.012, cutoffK: 0.015, minGain: 4e-3 };
|
|
44827
|
+
var SURFACES = {
|
|
44828
|
+
concrete: { heel: { f: 95, d: 0.05, vol: 0.55 }, roll: { type: "bandpass", f: 2300, q: 1.1, d: 0.05, vol: 0.38 }, grains: { count: 2, f: 4200, q: 2, spread: 0.04, vol: 0.08 } },
|
|
44829
|
+
asphalt: { heel: { f: 90, d: 0.05, vol: 0.5 }, roll: { type: "bandpass", f: 1700, q: 0.9, d: 0.06, vol: 0.36 }, grains: { count: 4, f: 3600, q: 2.5, spread: 0.06, vol: 0.1 } },
|
|
44830
|
+
wood: { heel: { f: 130, d: 0.08, vol: 0.55 }, roll: { type: "lowpass", f: 1300, q: 0.8, d: 0.06, vol: 0.3 }, ring: [{ f: 210, d: 0.1, vol: 0.18 }, { f: 470, d: 0.06, vol: 0.06 }] },
|
|
44831
|
+
tile: { heel: { f: 110, d: 0.04, vol: 0.45 }, roll: { type: "bandpass", f: 3600, q: 2, d: 0.03, vol: 0.42 }, ring: [{ f: 1900, d: 0.03, vol: 0.05 }] },
|
|
44832
|
+
dirt: { heel: { f: 75, d: 0.06, vol: 0.45 }, roll: { type: "lowpass", f: 750, q: 0.7, d: 0.09, vol: 0.4 }, grains: { count: 3, f: 1800, q: 1.5, spread: 0.07, vol: 0.06 } },
|
|
44833
|
+
grass: { heel: { f: 70, d: 0.05, vol: 0.32 }, roll: { type: "highpass", f: 2600, q: 0.7, d: 0.13, vol: 0.28 }, grains: { count: 4, f: 5200, q: 1.2, spread: 0.1, vol: 0.07 } },
|
|
44834
|
+
gravel: { heel: { f: 80, d: 0.05, vol: 0.4 }, roll: { type: "lowpass", f: 950, q: 0.8, d: 0.1, vol: 0.3 }, grains: { count: 8, f: 2600, q: 3, spread: 0.13, vol: 0.2 } },
|
|
44835
|
+
sand: { heel: { f: 65, d: 0.06, vol: 0.3 }, roll: { type: "bandpass", f: 1500, q: 0.6, d: 0.16, vol: 0.3 }, grains: { count: 5, f: 4800, q: 1.5, spread: 0.12, vol: 0.05 } },
|
|
44836
|
+
metal: { heel: { f: 120, d: 0.05, vol: 0.5 }, roll: { type: "bandpass", f: 2800, q: 1.5, d: 0.03, vol: 0.25 }, ring: [{ f: 420, d: 0.25, vol: 0.16 }, { f: 1130, d: 0.18, vol: 0.09 }, { f: 2470, d: 0.1, vol: 0.04 }] },
|
|
44837
|
+
water: { heel: { f: 70, d: 0.04, vol: 0.25 }, roll: { type: "bandpass", f: 3e3, q: 1.2, d: 0.1, vol: 0.18 }, splash: { f: 1100, f2: 380, d: 0.22, vol: 0.55 }, grains: { count: 4, f: 2400, q: 6, spread: 0.18, vol: 0.12 } },
|
|
44838
|
+
glass: { heel: { f: 90, d: 0.04, vol: 0.4 }, roll: { type: "highpass", f: 4500, q: 0.8, d: 0.06, vol: 0.2 }, grains: { count: 9, f: 6200, q: 5, spread: 0.12, vol: 0.22 }, ring: [{ f: 3900, d: 0.04, vol: 0.04 }, { f: 5300, d: 0.03, vol: 0.03 }] },
|
|
44839
|
+
carpet: { heel: { f: 70, d: 0.05, vol: 0.32 }, roll: { type: "lowpass", f: 420, q: 0.7, d: 0.07, vol: 0.3 } }
|
|
44840
|
+
};
|
|
44841
|
+
var GAITS = {
|
|
44842
|
+
walk: { vol: 1, bright: 1, toe: 0.075, short: 1 },
|
|
44843
|
+
run: { vol: 1.35, bright: 1.25, toe: 0.035, short: 0.75 }
|
|
44844
|
+
};
|
|
44845
|
+
var grainLayers = (g, take, start2, scale) => Array.from(
|
|
44846
|
+
{ length: g.count },
|
|
44847
|
+
(_, i) => sceneNoise({ type: "bandpass", f: [g.f * take.f * 0.85, g.f * take.f * 1.15], q: g.q, d: [8e-3, 0.02], vol: g.vol * scale * take.v, delay: start2 + (i + 0.5) / g.count * g.spread * take.t })
|
|
44848
|
+
);
|
|
44849
|
+
var ringLayers = (rings, take, scale, at = 0) => rings.map((r) => sceneTone({ f: r.f * take.f, d: r.d * take.t, vol: r.vol * scale * take.v, delay: at }));
|
|
44850
|
+
function footLayers(surface, take, gait, weight = 1) {
|
|
44851
|
+
const s = SURFACES[surface];
|
|
44852
|
+
const toe = gait.toe * take.t;
|
|
44853
|
+
return [
|
|
44854
|
+
sceneTone({ f: s.heel.f * take.f * weight ** -0.3, f2: s.heel.f * take.f * 0.6, d: s.heel.d * gait.short * take.t * weight ** 0.5, vol: s.heel.vol * gait.vol * take.v * weight ** 0.5 }),
|
|
44855
|
+
sceneNoise({ type: "lowpass", f: 500 * gait.bright, d: 0.02 * take.t, vol: 0.18 * gait.vol * take.v * weight ** 0.5 }),
|
|
44856
|
+
sceneNoise({ type: s.roll.type, f: [s.roll.f * take.f * gait.bright * 0.92, s.roll.f * take.f * gait.bright * 1.08], q: s.roll.q, d: s.roll.d * gait.short * take.t * weight ** 0.3, vol: s.roll.vol * gait.vol * take.v, delay: toe }),
|
|
44857
|
+
...s.grains ? grainLayers(s.grains, take, toe * 0.5, gait.vol * weight ** 0.5) : [],
|
|
44858
|
+
...s.ring ? ringLayers(s.ring, take, gait.vol * weight ** 0.5) : [],
|
|
44859
|
+
...s.splash ? [sceneNoise({ type: "bandpass", f: s.splash.f * take.f, f2: s.splash.f2 * take.f, q: 1.4, d: s.splash.d * take.t * weight ** 0.4, vol: s.splash.vol * gait.vol * take.v * weight ** 0.5 })] : []
|
|
44860
|
+
];
|
|
44861
|
+
}
|
|
44862
|
+
var quieter = (level, layers) => layers.map((layer) => {
|
|
44863
|
+
const gain = layer.gain ?? 1;
|
|
44864
|
+
if (typeof gain === "number") return { ...layer, gain: gain * level };
|
|
44865
|
+
if (Array.isArray(gain)) return { ...layer, gain: [gain[0] * level, gain[1] * level] };
|
|
44866
|
+
return layer;
|
|
44867
|
+
});
|
|
44868
|
+
var recipe = (id, layers, falloff, bus = "world") => ({ id, bus, pan: true, layers, falloff, sources: ["sdk"] });
|
|
44869
|
+
var takeId = (id, index) => `${id}_${String(index + 1).padStart(2, "0")}`;
|
|
44870
|
+
function takes(id, layersOf, falloff, rate = [0.96, 1.04], bus) {
|
|
44871
|
+
const sounds = TAKES.map((take, index) => recipe(takeId(id, index), layersOf(take, index), falloff, bus));
|
|
44872
|
+
return { sounds, set: { id, variants: sounds.map((sound) => sound.id), rate } };
|
|
44873
|
+
}
|
|
44874
|
+
var footstep = (surface, gait) => takes(footstepSoundId(surface, gait), (take) => footLayers(surface, take, GAITS[gait]), FOOTSTEP_FALLOFF);
|
|
44875
|
+
var LANDINGS = { light: { weight: 1.4, cloth: 0.12 }, heavy: { weight: 2.4, cloth: 0.22 } };
|
|
44876
|
+
var LANDING_LEVEL = 0.65;
|
|
44877
|
+
var landing = (surface, landing2) => takes(
|
|
44878
|
+
`land_${surface}_${landing2}`,
|
|
44879
|
+
(take) => quieter(LANDING_LEVEL, [
|
|
44880
|
+
// both feet, a hair apart, then the knees taking the weight (a low body thump) and the clothes settling
|
|
44881
|
+
...footLayers(surface, take, GAITS.run, LANDINGS[landing2].weight),
|
|
44882
|
+
...footLayers(surface, { ...take, v: take.v * 0.6 }, GAITS.run, LANDINGS[landing2].weight * 0.6).map((layer) => ({ ...layer, at: (typeof layer.at === "number" ? layer.at : 0) + 0.018 * take.t })),
|
|
44883
|
+
sceneTone({ f: 60 * take.f, f2: 38, d: 0.14 * LANDINGS[landing2].weight * take.t, vol: 0.22 * LANDINGS[landing2].weight ** 0.7 * take.v, delay: 0.02 }),
|
|
44884
|
+
sceneNoise({ type: "bandpass", f: [1800, 2600], q: 0.8, d: 0.18, vol: LANDINGS[landing2].cloth * take.v, delay: 0.04 })
|
|
44885
|
+
]),
|
|
44886
|
+
FOOTSTEP_FALLOFF
|
|
44887
|
+
);
|
|
44888
|
+
var whoosh = (blow, from, to, d, vol, q = 1.6) => (take) => [
|
|
44889
|
+
// the air: a band sweeping up as the limb speeds up; it peaks `SWING_LEAD_SECONDS` in, the moment before the contact, then dies away
|
|
44890
|
+
sceneNoise({ type: "bandpass", f: from * take.f, f2: to * take.f, q, a: SWING_LEAD_SECONDS[blow], d: d * take.t, vol: vol * take.v }),
|
|
44891
|
+
sceneNoise({ type: "lowpass", f: 600 * take.f, a: SWING_LEAD_SECONDS[blow], d: d * take.t * 0.8, vol: vol * 0.35 * take.v })
|
|
44892
|
+
];
|
|
44893
|
+
var fleshHit = (o) => (take) => [
|
|
44894
|
+
sceneNoise({ type: "bandpass", f: o.slapF * take.f, q: 1.2, d: 0.03 * take.t, vol: o.slap * take.v }),
|
|
44895
|
+
sceneNoise({ type: "highpass", f: 3500 * take.f, d: 0.012, vol: o.slap * 0.4 * take.v }),
|
|
44896
|
+
sceneTone({ f: o.thudF * take.f, f2: o.thudF * 0.5, d: o.thudD * take.t, vol: o.thud * take.v }),
|
|
44897
|
+
sceneNoise({ type: "lowpass", f: 600 * take.f, d: o.thudD * 1.2 * take.t, vol: o.thud * 0.5 * take.v }),
|
|
44898
|
+
...o.crack ? [sceneNoise({ type: "highpass", f: 2500, d: 0.015, vol: o.crack * take.v, delay: 6e-3 }), sceneTone({ wave: "square", f: 900 * take.f, f2: 300, d: 0.02, vol: o.crack * 0.15 * take.v, delay: 6e-3 })] : [],
|
|
44899
|
+
...o.wet ? [sceneNoise({ type: "bandpass", f: 1400 * take.f, f2: 500, q: 2.5, d: 0.12 * take.t, vol: o.wet * take.v, delay: 0.01 })] : []
|
|
44900
|
+
];
|
|
44901
|
+
var knock = (o) => (take) => [
|
|
44902
|
+
sceneNoise({ type: "bandpass", f: o.clickF * take.f, q: 1.5, d: 0.018, vol: o.click * take.v }),
|
|
44903
|
+
...o.tones.map(([f, d, vol]) => sceneTone({ f: f * take.f, d: d * take.t, vol: vol * take.v }))
|
|
44904
|
+
];
|
|
44905
|
+
var voice = (o) => (take) => [
|
|
44906
|
+
sceneVoice({ f0: o.f0 * take.f, f1: o.f1 * take.f, d: o.d * take.t, fA: o.fA * take.f, fB: o.fB * take.f, noise: o.noise, vol: o.vol * take.v })
|
|
44907
|
+
];
|
|
44908
|
+
var BODY = {
|
|
44909
|
+
jump: (take) => [
|
|
44910
|
+
sceneNoise({ type: "bandpass", f: 900 * take.f, f2: 1700 * take.f, q: 1, a: 0.03, d: 0.12, vol: 0.18 * take.v }),
|
|
44911
|
+
sceneNoise({ type: "bandpass", f: 2200 * take.f, q: 0.8, d: 0.04, vol: 0.12 * take.v }),
|
|
44912
|
+
sceneTone({ f: 85 * take.f, f2: 60, d: 0.04, vol: 0.2 * take.v })
|
|
44913
|
+
],
|
|
44914
|
+
cloth_rustle: (take) => [
|
|
44915
|
+
{ ...sceneNoise({ type: "bandpass", f: 2400 * take.f, q: 0.8, a: 0.06, d: 0.22 * take.t, vol: 0.12 * take.v }), modulators: [{ target: "gain", wave: "triangle", rate: [9, 14], depth: 0.5 }] }
|
|
44916
|
+
],
|
|
44917
|
+
body_fall: (take) => [
|
|
44918
|
+
sceneTone({ f: 58 * take.f, f2: 35, d: 0.28 * take.t, vol: 0.9 * take.v }),
|
|
44919
|
+
sceneNoise({ type: "lowpass", f: 480 * take.f, d: 0.3 * take.t, vol: 0.55 * take.v }),
|
|
44920
|
+
sceneNoise({ type: "bandpass", f: 1300 * take.f, q: 1, d: 0.05, vol: 0.3 * take.v }),
|
|
44921
|
+
// the limbs a moment later, and the clothes
|
|
44922
|
+
sceneTone({ f: 75 * take.f, f2: 45, d: 0.12, vol: 0.4 * take.v, delay: 0.13 * take.t }),
|
|
44923
|
+
sceneNoise({ type: "bandpass", f: 2200, q: 0.8, d: 0.2, vol: 0.12 * take.v, delay: 0.05 })
|
|
44924
|
+
],
|
|
44925
|
+
fall_damage: (take) => [
|
|
44926
|
+
...BODY.body_fall(take),
|
|
44927
|
+
sceneNoise({ type: "highpass", f: 2800, d: 0.02, vol: 0.35 * take.v, delay: 0.01 }),
|
|
44928
|
+
...voice({ f0: 170, f1: 110, d: 0.32, fA: 650, fB: 1150, noise: 0.25, vol: 0.32 })(take).map((layer) => ({ ...layer, at: 0.08 }))
|
|
44929
|
+
],
|
|
44930
|
+
player_hurt: voice({ f0: 150, f1: 105, d: 0.26, fA: 620, fB: 1100, noise: 0.3, vol: 0.35 }),
|
|
44931
|
+
player_breath_run: (take) => [
|
|
44932
|
+
sceneNoise({ type: "bandpass", f: 1200 * take.f, q: 1, a: 0.08, d: 0.22 * take.t, vol: 0.25 * take.v }),
|
|
44933
|
+
sceneNoise({ type: "bandpass", f: 900 * take.f, q: 1, a: 0.06, d: 0.26 * take.t, vol: 0.3 * take.v, delay: 0.3 * take.t })
|
|
44934
|
+
],
|
|
44935
|
+
player_death: voice({ f0: 135, f1: 68, d: 1, fA: 560, fB: 980, noise: 0.35, vol: 0.4 }),
|
|
44936
|
+
bite: (take) => [
|
|
44937
|
+
sceneNoise({ type: "highpass", f: 2600, d: 0.015, vol: 0.4 * take.v }),
|
|
44938
|
+
sceneNoise({ type: "bandpass", f: 1600 * take.f, f2: 450, q: 2.2, d: 0.16 * take.t, vol: 0.55 * take.v, delay: 0.01 }),
|
|
44939
|
+
sceneNoise({ type: "bandpass", f: 3200 * take.f, f2: 1800, q: 1.2, d: 0.22 * take.t, vol: 0.25 * take.v, delay: 0.09 }),
|
|
44940
|
+
sceneTone({ f: 120 * take.f, f2: 70, d: 0.06, vol: 0.3 * take.v })
|
|
44941
|
+
],
|
|
44942
|
+
grab: (take) => [
|
|
44943
|
+
sceneNoise({ type: "bandpass", f: 1900 * take.f, q: 0.9, a: 4e-3, d: 0.13 * take.t, vol: 0.32 * take.v }),
|
|
44944
|
+
sceneTone({ f: 95 * take.f, f2: 60, d: 0.07, vol: 0.3 * take.v }),
|
|
44945
|
+
sceneNoise({ type: "lowpass", f: 700, d: 0.08, vol: 0.2 * take.v })
|
|
44946
|
+
],
|
|
44947
|
+
punch_swing: whoosh("punch", 450, 1500, 0.16, 0.9),
|
|
44948
|
+
punch_hit_body: fleshHit({ slap: 0.55, slapF: 1500, thud: 0.6, thudF: 115, thudD: 0.09 }),
|
|
44949
|
+
punch_hit_face: fleshHit({ slap: 0.75, slapF: 2300, thud: 0.45, thudF: 150, thudD: 0.07, crack: 0.25 }),
|
|
44950
|
+
punch_hit_object: knock({ clickF: 1800, click: 0.3, tones: [[210, 0.04, 0.25]] }),
|
|
44951
|
+
kick_swing: whoosh("kick", 280, 950, 0.22, 1, 1.3),
|
|
44952
|
+
kick_hit: fleshHit({ slap: 0.45, slapF: 1100, thud: 0.85, thudF: 82, thudD: 0.14 }),
|
|
44953
|
+
kick_hit_object: knock({ clickF: 1e3, click: 0.3, tones: [[92, 0.08, 0.5]] }),
|
|
44954
|
+
shove_two_hands: (take) => [
|
|
44955
|
+
sceneNoise({ type: "bandpass", f: 950 * take.f, q: 0.9, a: 0.01, d: 0.13 * take.t, vol: 0.38 * take.v }),
|
|
44956
|
+
sceneTone({ f: 100 * take.f, f2: 60, d: 0.1 * take.t, vol: 0.45 * take.v }),
|
|
44957
|
+
sceneNoise({ type: "bandpass", f: 2300, q: 0.8, d: 0.16, vol: 0.12 * take.v, delay: 0.03 })
|
|
44958
|
+
],
|
|
44959
|
+
knife_swing: whoosh("blade", 1900, 4600, 0.12, 1.1, 2.2),
|
|
44960
|
+
knife_stab: fleshHit({ slap: 0.2, slapF: 1200, thud: 0.4, thudF: 160, thudD: 0.06, wet: 0.5 }),
|
|
44961
|
+
knife_slash: (take) => [
|
|
44962
|
+
sceneNoise({ type: "highpass", f: 3200 * take.f, f2: 1800, d: 0.13 * take.t, vol: 0.35 * take.v }),
|
|
44963
|
+
sceneNoise({ type: "bandpass", f: 1300 * take.f, f2: 600, q: 2.5, d: 0.12 * take.t, vol: 0.35 * take.v, delay: 0.02 })
|
|
44964
|
+
],
|
|
44965
|
+
knife_hit_object: knock({ clickF: 3200, click: 0.25, tones: [[2800, 0.08, 0.07], [4150, 0.06, 0.05]] }),
|
|
44966
|
+
blunt_swing: whoosh("blunt", 220, 760, 0.28, 1.1, 1.5),
|
|
44967
|
+
blunt_hit: fleshHit({ slap: 0.35, slapF: 900, thud: 1, thudF: 70, thudD: 0.18, crack: 0.3 }),
|
|
44968
|
+
blunt_hit_object: knock({ clickF: 1400, click: 0.35, tones: [[300, 0.12, 0.25], [760, 0.08, 0.12]] }),
|
|
44969
|
+
axe_swing: whoosh("chop", 190, 620, 0.3, 1.2, 1.4),
|
|
44970
|
+
axe_chop: fleshHit({ slap: 0.3, slapF: 1400, thud: 0.75, thudF: 140, thudD: 0.1, crack: 0.35, wet: 0.45 }),
|
|
44971
|
+
axe_hit_object: knock({ clickF: 2200, click: 0.4, tones: [[1500, 0.15, 0.1], [2300, 0.1, 0.06], [140, 0.1, 0.35]] })
|
|
44972
|
+
};
|
|
44973
|
+
var BODY_BUS = { player_hurt: "voices", player_death: "voices", player_breath_run: "voices", fall_damage: "voices" };
|
|
44974
|
+
var built = [
|
|
44975
|
+
...SURFACE_IDS.flatMap((surface) => GAIT_IDS.map((gait) => footstep(surface, gait))),
|
|
44976
|
+
...SURFACE_IDS.flatMap((surface) => LANDING_IDS.map((l) => landing(surface, l))),
|
|
44977
|
+
...BODY_SOUND_IDS.map((id) => takes(id, BODY[id], BODY_FALLOFF, id.endsWith("_swing") ? [0.94, 1.06] : [0.96, 1.04], BODY_BUS[id]))
|
|
44978
|
+
];
|
|
44979
|
+
var BODY_FOLEY_BANK = {
|
|
44980
|
+
id: "body_foley",
|
|
44981
|
+
sounds: built.flatMap((entry) => entry.sounds),
|
|
44982
|
+
sets: built.map((entry) => entry.set)
|
|
44983
|
+
};
|
|
44984
|
+
var BODY_FOLEY_SET_IDS = [...FOOTSTEP_SOUND_IDS, ...LAND_SOUND_IDS, ...BODY_SOUND_IDS];
|
|
44985
|
+
|
|
43541
44986
|
// src/test-area/types.ts
|
|
43542
44987
|
var defaultEffectIds = {
|
|
43543
44988
|
ignite: "vehicle_fire",
|
|
@@ -43560,10 +45005,12 @@ var GameVehiclesThree = (() => {
|
|
|
43560
45005
|
var ITEM_OF = { compact_hatch: "hatch", midsize_sedan: "sedan", midsize_pickup: "pickup", sport_bike: "sport_bike", box_truck: "box_truck", city_bus: "city_bus", battle_tank: "battle_tank", attack_helicopter: "attack_helicopter" };
|
|
43561
45006
|
var itemId = (key) => ITEM_OF[key] ?? key;
|
|
43562
45007
|
var LANE = { z: 11, from: -12, wall: 13 };
|
|
45008
|
+
var LEAF_REST_RADIANS = 0.02;
|
|
43563
45009
|
var MATERIAL_COLOURS = { metal: 13421772, glass: 4500223, rubber: 16750848, fuel: 16724736 };
|
|
43564
45010
|
var ZONE_COLOURS = { door: 5627221, hood: 14540083, lid: 14522675, bumper: 14505437, glass: 4500223, light: 16777215, wheel: 16742195 };
|
|
43565
45011
|
var BODY_HEIGHT = 1.7;
|
|
43566
45012
|
function createVehiclesTestModule(options = {}) {
|
|
45013
|
+
const fleet = options.fleet ?? { colorFromSeed, fleetDims, installFleet, paintPalettes, paletteOf };
|
|
43567
45014
|
const locale = options.locale ?? "pt-BR";
|
|
43568
45015
|
const text = TEXT[locale] ?? TEXT["pt-BR"];
|
|
43569
45016
|
const keys = options.vehicles ?? DEFAULT_TEST_VEHICLES;
|
|
@@ -43588,23 +45035,29 @@ var GameVehiclesThree = (() => {
|
|
|
43588
45035
|
engineLoop?.stop();
|
|
43589
45036
|
engineLoop = void 0;
|
|
43590
45037
|
};
|
|
45038
|
+
const particleMaterials = {
|
|
45039
|
+
own: (build) => isRenderPools(host?.pools) ? host.pools.materials.own(build) : build(),
|
|
45040
|
+
release: (material) => isRenderPools(host?.pools) ? host.pools.materials.release(material) : material.dispose?.()
|
|
45041
|
+
};
|
|
43591
45042
|
const kitFor = (THREE) => {
|
|
43592
45043
|
three = THREE;
|
|
43593
45044
|
let kit = kits.get(THREE);
|
|
43594
45045
|
if (!kit) {
|
|
43595
45046
|
if (options.createKit) kit = options.createKit(THREE);
|
|
43596
45047
|
else {
|
|
43597
|
-
kit = createVehicleKit({ THREE, locale, ...options.document ? { document: options.document } : {} });
|
|
43598
|
-
installFleet(kit);
|
|
45048
|
+
kit = createVehicleKit({ THREE, locale, particleMaterials, effects: () => host?.effects, ...options.document ? { document: options.document } : {} });
|
|
45049
|
+
fleet.installFleet(kit);
|
|
43599
45050
|
}
|
|
43600
45051
|
kits.set(THREE, kit);
|
|
43601
45052
|
}
|
|
43602
45053
|
return kit;
|
|
43603
45054
|
};
|
|
43604
|
-
const paletteFor = (key) => settings.palette === "civil" ? paintPalettes.civil : settings.palette === "military" ? paintPalettes.military : paletteOf(key);
|
|
45055
|
+
const paletteFor = (key) => settings.palette === "civil" ? fleet.paintPalettes.civil : settings.palette === "military" ? fleet.paintPalettes.military : fleet.paletteOf(key);
|
|
43605
45056
|
const paintOf = (entry) => {
|
|
43606
45057
|
if (!settings.paint) return;
|
|
43607
|
-
|
|
45058
|
+
entry.lod?.dispose();
|
|
45059
|
+
delete entry.lod;
|
|
45060
|
+
const color2 = fleet.colorFromSeed(settings.seed + entry.index, paletteFor(entry.key));
|
|
43608
45061
|
if (!entry.paint) {
|
|
43609
45062
|
const vehicle = entry.item.vehicle;
|
|
43610
45063
|
const primary = primaryPaint(entry.item.vehicle);
|
|
@@ -43626,19 +45079,40 @@ var GameVehiclesThree = (() => {
|
|
|
43626
45079
|
slow: true,
|
|
43627
45080
|
build: (THREE) => {
|
|
43628
45081
|
const kit = kitFor(THREE);
|
|
43629
|
-
const
|
|
43630
|
-
|
|
43631
|
-
const entry = { root:
|
|
43632
|
-
placed.set(
|
|
45082
|
+
const built2 = buildVehicleItem(kit, key, { lod: settings.quality === "lite", ...scenario ? { scenario } : {} });
|
|
45083
|
+
built2.root.userData.kit = kit;
|
|
45084
|
+
const entry = { root: built2.root, key, ...scenario ? { scenario } : {}, item: built2, index: counter++, helpers: [] };
|
|
45085
|
+
placed.set(built2.root.uuid, entry);
|
|
43633
45086
|
measure(entry);
|
|
43634
45087
|
paintOf(entry);
|
|
43635
|
-
return
|
|
45088
|
+
return built2.root;
|
|
43636
45089
|
},
|
|
43637
45090
|
impl: (root, id) => {
|
|
43638
45091
|
const r = root;
|
|
43639
45092
|
const kit = r.userData.kit;
|
|
43640
|
-
const d = createVehicleDestructible(kit, r.userData.vehicle, { id, frame: root, name: text.items[itemKey] ?? key });
|
|
45093
|
+
const d = createVehicleDestructible(kit, r.userData.vehicle, { id, frame: root, name: text.items[itemKey] ?? key, creaseQueue });
|
|
43641
45094
|
tapEffects(d);
|
|
45095
|
+
const setPartPose = d.setPartPose?.bind(d);
|
|
45096
|
+
{
|
|
45097
|
+
const rests = new Map(d.describe().parts.map((part) => [part.id, part.rotation ?? [0, 0, 0]]));
|
|
45098
|
+
d.setPartPose = (partId, position, rotation) => {
|
|
45099
|
+
const entry = [...placed.values()].find((candidate) => candidate.root === root);
|
|
45100
|
+
const rest = rests.get(partId) ?? [0, 0, 0];
|
|
45101
|
+
const isOpen = (rotation ?? [0, 0, 0]).some((angle, axis) => Math.abs(angle - (rest[axis] ?? 0)) > LEAF_REST_RADIANS);
|
|
45102
|
+
if (entry) {
|
|
45103
|
+
entry.posedParts ?? (entry.posedParts = /* @__PURE__ */ new Set());
|
|
45104
|
+
if (isOpen) entry.posedParts.add(partId);
|
|
45105
|
+
else entry.posedParts.delete(partId);
|
|
45106
|
+
}
|
|
45107
|
+
return setPartPose?.(partId, position, rotation);
|
|
45108
|
+
};
|
|
45109
|
+
}
|
|
45110
|
+
const hitBody = d.hit.bind(d);
|
|
45111
|
+
d.hit = (h) => {
|
|
45112
|
+
const entry = [...placed.values()].find((candidate) => candidate.root === root);
|
|
45113
|
+
if (entry) entry.touched = true;
|
|
45114
|
+
return hitBody(h);
|
|
45115
|
+
};
|
|
43642
45116
|
cabins.track(id, d, root);
|
|
43643
45117
|
r.userData.destructible = d;
|
|
43644
45118
|
return d;
|
|
@@ -43651,10 +45125,10 @@ var GameVehiclesThree = (() => {
|
|
|
43651
45125
|
if (!THREE) return void 0;
|
|
43652
45126
|
if (!clipCache.has(key)) {
|
|
43653
45127
|
const kit = kitFor(THREE);
|
|
43654
|
-
const
|
|
43655
|
-
const d = createVehicleDestructible(kit,
|
|
45128
|
+
const built2 = buildVehicleItem(kit, key);
|
|
45129
|
+
const d = createVehicleDestructible(kit, built2.vehicle, { id: `${itemId(key)}_clips`, frame: built2.root, headless: true });
|
|
43656
45130
|
clipCache.set(key, d.animations());
|
|
43657
|
-
kit.dispose(
|
|
45131
|
+
kit.dispose(built2.vehicle);
|
|
43658
45132
|
}
|
|
43659
45133
|
return clipCache.get(key);
|
|
43660
45134
|
};
|
|
@@ -43779,33 +45253,33 @@ var GameVehiclesThree = (() => {
|
|
|
43779
45253
|
if (!host || !three) return;
|
|
43780
45254
|
clearLane();
|
|
43781
45255
|
const kit = kitFor(three);
|
|
43782
|
-
const vehicles = createVehiclesThree(three, { kit });
|
|
43783
|
-
const
|
|
45256
|
+
const vehicles = createVehiclesThree(three, { kit, fleet });
|
|
45257
|
+
const built2 = vehicles.build("compact_hatch", { quality: "lite", seed: settings.seed });
|
|
43784
45258
|
const wall = new three.Mesh(new three.BoxGeometry(0.6, 2, 6), new three.MeshStandardMaterial({ color: 7829367 }));
|
|
43785
45259
|
wall.position.set(LANE.wall + 0.3, 1, LANE.z);
|
|
43786
45260
|
const scene = host.scene;
|
|
43787
|
-
scene.add(
|
|
45261
|
+
scene.add(built2.group, wall);
|
|
43788
45262
|
const mode = settings.driving === "semi" ? "semi" : "arcade";
|
|
43789
45263
|
const surfaces = createSurfaces();
|
|
43790
45264
|
const idle = { throttle: 0, brake: 0, steer: 0, handbrake: false };
|
|
43791
45265
|
const state = { time: 0, exhaust: 0, ended: false, wasBlocked: false };
|
|
43792
|
-
const arcade = createArcadeDriver({ length:
|
|
45266
|
+
const arcade = createArcadeDriver({ length: built2.length, width: built2.width });
|
|
43793
45267
|
const semi = createSemiSimDriver({}, { surfaces });
|
|
43794
45268
|
const driver = mode === "semi" ? semi : arcade;
|
|
43795
45269
|
driver.place(LANE.from, LANE.z, 0);
|
|
43796
|
-
const gap = () => LANE.wall - (driver.state.x +
|
|
45270
|
+
const gap = () => LANE.wall - (driver.state.x + built2.length / 2);
|
|
43797
45271
|
const decel = () => mode === "semi" ? 9 * surfaces.get(settings.surface).grip : arcade.spec.brakeAgainstMotion;
|
|
43798
45272
|
const brakeAt = () => lane ? lane.speed() * lane.speed() / (2 * decel()) + 3 : 3;
|
|
43799
45273
|
const pose = () => {
|
|
43800
|
-
|
|
43801
|
-
|
|
45274
|
+
built2.group.position.set(driver.state.x, 0, driver.state.z);
|
|
45275
|
+
built2.group.rotation.y = driver.state.yaw + Math.PI / 2;
|
|
43802
45276
|
};
|
|
43803
45277
|
pose();
|
|
43804
45278
|
engineLoop = audio()?.loop?.(soundIds.engine, { position: [driver.state.x, 0.5, driver.state.z] });
|
|
43805
45279
|
const log = (key, value) => host?.log(fill(text, locale, text.lane[key], value.toFixed(1)));
|
|
43806
45280
|
lane = {
|
|
43807
|
-
car:
|
|
43808
|
-
group:
|
|
45281
|
+
car: built2,
|
|
45282
|
+
group: built2.group,
|
|
43809
45283
|
wall,
|
|
43810
45284
|
mode,
|
|
43811
45285
|
done: false,
|
|
@@ -43841,7 +45315,7 @@ var GameVehiclesThree = (() => {
|
|
|
43841
45315
|
const fx = effects();
|
|
43842
45316
|
if (fx && state.exhaust <= 0 && Math.abs(lane?.speed() ?? 0) > 0.5) {
|
|
43843
45317
|
state.exhaust = 0.4;
|
|
43844
|
-
fx.play({ effect: effectIds.exhaust, point: [driver.state.x - Math.cos(driver.state.yaw) * (
|
|
45318
|
+
fx.play({ effect: effectIds.exhaust, point: [driver.state.x - Math.cos(driver.state.yaw) * (built2.length / 2), 0.3, driver.state.z + Math.sin(driver.state.yaw) * (built2.length / 2)], scale: Math.min(1, Math.abs(lane?.speed() ?? 0) / 17) });
|
|
43845
45319
|
}
|
|
43846
45320
|
if (!state.ended && state.time > 1 && Math.abs(lane?.speed() ?? 0) < 0.05) {
|
|
43847
45321
|
state.ended = true;
|
|
@@ -43885,6 +45359,16 @@ var GameVehiclesThree = (() => {
|
|
|
43885
45359
|
break;
|
|
43886
45360
|
}
|
|
43887
45361
|
};
|
|
45362
|
+
const creaseQueue = createCreaseQueue();
|
|
45363
|
+
const updateLod = (entry) => {
|
|
45364
|
+
if (!host || settings.quality === "lite") return;
|
|
45365
|
+
entry.lod ?? (entry.lod = createVehicleLod(entry.root.userData.kit, entry.item.vehicle, entry.root, entry.root.children[0]));
|
|
45366
|
+
const at = host.player().position;
|
|
45367
|
+
const distance = Math.hypot(at[0] - entry.root.position.x, at[2] - entry.root.position.z);
|
|
45368
|
+
const c = entry.item.vehicle;
|
|
45369
|
+
if (c && (c.rollState || c.flipped || c.blast || c.exploded)) entry.touched = true;
|
|
45370
|
+
entry.lod.update(distance, entry.touched === true, entry.scenario !== void 0 || (entry.posedParts?.size ?? 0) > 0);
|
|
45371
|
+
};
|
|
43888
45372
|
const frame = (dt) => {
|
|
43889
45373
|
for (const [id, entry] of placed) {
|
|
43890
45374
|
if (!entry.root.parent) {
|
|
@@ -43892,6 +45376,7 @@ var GameVehiclesThree = (() => {
|
|
|
43892
45376
|
continue;
|
|
43893
45377
|
}
|
|
43894
45378
|
measure(entry);
|
|
45379
|
+
updateLod(entry);
|
|
43895
45380
|
}
|
|
43896
45381
|
if (host?.bench && boxKey() !== helpersShown && (host.bench.layer("damageables") || host.bench.layer("zones") || helpersShown !== "")) refreshLayers();
|
|
43897
45382
|
lane?.step(dt);
|
|
@@ -43922,7 +45407,7 @@ var GameVehiclesThree = (() => {
|
|
|
43922
45407
|
const sizeError = () => {
|
|
43923
45408
|
let worst = 0;
|
|
43924
45409
|
for (const entry of placed.values()) {
|
|
43925
|
-
const want = fleetDims(entry.key);
|
|
45410
|
+
const want = fleet.fleetDims(entry.key);
|
|
43926
45411
|
const got = entry.size;
|
|
43927
45412
|
if (!want || !got || entry.scenario) continue;
|
|
43928
45413
|
worst = Math.max(worst, Math.abs(got.length - want.length), Math.abs(got.width - want.width), Math.abs(got.height - want.height));
|
|
@@ -43944,15 +45429,15 @@ var GameVehiclesThree = (() => {
|
|
|
43944
45429
|
const rowOf = (list2, z) => {
|
|
43945
45430
|
let cursor = 0;
|
|
43946
45431
|
const spots = list2.map((entry) => {
|
|
43947
|
-
const width = fleetDims(entry.key)?.width ?? 2;
|
|
45432
|
+
const width = fleet.fleetDims(entry.key)?.width ?? 2;
|
|
43948
45433
|
const x = cursor + width / 2;
|
|
43949
45434
|
cursor += width + gap;
|
|
43950
45435
|
return { id: entry.id, x };
|
|
43951
45436
|
});
|
|
43952
45437
|
return { spots, z, width: Math.max(0, cursor - gap) };
|
|
43953
45438
|
};
|
|
43954
|
-
const front = rowOf(entries.filter((e) => (fleetDims(e.key)?.width ?? 2) <= WIDE), 0);
|
|
43955
|
-
const back = rowOf(entries.filter((e) => (fleetDims(e.key)?.width ?? 2) > WIDE), -16);
|
|
45439
|
+
const front = rowOf(entries.filter((e) => (fleet.fleetDims(e.key)?.width ?? 2) <= WIDE), 0);
|
|
45440
|
+
const back = rowOf(entries.filter((e) => (fleet.fleetDims(e.key)?.width ?? 2) > WIDE), -16);
|
|
43956
45441
|
const placements = [front, back].flatMap((row) => row.spots.map(({ id, x }) => ({ item: id, position: [x - row.width / 2, 0, row.z], rotationY: 0 })));
|
|
43957
45442
|
return { placements, view: { eye: [0, 5, Math.max(14, front.width * 0.6)], target: [0, 1, -2] } };
|
|
43958
45443
|
},
|
|
@@ -43991,11 +45476,14 @@ var GameVehiclesThree = (() => {
|
|
|
43991
45476
|
const stopChange = lent.bench?.onChange(onChange);
|
|
43992
45477
|
const stopFrame = lent.onFrame(frame);
|
|
43993
45478
|
const stopBlocker = lent.addBlocker?.(blocked);
|
|
45479
|
+
const stopCrease = lent.defer?.(creaseQueue.deferredQueue(), DEFERRED_PRIORITY[DEFERRED_QUEUE_ID.VEHICLE_CREASE]);
|
|
45480
|
+
if (isRenderPools(lent.pools)) lent.pools.materials.register("vehicles.cracked-glass", () => crackedGlassMaterial(three, new three.DataTexture(new Uint8Array(4), 1, 1)));
|
|
43994
45481
|
lent.audio?.register?.(LIBRARY_BANK);
|
|
43995
45482
|
return () => {
|
|
43996
45483
|
stopChange?.();
|
|
43997
45484
|
stopFrame();
|
|
43998
45485
|
stopBlocker?.();
|
|
45486
|
+
stopCrease?.();
|
|
43999
45487
|
cabins.clear(effects());
|
|
44000
45488
|
clearHelpers();
|
|
44001
45489
|
clearLane();
|