@adatechnology/game-vehicles-three 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,10 @@
1
- export { B as BuildVehicleOptions, a as BuiltVehicle, D as DEFAULT_TEST_VEHICLES, b as DEFAULT_TEST_WRECKS, c as DocumentLike, E as EffectsLike, F as FleetDims, M as ModuleRoomLike, P as PAGE_ITEM_ALIASES, d as PAGE_SCENARIO_ALIASES, V as VEHICLES_AREA_ID, e as VEHICLE_SCENARIO_IDS, f as VehicleEffectIds, g as VehicleFleetContent, h as VehicleQuality, i as VehicleSoundIds, j as VehicleWreck, k as VehiclesContext, l as VehiclesRoom, m as VehiclesTestFleet, n as VehiclesTestOptions, o as VehiclesThree, p as VehiclesThreeOptions, q as createVehiclesTestModule, r as createVehiclesThree, s as defaultEffectIds, t as defaultSoundIds, u as loadVehiclesTestModule } from './testing-DmGv7Gpb.js';
2
- import { EffectSink } from '@adatechnology/game-contracts';
1
+ import { E as EngineProfile, V as VehicleSoundKeys, B as BuiltVehicle } from './testing-C-BgV7gj.js';
2
+ export { a as BIKE_ENGINE, b as BuildVehicleOptions, C as CAR_ENGINE, c as CRASH_SPEEDS, D as DEFAULT_TEST_VEHICLES, d as DEFAULT_TEST_WRECKS, e as DEFAULT_VEHICLE_SOUND_KEYS, f as DocumentLike, g as ENGINE_PROFILES, h as EffectsLike, i as EngineLayer, j as EngineLoadLayer, F as FleetDims, M as ModuleRoomLike, P as PAGE_ITEM_ALIASES, k as PAGE_SCENARIO_ALIASES, l as PROVING_AREA_ID, m as PROVING_TEXT, n as ProvingModuleOptions, o as ProvingRoomLike, p as ProvingText, T as TRUCK_ENGINE, q as VEHICLES_AREA_ID, r as VEHICLE_SCENARIO_IDS, s as VehicleEffectIds, t as VehicleFleetContent, u as VehicleQuality, v as VehicleSoundIds, w as VehicleWreck, x as VehiclesContext, y as VehiclesRoom, z as VehiclesTestFleet, A as VehiclesTestOptions, G as VehiclesThree, H as VehiclesThreeOptions, I as createProvingModule, J as createVehiclesTestModule, K as createVehiclesThree, L as defaultEffectIds, N as defaultSoundIds, O as loadProvingModule, Q as loadVehiclesTestModule } from './testing-C-BgV7gj.js';
3
+ import { EffectSink, Vec3, AudioSink } from '@adatechnology/game-contracts';
3
4
  import { CabinSource } from '@adatechnology/game-vehicles';
5
+ import { LoopRecipe, Falloff, SoundRecipe, SoundBank } from '@adatechnology/game-audio';
6
+ import { Object3D, CanvasTexture, CircleGeometry, MeshBasicMaterial, Mesh, Vector3 } from 'three';
7
+ import '@adatechnology/game-vehicles-proving';
4
8
 
5
9
  /**
6
10
  * Keeps the host's effects told where the cabins of the vehicles are and how open they are (`EffectSink.enclose`), so the smoke, dust and steam
@@ -23,6 +27,92 @@ interface CabinSmoke {
23
27
  }
24
28
  declare function createCabinSmoke(): CabinSmoke;
25
29
 
30
+ /** How a vehicle loop falls off: `1 / (1 + d² × 0.004)`, the game's one-shot curve, with the cutoff muffled by `1 + d × 0.01` (a car far away is dull). */
31
+ declare const VEHICLE_LOOP_FALLOFF: Falloff;
32
+ /** The engines (car, truck, bike) and the tyres, as loops. */
33
+ declare const VEHICLE_LOOPS: readonly LoopRecipe[];
34
+ /** The one-shots: the starter, the engine stopping, crashes by speed, and the doors, trunk and hood of a car. */
35
+ declare const VEHICLE_SOUNDS: readonly SoundRecipe[];
36
+ declare const VEHICLE_SOUND_BANK: SoundBank;
37
+
38
+ /** What one engine loop is set to this frame. `frequency` is absent for the load layer (noise has no pitch). */
39
+ type EngineLayerSetting = {
40
+ readonly sound: string;
41
+ readonly volume: number;
42
+ readonly frequency?: number;
43
+ readonly cutoff: number;
44
+ };
45
+ type EngineMixInput = {
46
+ readonly rpm: number;
47
+ /** 0..1, how open the throttle is (the engine's load). */
48
+ readonly throttle: number;
49
+ };
50
+ /** The firing frequency of a four-stroke engine, Hz: every cylinder fires once every two turns. */
51
+ declare const firingHz: (profile: EngineProfile, rpm: number) => number;
52
+ /** RPM as a share of the range: 0 at idle, 1 at the redline. */
53
+ declare const rpmShare: (profile: EngineProfile, rpm: number) => number;
54
+ /** Equal-power weight of a layer centred at `centre` with `width` at the normalised RPM `n`. */
55
+ declare const layerWeight: (centre: number, width: number, n: number) => number;
56
+ /**
57
+ * The engine's loops for an RPM and a throttle: every tone layer at the firing frequency times its harmonic, faded in and out across the RPM range so
58
+ * the sum stays even, louder and brighter under load; the load layer opens with the throttle. A stopped engine (`rpm` 0) is silent.
59
+ */
60
+ declare function engineMix(profile: EngineProfile, input: EngineMixInput): EngineLayerSetting[];
61
+ /**
62
+ * A guess of the RPM from the speed for a driver without an engine model: the gear is kept between calls (up above 85% of the redline, down below
63
+ * 40%), so the RPM climbs and drops at each shift as it does in a real car.
64
+ */
65
+ declare function createGearGuess(profile: EngineProfile): {
66
+ rpm(speed: number, throttle: number): number;
67
+ readonly gear: number;
68
+ };
69
+
70
+ /** What the vehicle is doing this frame. Without `rpm` (a driver with no engine model) the RPM is guessed from the speed through the profile's gears. */
71
+ type VehicleSoundFrame = {
72
+ readonly dt: number;
73
+ readonly position: Vec3;
74
+ /** m/s, signed or not. */
75
+ readonly speed: number;
76
+ /** 0..1. */
77
+ readonly throttle: number;
78
+ readonly rpm?: number;
79
+ /** 0..1: how much the tyres slide (the largest wheel slip; 1 = locked or spinning). */
80
+ readonly slip?: number;
81
+ /** What the tyres are on: `dirt` for earth, gravel, sand or grass; anything else squeals as asphalt. */
82
+ readonly surface?: 'asphalt' | 'dirt';
83
+ };
84
+ type VehicleSoundOptions = {
85
+ readonly profile?: EngineProfile;
86
+ /** Any of the one-shot and tyre ids, pointed at other sounds. */
87
+ readonly sounds?: Partial<VehicleSoundKeys>;
88
+ /** Seconds the starter turns before the engine catches (the `engine_start` recipe catches at 0.75 s). */
89
+ readonly crankSeconds?: number;
90
+ };
91
+ /** What was asked of the sink, for the checks and the bench: the RPM in use and the level of each loop. */
92
+ type VehicleSoundReading = {
93
+ readonly running: boolean;
94
+ readonly rpm: number;
95
+ readonly levels: Readonly<Record<string, number>>;
96
+ };
97
+ type VehicleSound = {
98
+ /** Turns the key: the starter, then the engine catches with a flare of RPM. `fail` cranks without catching (no fuel, a dead engine). */
99
+ start(position: Vec3, options?: {
100
+ readonly fail?: boolean;
101
+ }): void;
102
+ /** Ignition off: the engine runs down. */
103
+ stop(position: Vec3): void;
104
+ /** A hit at `speed` m/s: light, medium or heavy by speed, louder with it. */
105
+ crash(speed: number, position: Vec3): 'light' | 'medium' | 'heavy';
106
+ update(frame: VehicleSoundFrame): void;
107
+ readonly reading: VehicleSoundReading;
108
+ dispose(): void;
109
+ };
110
+ /**
111
+ * The sounds of one vehicle on a host's sink (`ModuleHost.audio`): the engine loops by RPM and load, the starter, the tyres skidding and rolling,
112
+ * and crashes by speed. The loops are placed at the vehicle every frame (distance and side come from the sink). Works without a sink (silent).
113
+ */
114
+ declare function createVehicleSound(audio: AudioSink | undefined, options?: VehicleSoundOptions): VehicleSound;
115
+
26
116
  /**
27
117
  * The light mode of the team's Frota Leve (frota-leve.js 14202-14310): a built vehicle fused into six meshes, one per class of material,
28
118
  * with the meshes nobody sees from outside left out. A literal port: the classes, the thresholds (3 cm prune, 0.99 opacity, 0.5 metalness,
@@ -64,6 +154,10 @@ declare function liteMeshes(THREE: any, fusion: LiteFusion, materials: Record<Li
64
154
 
65
155
  /** Past this distance (m) an untouched vehicle draws fused: nobody sees a door seam from here, and the full model costs hundreds of draw calls. */
66
156
  declare const VEHICLE_LOD_DISTANCE = 14;
157
+ type VehicleLodOptions = {
158
+ /** The clock (ms) the quiet time is read from (default `performance.now`). */
159
+ readonly now?: () => number;
160
+ };
67
161
  type VehicleLod = {
68
162
  /** `touched`: hit or driven, from now on it always draws in full (its damage only exists there); `posed`: a door, hood or lid is open now (fused only while all are shut). */
69
163
  update(distance: number, touched: boolean, posed?: boolean): void;
@@ -71,6 +165,170 @@ type VehicleLod = {
71
165
  dispose(): void;
72
166
  };
73
167
  /** Shows `full` near and the kit's fused light mode (one mesh per class of material) far, in `root`'s own space. Hit tests read the full model, visible or not. */
74
- declare function createVehicleLod(kit: any, context: any, root: any, full: any): VehicleLod;
168
+ declare function createVehicleLod(kit: any, context: any, root: any, full: any, options?: VehicleLodOptions): VehicleLod;
169
+
170
+ type LampSwitch = {
171
+ mode: 'off' | 'position' | 'low' | 'high';
172
+ fog: boolean;
173
+ interior: boolean;
174
+ brake: boolean;
175
+ reverse: boolean;
176
+ /** Indicator lamps lit this instant (the controls blink them). */
177
+ left: boolean;
178
+ right: boolean;
179
+ };
180
+ /** Glow of the lamp glass by switch, as a share of what the kit drew (the kit draws them lit), and the beams. */
181
+ declare const LAMP_RULES: {
182
+ readonly glow: {
183
+ readonly head: {
184
+ readonly off: 0.04;
185
+ readonly position: 0.3;
186
+ readonly low: 1;
187
+ readonly high: 1.35;
188
+ };
189
+ readonly tail: {
190
+ readonly off: 0.15;
191
+ readonly on: 0.7;
192
+ readonly brake: 1.6;
193
+ };
194
+ readonly fog: {
195
+ readonly off: 0.04;
196
+ readonly on: 1.1;
197
+ };
198
+ readonly amber: {
199
+ readonly off: 0.1;
200
+ readonly on: 2.2;
201
+ };
202
+ };
203
+ readonly low: {
204
+ readonly color: 16773584;
205
+ readonly intensity: 2.4;
206
+ readonly distance: 32;
207
+ readonly angle: 0.42;
208
+ readonly penumbra: 0.55;
209
+ readonly decay: 1.6;
210
+ readonly drop: 0.09;
211
+ };
212
+ readonly high: {
213
+ readonly color: 16774882;
214
+ readonly intensity: 3.6;
215
+ readonly distance: 70;
216
+ readonly angle: 0.3;
217
+ readonly penumbra: 0.45;
218
+ readonly decay: 1.4;
219
+ readonly drop: 0.015;
220
+ };
221
+ readonly fog: {
222
+ readonly color: 16773320;
223
+ readonly intensity: 1.6;
224
+ readonly distance: 16;
225
+ readonly angle: 0.75;
226
+ readonly penumbra: 0.7;
227
+ readonly decay: 1.8;
228
+ readonly drop: 0.12;
229
+ };
230
+ readonly reverse: {
231
+ readonly color: 16054015;
232
+ readonly intensity: 0.9;
233
+ readonly distance: 7;
234
+ readonly decay: 2;
235
+ };
236
+ readonly interior: {
237
+ readonly color: 16769712;
238
+ readonly intensity: 0.5;
239
+ readonly distance: 2.4;
240
+ readonly decay: 2;
241
+ };
242
+ };
243
+ interface VehicleLamps {
244
+ /** What this vehicle has: fog lamps only when the kit drew them. */
245
+ readonly has: {
246
+ head: boolean;
247
+ tail: boolean;
248
+ fog: boolean;
249
+ indicators: boolean;
250
+ };
251
+ set(lamps: LampSwitch): void;
252
+ readonly state: LampSwitch;
253
+ dispose(): void;
254
+ }
255
+ declare function createVehicleLamps(THREE: {
256
+ Object3D: new () => Object3D;
257
+ }, built: BuiltVehicle, options?: {
258
+ lights?: unknown;
259
+ owner?: string;
260
+ }): VehicleLamps;
261
+
262
+ /** What the cluster shows this instant. */
263
+ type DashboardReading = {
264
+ kmh: number;
265
+ rpm: number;
266
+ /** -1 reverse, 0 neutral, 1.. forward. */
267
+ gear: number;
268
+ ignition: boolean;
269
+ engineOn: boolean;
270
+ left: boolean;
271
+ right: boolean;
272
+ highBeam: boolean;
273
+ lowBeam: boolean;
274
+ fog: boolean;
275
+ parkingBrake: boolean;
276
+ seatbelt: boolean;
277
+ fourWheel: boolean;
278
+ /** Engine temperature, 0 (cold) to 1 (overheating); leave out while the engine has no heat model. */
279
+ temperature?: number;
280
+ /** Fuel, 0 (empty) to 1 (full); leave out while the vehicle has no fuel model. */
281
+ fuel?: number;
282
+ };
283
+ /** The scale of the dials and how often the faces are redrawn. */
284
+ type DashboardOptions = {
285
+ /** The kit's dial material (`kit.materials.gauge`): the dials are found by it. */
286
+ gauge: unknown;
287
+ /** The kit's needle material (`kit.materials.amber`): the fixed needles drawn on the dials hide while the live face shows. */
288
+ needle?: unknown;
289
+ /** Top of the speedometer, km/h. Default 220. */
290
+ maxKmh?: number;
291
+ /** Red line of the rev counter. Default 6500. */
292
+ redlineRpm?: number;
293
+ /** Redraws per second at most. Default 15. */
294
+ fps?: number;
295
+ /** Where the canvases come from (tests pass a fake one). Default the page's. */
296
+ document?: {
297
+ createElement(tag: 'canvas'): HTMLCanvasElement;
298
+ };
299
+ };
300
+ interface VehicleDashboard {
301
+ /** How many dials were found (0: a vehicle without a cluster drawn, nothing to show). */
302
+ readonly dials: number;
303
+ update(reading: DashboardReading, dt: number): void;
304
+ dispose(): void;
305
+ }
306
+ type ThreeLib = {
307
+ CanvasTexture: new (canvas: HTMLCanvasElement) => CanvasTexture;
308
+ CircleGeometry: new (radius: number, segments: number) => CircleGeometry;
309
+ MeshBasicMaterial: new (p: {
310
+ map: CanvasTexture;
311
+ transparent: boolean;
312
+ toneMapped: boolean;
313
+ depthWrite: boolean;
314
+ }) => MeshBasicMaterial;
315
+ Mesh: new (g: CircleGeometry, m: MeshBasicMaterial) => Mesh;
316
+ Vector3: new (x?: number, y?: number, z?: number) => Vector3;
317
+ };
318
+ /** The colours of the cluster: the warning lights by the usual code (red stop, amber caution, green and blue information). */
319
+ declare const DASHBOARD_LOOK: {
320
+ readonly face: "#0b1110";
321
+ readonly ring: "#2f3a36";
322
+ readonly marks: "#cfe8dc";
323
+ readonly needle: "#ff6a2a";
324
+ readonly red: "#e2402f";
325
+ readonly amber: "#f2a630";
326
+ readonly green: "#46d16f";
327
+ readonly blue: "#3f8cff";
328
+ readonly dim: "rgba(207,232,220,0.12)";
329
+ /** How far in front of the kit's dial the face sits, metres (the kit's needle sticks out 6 mm). */
330
+ readonly lift: 0.011;
331
+ };
332
+ declare function createVehicleDashboard(THREE: ThreeLib, built: BuiltVehicle, options: DashboardOptions): VehicleDashboard;
75
333
 
76
- export { type CabinSmoke, LITE_CLASSES, type LiteClass, type LiteFusion, PRUNE_BELOW, VEHICLE_LOD_DISTANCE, type VehicleLod, classColor, classify, createCabinSmoke, createVehicleLod, fuse, liteMaterials, liteMeshes };
334
+ export { BuiltVehicle, type CabinSmoke, DASHBOARD_LOOK, type DashboardOptions, type DashboardReading, type EngineLayerSetting, type EngineMixInput, EngineProfile, LAMP_RULES, LITE_CLASSES, type LampSwitch, type LiteClass, type LiteFusion, PRUNE_BELOW, VEHICLE_LOD_DISTANCE, VEHICLE_LOOPS, VEHICLE_LOOP_FALLOFF, VEHICLE_SOUNDS, VEHICLE_SOUND_BANK, type VehicleDashboard, type VehicleLamps, type VehicleLod, type VehicleSound, type VehicleSoundFrame, VehicleSoundKeys, type VehicleSoundOptions, type VehicleSoundReading, classColor, classify, createCabinSmoke, createGearGuess, createVehicleDashboard, createVehicleLamps, createVehicleLod, createVehicleSound, engineMix, firingHz, fuse, layerWeight, liteMaterials, liteMeshes, rpmShare };