@adatechnology/game-interactables 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +202 -2
- package/dist/index.d.ts +831 -0
- package/dist/index.global.js +1765 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +1740 -0
- package/dist/index.js.map +1 -0
- package/package.json +52 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,831 @@
|
|
|
1
|
+
import { Thumbnail } from '@adatechnology/game-contracts';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Contract of @adatechnology/game-interactables.
|
|
5
|
+
*
|
|
6
|
+
* The package is a renderer-agnostic runtime for interactive world objects: movable parts (doors, drawers, lids, knobs, flaps),
|
|
7
|
+
* containers with pickable items, a logical power grid (meter, circuits, sockets, switches, devices), fuel (gas bottles, charcoal),
|
|
8
|
+
* a logical water network (tanks feeding taps, showers, tanks and flushes), seats and beds, soft volumes that sway instead of blocking,
|
|
9
|
+
* effect emitters (smoke, fire, steam, water, sparks), mirror surfaces and damage.
|
|
10
|
+
*
|
|
11
|
+
* Content packs (for example @adatechnology/game-interactables-household) describe objects as `ObjectSpec` data; the host adds them
|
|
12
|
+
* to a `World`, calls `update(dt)` every frame and draws whatever the world reports. Coordinates in a spec are local to the object
|
|
13
|
+
* (front = +z, origin at the center of the footprint on the floor, meters). `World` converts them with the object's `Transform`.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
type Vec3 = [number, number, number];
|
|
17
|
+
/** Placement of an object in the host's space. Rotation is around +y (radians). */
|
|
18
|
+
interface Transform {
|
|
19
|
+
x: number;
|
|
20
|
+
y: number;
|
|
21
|
+
z: number;
|
|
22
|
+
ry: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* How a part moves between t = 0 (closed / off) and t = 1 (open / on).
|
|
26
|
+
* - `hinge`: rotate `angle` radians around `axis` through the pivot (doors, lids, flaps, oven door).
|
|
27
|
+
* - `slide`: translate `distance` meters along `axis` (drawers, sliding panels, gate leaves, curtains).
|
|
28
|
+
* - `scale`: scale along `axis` from 1 to `scale` (blinds being raised, curtains bunching).
|
|
29
|
+
* - `rocker`: small rotation like `hinge`, snaps (switches).
|
|
30
|
+
* - `knob`: rotation like `hinge`, for stove knobs and valves.
|
|
31
|
+
*/
|
|
32
|
+
type MotionKind = 'hinge' | 'slide' | 'scale' | 'rocker' | 'knob';
|
|
33
|
+
interface Motion {
|
|
34
|
+
kind: MotionKind;
|
|
35
|
+
/** Axis in the part's local frame. Default [0, 1, 0]. */
|
|
36
|
+
axis?: Vec3;
|
|
37
|
+
/** Radians, for hinge / rocker / knob. */
|
|
38
|
+
angle?: number;
|
|
39
|
+
/** Meters, for slide. */
|
|
40
|
+
distance?: number;
|
|
41
|
+
/** Final scale factor, for scale. */
|
|
42
|
+
scale?: number;
|
|
43
|
+
/** Units of t per second. Default 2.5 (0.4 s to fully open). */
|
|
44
|
+
speed?: number;
|
|
45
|
+
}
|
|
46
|
+
/** A rectangle on the floor plane in object-local coordinates: [x0, z0, x1, z1]. */
|
|
47
|
+
type Rect = [number, number, number, number];
|
|
48
|
+
interface PartSpec {
|
|
49
|
+
/** Unique inside the object, snake_case or kebab-case (`door`, `drawer_2`, `lid`). */
|
|
50
|
+
id: string;
|
|
51
|
+
/** Pivot in object-local coordinates (hinge line, slide origin). */
|
|
52
|
+
pivot: Vec3;
|
|
53
|
+
/** Extra rotation of the part frame around +y, radians. */
|
|
54
|
+
ry?: number;
|
|
55
|
+
motion: Motion;
|
|
56
|
+
/** Initial t. Default 0. */
|
|
57
|
+
t0?: number;
|
|
58
|
+
/**
|
|
59
|
+
* Floor area swept by the part when it goes from t = 0 to t = 1, in object-local coordinates.
|
|
60
|
+
* Hosts use it with `fitSweep` so a door never opens through a wall.
|
|
61
|
+
*/
|
|
62
|
+
sweep?: Rect;
|
|
63
|
+
/**
|
|
64
|
+
* Closed-pose bounding box of the part's geometry, object-local: [x0, y0, z0, x1, y1, z1]. When present, `fitSweep` moves this
|
|
65
|
+
* whole slab (thickness, hinge offset, any hinge axis, slides) instead of testing the thin `sweep` rectangle.
|
|
66
|
+
*/
|
|
67
|
+
bounds?: [number, number, number, number, number, number];
|
|
68
|
+
/** The part only moves while this part is at t >= 0.5 (an inner drawer behind a door). */
|
|
69
|
+
requires?: string;
|
|
70
|
+
/** Label key used by the default interaction (see `InteractionSpec.label`). */
|
|
71
|
+
label?: string;
|
|
72
|
+
/**
|
|
73
|
+
* Parts of one object that share a group move together: `setPart` or a toggle on any member sets the target of all of them
|
|
74
|
+
* (blind slats, the two panels of a curtain).
|
|
75
|
+
*/
|
|
76
|
+
group?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Destruction tags for the shared destruction SDK (`@adatechnology/game-destruction`). Plain ids that match the SDK's material and joint
|
|
79
|
+
* kinds; this package has no dependency on it. The host maps the tags to its destruction parts.
|
|
80
|
+
*/
|
|
81
|
+
destruction?: PartDestruction;
|
|
82
|
+
}
|
|
83
|
+
/** Joint kinds of the destruction SDK (`JointKind`). */
|
|
84
|
+
type DestructionJoint = 'screw' | 'bolt' | 'nail' | 'weld' | 'glue' | 'hinge' | 'clip' | 'tie' | 'mortar' | 'fused' | 'stem';
|
|
85
|
+
/** What a part is made of and how it is attached. Field names and shapes mirror the SDK's `PartSpec`. */
|
|
86
|
+
interface PartDestruction {
|
|
87
|
+
/** SDK material id (`steel`, `wood_soft`, `mdf`, `glass`, `ceramic`, `plastic`, `fabric`...). */
|
|
88
|
+
material: string;
|
|
89
|
+
/** How the part is attached to the rest of the object. */
|
|
90
|
+
joint?: DestructionJoint | (string & {});
|
|
91
|
+
/** What the part is (`door`, `drawer`, `leg`, `top`, `glass`, `shelf`, `lid`, `panel`, `handle`, `knob`...). */
|
|
92
|
+
piece?: string;
|
|
93
|
+
/** The part explodes when destroyed, or when its temperature passes `atC` (energy in joules, radius in metres). */
|
|
94
|
+
explodes?: {
|
|
95
|
+
energy: number;
|
|
96
|
+
radius: number;
|
|
97
|
+
atC?: number;
|
|
98
|
+
};
|
|
99
|
+
/** Fluid inside the part; `fluid` is an SDK `FluidKind` (`water`, `fuel`, `oil`, `gas`...). */
|
|
100
|
+
contains?: {
|
|
101
|
+
fluid: string;
|
|
102
|
+
liters: number;
|
|
103
|
+
pressurized?: boolean;
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/** One stack of items. `type` is an id from the content pack's item catalog. */
|
|
107
|
+
interface ItemStack {
|
|
108
|
+
type: string;
|
|
109
|
+
qty: number;
|
|
110
|
+
/** Free per-instance data (letter text key, expiry, condition...). */
|
|
111
|
+
data?: Record<string, unknown>;
|
|
112
|
+
}
|
|
113
|
+
interface ItemDef {
|
|
114
|
+
id: string;
|
|
115
|
+
category: string;
|
|
116
|
+
/** Bounding size [w, h, d] in meters, used to place the item on a slot and to check it fits. */
|
|
117
|
+
size: Vec3;
|
|
118
|
+
/** kg per unit. */
|
|
119
|
+
weight: number;
|
|
120
|
+
/** Max units per stack. Default 1. */
|
|
121
|
+
stack?: number;
|
|
122
|
+
/** Can the player take it. Default true. */
|
|
123
|
+
pickable?: boolean;
|
|
124
|
+
/** Locale key of the display name. Default `item.<id>`. */
|
|
125
|
+
name?: string;
|
|
126
|
+
/** Hint for the host's renderer: which simple shape to draw (`can`, `box`, `bottle`, `jar`, `bag`, `cloth`, `paper`, `tool`...). */
|
|
127
|
+
shape?: string;
|
|
128
|
+
color?: number;
|
|
129
|
+
/** Picture for catalogues and inventories. */
|
|
130
|
+
thumbnail?: Thumbnail;
|
|
131
|
+
}
|
|
132
|
+
type ItemCatalog = Record<string, ItemDef>;
|
|
133
|
+
/** A spot where one stack sits, in object-local coordinates (bottom center of the stack). */
|
|
134
|
+
interface SlotSpec {
|
|
135
|
+
pos: Vec3;
|
|
136
|
+
/** Largest item [w, h, d] the slot holds. */
|
|
137
|
+
max: Vec3;
|
|
138
|
+
/** The slot moves with this part (a drawer or a door shelf). */
|
|
139
|
+
part?: string;
|
|
140
|
+
}
|
|
141
|
+
interface ContainerSpec {
|
|
142
|
+
id: string;
|
|
143
|
+
/** Part that must be open (t >= 0.5) to see and take items. Omit for open shelves. */
|
|
144
|
+
access?: string;
|
|
145
|
+
/** Inner volume, object-local: center and half sizes. Used for previews and to keep items inside. */
|
|
146
|
+
volume: {
|
|
147
|
+
center: Vec3;
|
|
148
|
+
half: Vec3;
|
|
149
|
+
};
|
|
150
|
+
slots: SlotSpec[];
|
|
151
|
+
/** Loot table id used when no explicit contents are given. */
|
|
152
|
+
loot?: string;
|
|
153
|
+
/** Explicit contents, slot by slot (null = empty). Wins over `loot`. */
|
|
154
|
+
contents?: Array<ItemStack | null>;
|
|
155
|
+
}
|
|
156
|
+
interface LootEntry {
|
|
157
|
+
type: string;
|
|
158
|
+
/** Relative weight. */
|
|
159
|
+
weight: number;
|
|
160
|
+
/** Quantity range [min, max]. Default [1, 1]. */
|
|
161
|
+
qty?: [number, number];
|
|
162
|
+
}
|
|
163
|
+
interface LootTable {
|
|
164
|
+
/** Chance that a slot is filled, 0..1. */
|
|
165
|
+
fill: number;
|
|
166
|
+
entries: LootEntry[];
|
|
167
|
+
}
|
|
168
|
+
type LootTables = Record<string, LootTable>;
|
|
169
|
+
/** A wall socket. `circuit` refers to a circuit id of the building (see `World.power`). */
|
|
170
|
+
interface SocketSpec {
|
|
171
|
+
id: string;
|
|
172
|
+
pos: Vec3;
|
|
173
|
+
circuit?: string;
|
|
174
|
+
}
|
|
175
|
+
/** A light switch. Switches toggle devices of kind `lamp` by id (ids are world-wide, `objectId:deviceId` or plain ids). */
|
|
176
|
+
interface SwitchSpec {
|
|
177
|
+
id: string;
|
|
178
|
+
/** Rocker part that moves. */
|
|
179
|
+
part?: string;
|
|
180
|
+
controls: string[];
|
|
181
|
+
}
|
|
182
|
+
type DeviceKind = 'lamp' | 'appliance' | 'screen' | 'pump' | 'heater';
|
|
183
|
+
interface DeviceSpec {
|
|
184
|
+
id: string;
|
|
185
|
+
kind: DeviceKind;
|
|
186
|
+
watts: number;
|
|
187
|
+
/** Needs a powered socket or circuit to run. Default true. */
|
|
188
|
+
electric?: boolean;
|
|
189
|
+
/** Socket id it is plugged into (world-wide id) or `auto` to plug into the nearest free socket within 2 m. */
|
|
190
|
+
socket?: string | 'auto';
|
|
191
|
+
/** Hard-wired to a circuit instead of a socket (ceiling lamps, shower heater). */
|
|
192
|
+
circuit?: string;
|
|
193
|
+
/** Where the plug sits on the object (local), so the host can draw the cord to the socket. */
|
|
194
|
+
plug?: Vec3;
|
|
195
|
+
/** Part that shows the on state (power button, knob). */
|
|
196
|
+
part?: string;
|
|
197
|
+
/** Starts on. Default false. */
|
|
198
|
+
on?: boolean;
|
|
199
|
+
/** For screens: number of channels the host can draw. */
|
|
200
|
+
channels?: number;
|
|
201
|
+
/**
|
|
202
|
+
* Id of a fixture of the same object that flows while this device is on and powered (a washing machine's water inlet).
|
|
203
|
+
* The fixture is driven by the device: it gets no interaction of its own.
|
|
204
|
+
*/
|
|
205
|
+
fixture?: string;
|
|
206
|
+
}
|
|
207
|
+
interface FuelSourceSpec {
|
|
208
|
+
id: string;
|
|
209
|
+
kind: 'gas' | 'charcoal' | 'wood';
|
|
210
|
+
/** kg. */
|
|
211
|
+
capacity: number;
|
|
212
|
+
/** kg at start. Default = capacity. */
|
|
213
|
+
level?: number;
|
|
214
|
+
/** Valve part (gas bottle regulator). */
|
|
215
|
+
valve?: string;
|
|
216
|
+
}
|
|
217
|
+
/** Something that burns fuel when on: stove burner, oven, barbecue bed. */
|
|
218
|
+
interface BurnerSpec {
|
|
219
|
+
id: string;
|
|
220
|
+
pos: Vec3;
|
|
221
|
+
/** Knob / valve part. */
|
|
222
|
+
part?: string;
|
|
223
|
+
/** Fuel source id (local to the object, or world-wide `objectId:sourceId`, or `auto` = nearest gas bottle within 2 m). */
|
|
224
|
+
fuel: string;
|
|
225
|
+
/** kg per second at full flame. */
|
|
226
|
+
rate: number;
|
|
227
|
+
/** Needs a lighter/match first (charcoal). Gas burners light from the knob. Default false. */
|
|
228
|
+
needsIgnition?: boolean;
|
|
229
|
+
}
|
|
230
|
+
/** Logical water network: tanks feed fixtures. Pipes are not simulated, only the link. */
|
|
231
|
+
interface TankSpec {
|
|
232
|
+
id: string;
|
|
233
|
+
/** Liters. */
|
|
234
|
+
capacity: number;
|
|
235
|
+
level?: number;
|
|
236
|
+
/** Inlet that refills from rain, in m^2 of collecting area. 0 = none. */
|
|
237
|
+
rainArea?: number;
|
|
238
|
+
}
|
|
239
|
+
type FixtureKind = 'tap' | 'shower' | 'utility_sink' | 'flush' | 'hose' | 'filter';
|
|
240
|
+
interface FixtureSpec {
|
|
241
|
+
id: string;
|
|
242
|
+
kind: FixtureKind;
|
|
243
|
+
/** Where water comes out, object-local, and its direction. */
|
|
244
|
+
outlet: Vec3;
|
|
245
|
+
dir?: Vec3;
|
|
246
|
+
/** Liters per minute when fully open. A flush uses `volume` once instead. */
|
|
247
|
+
flow?: number;
|
|
248
|
+
volume?: number;
|
|
249
|
+
/** Valve / handle part. */
|
|
250
|
+
part?: string;
|
|
251
|
+
/** Tank id (world-wide) or `auto` = the building's default tank. */
|
|
252
|
+
tank?: string | 'auto';
|
|
253
|
+
/** Needs power too (electric shower heats; still flows cold without power). */
|
|
254
|
+
heater?: string;
|
|
255
|
+
}
|
|
256
|
+
type SeatPose = 'sit' | 'lie';
|
|
257
|
+
interface SeatSpec {
|
|
258
|
+
id: string;
|
|
259
|
+
pose: SeatPose;
|
|
260
|
+
/** Hips (sit) or pelvis (lie), object-local. */
|
|
261
|
+
pos: Vec3;
|
|
262
|
+
/** Facing of the actor, relative to the object. */
|
|
263
|
+
ry: number;
|
|
264
|
+
/** Eye height above `pos` for the camera. Default 0.62 sit, 0.18 lie. */
|
|
265
|
+
eye?: number;
|
|
266
|
+
/** Where the actor stands when leaving, object-local. */
|
|
267
|
+
exit: Vec3;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* A soft volume never blocks. When an actor pushes through it, it swings like a pendulum (damped spring) and settles back.
|
|
271
|
+
* Panels (shower doors) can also be pushed open if `part` is given: the push drives the part's t.
|
|
272
|
+
*/
|
|
273
|
+
interface SoftSpec {
|
|
274
|
+
id: string;
|
|
275
|
+
kind: 'cloth' | 'curtain' | 'panel' | 'foliage' | 'strip';
|
|
276
|
+
/** Top anchor line center, object-local. */
|
|
277
|
+
anchor: Vec3;
|
|
278
|
+
/** [w, h, d] of the hanging volume below the anchor. */
|
|
279
|
+
size: Vec3;
|
|
280
|
+
/** Spring stiffness (1/s^2) and damping (1/s). Defaults 30 and 4. */
|
|
281
|
+
stiffness?: number;
|
|
282
|
+
damping?: number;
|
|
283
|
+
/** Max swing, radians. Default 0.7. */
|
|
284
|
+
maxAngle?: number;
|
|
285
|
+
/** Wind response 0..1. Default 1 for cloth, 0 for panels. */
|
|
286
|
+
wind?: number;
|
|
287
|
+
part?: string;
|
|
288
|
+
}
|
|
289
|
+
type EmitterKind = 'smoke' | 'fire' | 'steam' | 'water' | 'spark' | 'flame';
|
|
290
|
+
/** An effect the host should draw while `when` holds. The world reports active emitters with their intensity 0..1. */
|
|
291
|
+
interface EmitterSpec {
|
|
292
|
+
id: string;
|
|
293
|
+
kind: EmitterKind;
|
|
294
|
+
pos: Vec3;
|
|
295
|
+
dir?: Vec3;
|
|
296
|
+
/** What drives it: a burner, fixture, device or fuel source id of the same object. */
|
|
297
|
+
source: string;
|
|
298
|
+
/** Size hint in meters. */
|
|
299
|
+
size?: number;
|
|
300
|
+
/** How far (m) a water stream falls before it hits something (a basin, a bowl). Default: until the floor. */
|
|
301
|
+
reach?: number;
|
|
302
|
+
}
|
|
303
|
+
interface MirrorSpec {
|
|
304
|
+
id: string;
|
|
305
|
+
center: Vec3;
|
|
306
|
+
/** Normal in object-local coordinates (the side the mirror faces). */
|
|
307
|
+
normal: Vec3;
|
|
308
|
+
w: number;
|
|
309
|
+
h: number;
|
|
310
|
+
/** Moves with this part (mirror on a wardrobe door). */
|
|
311
|
+
part?: string;
|
|
312
|
+
}
|
|
313
|
+
/** Solid box collider, object-local. Soft things are never colliders. */
|
|
314
|
+
interface ColliderSpec {
|
|
315
|
+
id: string;
|
|
316
|
+
center: Vec3;
|
|
317
|
+
half: Vec3;
|
|
318
|
+
ry?: number;
|
|
319
|
+
/** Collider follows this part (a door): off while the part is at t > 0.5 when `offWhenOpen`. */
|
|
320
|
+
part?: string;
|
|
321
|
+
offWhenOpen?: boolean;
|
|
322
|
+
}
|
|
323
|
+
type DamageKind = 'glass' | 'wood' | 'water' | 'metal' | 'masonry' | 'gas' | 'fabric' | 'plastic';
|
|
324
|
+
/**
|
|
325
|
+
* @deprecated Damage now goes through the destruction SDK (`@adatechnology/game-destruction`); tag parts with `PartSpec.destruction` and
|
|
326
|
+
* `ObjectSpec.destruction`. `DamageSpec` and `world.damage` keep working but get no new features.
|
|
327
|
+
*/
|
|
328
|
+
interface DamageSpec {
|
|
329
|
+
/** Part id, fuel source id, tank id or `self` for the whole object. */
|
|
330
|
+
target: string;
|
|
331
|
+
kind: DamageKind;
|
|
332
|
+
hp: number;
|
|
333
|
+
}
|
|
334
|
+
/** What an interaction does. The world executes it. */
|
|
335
|
+
type Action = {
|
|
336
|
+
do: 'toggle_part';
|
|
337
|
+
part: string;
|
|
338
|
+
} | {
|
|
339
|
+
do: 'open_container';
|
|
340
|
+
container: string;
|
|
341
|
+
} | {
|
|
342
|
+
do: 'take';
|
|
343
|
+
container: string;
|
|
344
|
+
slot?: number;
|
|
345
|
+
} | {
|
|
346
|
+
do: 'toggle_device';
|
|
347
|
+
device: string;
|
|
348
|
+
} | {
|
|
349
|
+
do: 'cycle_device';
|
|
350
|
+
device: string;
|
|
351
|
+
} | {
|
|
352
|
+
do: 'toggle_switch';
|
|
353
|
+
switch: string;
|
|
354
|
+
}
|
|
355
|
+
/** Flips the building circuit `circuit` (see `World.power.setBreaker`). `part` is a rocker of the same object that mirrors the state (t = 1 when on); while that part is gated (`PartSpec.requires`, e.g. a closed panel door) the action is refused. `name` is shown in the prompt instead of the circuit id. */
|
|
356
|
+
| {
|
|
357
|
+
do: 'toggle_breaker';
|
|
358
|
+
circuit: string;
|
|
359
|
+
part?: string;
|
|
360
|
+
name?: string;
|
|
361
|
+
} | {
|
|
362
|
+
do: 'toggle_fixture';
|
|
363
|
+
fixture: string;
|
|
364
|
+
} | {
|
|
365
|
+
do: 'toggle_burner';
|
|
366
|
+
burner: string;
|
|
367
|
+
} | {
|
|
368
|
+
do: 'ignite';
|
|
369
|
+
burner: string;
|
|
370
|
+
} | {
|
|
371
|
+
do: 'toggle_fuel';
|
|
372
|
+
fuel: string;
|
|
373
|
+
} | {
|
|
374
|
+
do: 'sit';
|
|
375
|
+
seat: string;
|
|
376
|
+
} | {
|
|
377
|
+
do: 'read';
|
|
378
|
+
container: string;
|
|
379
|
+
slot: number;
|
|
380
|
+
};
|
|
381
|
+
interface InteractionSpec {
|
|
382
|
+
id: string;
|
|
383
|
+
/** Object-local point the player aims at. */
|
|
384
|
+
pos: Vec3;
|
|
385
|
+
/** Reach radius, meters. Default 1.2. */
|
|
386
|
+
radius?: number;
|
|
387
|
+
action: Action;
|
|
388
|
+
/**
|
|
389
|
+
* Locale key of the prompt, resolved with the current state: the world looks up `<label>.on` / `<label>.off` (or `.open` / `.closed`)
|
|
390
|
+
* and falls back to `<label>`. Example keys: `prompt.door`, `prompt.drawer`, `prompt.stove_knob`.
|
|
391
|
+
*/
|
|
392
|
+
label: string;
|
|
393
|
+
/** The interaction is available only while this part of this object (world-wide object id) is open (`t >= 0.5`). */
|
|
394
|
+
requires?: {
|
|
395
|
+
object: string;
|
|
396
|
+
part: string;
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
interface ObjectSpec {
|
|
400
|
+
/** Type id from the content pack (`fridge`, `wardrobe`, `stove`...). */
|
|
401
|
+
type: string;
|
|
402
|
+
parts?: PartSpec[];
|
|
403
|
+
containers?: ContainerSpec[];
|
|
404
|
+
sockets?: SocketSpec[];
|
|
405
|
+
switches?: SwitchSpec[];
|
|
406
|
+
devices?: DeviceSpec[];
|
|
407
|
+
fuels?: FuelSourceSpec[];
|
|
408
|
+
burners?: BurnerSpec[];
|
|
409
|
+
tanks?: TankSpec[];
|
|
410
|
+
fixtures?: FixtureSpec[];
|
|
411
|
+
seats?: SeatSpec[];
|
|
412
|
+
soft?: SoftSpec[];
|
|
413
|
+
emitters?: EmitterSpec[];
|
|
414
|
+
mirrors?: MirrorSpec[];
|
|
415
|
+
colliders?: ColliderSpec[];
|
|
416
|
+
/** @deprecated Use the destruction SDK; see `DamageSpec`. */
|
|
417
|
+
damage?: DamageSpec[];
|
|
418
|
+
/**
|
|
419
|
+
* Default destruction tags of the static body (everything that is not a movable part). `explodes` and `contains` describe the body itself
|
|
420
|
+
* (a gas bottle has no movable part that holds the gas).
|
|
421
|
+
*/
|
|
422
|
+
destruction?: Omit<PartDestruction, 'piece'>;
|
|
423
|
+
interactions?: InteractionSpec[];
|
|
424
|
+
/** Visible wires / conduits / cords (object-local polylines) the host draws as thin tubes. */
|
|
425
|
+
wires?: Array<{
|
|
426
|
+
id: string;
|
|
427
|
+
kind: 'drop' | 'conduit' | 'cord' | 'cable';
|
|
428
|
+
points: Vec3[];
|
|
429
|
+
radius?: number;
|
|
430
|
+
}>;
|
|
431
|
+
}
|
|
432
|
+
type InteractablesLocale = 'en' | 'pt-BR';
|
|
433
|
+
/** Locale table: key -> text. `{n}` style placeholders are filled from `vars`. */
|
|
434
|
+
type Strings = Record<string, string>;
|
|
435
|
+
/** The part of `DestructionWorld` the engine uses. A result with an `events` array of `{ type, part }` lets `damage` report `destroyed`. */
|
|
436
|
+
interface DestructionDelegate {
|
|
437
|
+
hitPart(objectId: string, partId: string, hit: {
|
|
438
|
+
type: string;
|
|
439
|
+
point: [number, number, number];
|
|
440
|
+
energy: number;
|
|
441
|
+
source?: string;
|
|
442
|
+
}): unknown;
|
|
443
|
+
}
|
|
444
|
+
interface WorldOptions {
|
|
445
|
+
locale?: InteractablesLocale | string;
|
|
446
|
+
/** Extra strings per locale, merged over the built-in ones (content packs pass theirs here). */
|
|
447
|
+
strings?: Partial<Record<InteractablesLocale, Strings>>;
|
|
448
|
+
items?: ItemCatalog;
|
|
449
|
+
loot?: LootTables;
|
|
450
|
+
/** Seed for loot and any random detail. Same seed + same adds = same world. */
|
|
451
|
+
seed?: number | string;
|
|
452
|
+
/** Grid power at start. Default true. */
|
|
453
|
+
grid?: boolean;
|
|
454
|
+
/** Rain intensity mm/h at start (fills tanks with `rainArea`). Default 0. */
|
|
455
|
+
rain?: number;
|
|
456
|
+
/** Wind vector [x, z] m/s for cloth. Default [0, 0]. */
|
|
457
|
+
wind?: [number, number];
|
|
458
|
+
/**
|
|
459
|
+
* External water network. When given, fixtures draw water through it instead of the world's own tanks: `draw` gets the
|
|
460
|
+
* world-wide fixture id (`objectId:fixtureId`) and the liters wanted for this step and returns the liters actually delivered
|
|
461
|
+
* (0 = dry: the host should show only a drip). Lets a building SDK own the tank, leaks and refills.
|
|
462
|
+
*/
|
|
463
|
+
waterSupply?: {
|
|
464
|
+
draw(fixture: string, liters: number): number;
|
|
465
|
+
};
|
|
466
|
+
/**
|
|
467
|
+
* Destruction delegate, duck-typed to `DestructionWorld.hitPart` of `@adatechnology/game-destruction` (no dependency on it). When given,
|
|
468
|
+
* `world.damage(objectId, target, amount, kind)` forwards to `destruction.hitPart(objectId, target, hit)` and the world stops its own hp
|
|
469
|
+
* bookkeeping (`DamageSpec` is ignored; `world.hp` returns null). The host registers the object in the destruction world under the same id.
|
|
470
|
+
* The hit is `{ type, point (world space), energy: amount, source: 'interactables' }`: `type` is `explosive` for `gas`, `slash` for `fabric`,
|
|
471
|
+
* `blunt` otherwise. Without it the deprecated behaviour is unchanged.
|
|
472
|
+
*/
|
|
473
|
+
destruction?: DestructionDelegate;
|
|
474
|
+
/** Called for every event. */
|
|
475
|
+
onEvent?: (event: WorldEvent) => void;
|
|
476
|
+
/** Return false to cancel an interaction (locked, needs a tool, tutorial...). */
|
|
477
|
+
canInteract?: (interaction: Interactable, actor: string) => boolean | void;
|
|
478
|
+
}
|
|
479
|
+
type WorldEvent = {
|
|
480
|
+
type: 'part';
|
|
481
|
+
object: string;
|
|
482
|
+
part: string;
|
|
483
|
+
t: number;
|
|
484
|
+
target: number;
|
|
485
|
+
} | {
|
|
486
|
+
type: 'pickup';
|
|
487
|
+
object: string;
|
|
488
|
+
container: string;
|
|
489
|
+
slot: number;
|
|
490
|
+
stack: ItemStack;
|
|
491
|
+
actor: string;
|
|
492
|
+
} | {
|
|
493
|
+
type: 'device';
|
|
494
|
+
object: string;
|
|
495
|
+
device: string;
|
|
496
|
+
on: boolean;
|
|
497
|
+
powered: boolean;
|
|
498
|
+
channel?: number;
|
|
499
|
+
} | {
|
|
500
|
+
type: 'switch';
|
|
501
|
+
object: string;
|
|
502
|
+
switch: string;
|
|
503
|
+
on: boolean;
|
|
504
|
+
} | {
|
|
505
|
+
type: 'fixture';
|
|
506
|
+
object: string;
|
|
507
|
+
fixture: string;
|
|
508
|
+
on: boolean;
|
|
509
|
+
flowing: boolean;
|
|
510
|
+
} | {
|
|
511
|
+
type: 'burner';
|
|
512
|
+
object: string;
|
|
513
|
+
burner: string;
|
|
514
|
+
on: boolean;
|
|
515
|
+
lit: boolean;
|
|
516
|
+
} | {
|
|
517
|
+
type: 'seat';
|
|
518
|
+
object: string;
|
|
519
|
+
seat: string;
|
|
520
|
+
actor: string;
|
|
521
|
+
seated: boolean;
|
|
522
|
+
} | {
|
|
523
|
+
type: 'damage';
|
|
524
|
+
object: string;
|
|
525
|
+
target: string;
|
|
526
|
+
hp: number;
|
|
527
|
+
destroyed: boolean;
|
|
528
|
+
} | {
|
|
529
|
+
type: 'explosion';
|
|
530
|
+
object: string;
|
|
531
|
+
pos: Vec3;
|
|
532
|
+
radius: number;
|
|
533
|
+
} | {
|
|
534
|
+
type: 'leak';
|
|
535
|
+
object: string;
|
|
536
|
+
target: string;
|
|
537
|
+
pos: Vec3;
|
|
538
|
+
} | {
|
|
539
|
+
type: 'message';
|
|
540
|
+
key: string;
|
|
541
|
+
text: string;
|
|
542
|
+
} | {
|
|
543
|
+
type: 'power';
|
|
544
|
+
grid: boolean;
|
|
545
|
+
}
|
|
546
|
+
/** A container without an access part was opened (open shelf): the host may show its contents. */
|
|
547
|
+
| {
|
|
548
|
+
type: 'container';
|
|
549
|
+
object: string;
|
|
550
|
+
container: string;
|
|
551
|
+
open: boolean;
|
|
552
|
+
};
|
|
553
|
+
/** World-space interaction, compatible with hosts that list `{id, tipo, pos, raio, rotulo, agir()}`. */
|
|
554
|
+
interface Interactable {
|
|
555
|
+
/** `objectId:interactionId`. */
|
|
556
|
+
id: string;
|
|
557
|
+
object: string;
|
|
558
|
+
kind: Action['do'];
|
|
559
|
+
pos: Vec3;
|
|
560
|
+
radius: number;
|
|
561
|
+
/** Current localized prompt as one phrase (`verb` + `object`). It never contains a key hint such as "E:"; the host adds its own. */
|
|
562
|
+
label: string;
|
|
563
|
+
/** Localized action word only, e.g. "Open" / "Abrir". */
|
|
564
|
+
verb: string;
|
|
565
|
+
/** Localized thing the verb applies to, e.g. "the fridge" / "a geladeira" (falls back to the object type name). Named `noun` because `object` is the owning object's id. */
|
|
566
|
+
noun: string;
|
|
567
|
+
/** False when the interaction cannot be used right now (see `reason`). `world.target` skips these unless `includeUnavailable`. */
|
|
568
|
+
available: boolean;
|
|
569
|
+
/** Locale key explaining why it is unavailable (`requires_open`, `no_power`, `locked`, `already_lit`, `needs_ignition`, `turn_on_first`); `world.t(reason)` is the text. */
|
|
570
|
+
reason?: string;
|
|
571
|
+
act(actor?: string): boolean;
|
|
572
|
+
}
|
|
573
|
+
/** Options of `world.target`. */
|
|
574
|
+
interface TargetOptions {
|
|
575
|
+
/** Meters from the eye (default 1.8). */
|
|
576
|
+
reach?: number;
|
|
577
|
+
/** Half angle of the view cone, radians (default 0.45). */
|
|
578
|
+
cone?: number;
|
|
579
|
+
/** Only candidates for which this returns true are considered. */
|
|
580
|
+
filter?: (interactable: Interactable) => boolean;
|
|
581
|
+
/** Only candidates whose `kind` is in this list are considered. */
|
|
582
|
+
kinds?: Action['do'][];
|
|
583
|
+
/** Also consider interactions that are not available right now (default false). */
|
|
584
|
+
includeUnavailable?: boolean;
|
|
585
|
+
}
|
|
586
|
+
/** Options of `world.colliders`. */
|
|
587
|
+
interface ColliderOptions {
|
|
588
|
+
/** Union overlapping or adjacent boxes of the same object into fewer OBBs (never loses coverage). Default false. */
|
|
589
|
+
merge?: boolean;
|
|
590
|
+
/** Largest gap between two boxes, meters, that still counts as adjacent when merging (default 0.02). */
|
|
591
|
+
gap?: number;
|
|
592
|
+
/** Extra volume a merge may add, as a fraction of the real union (default 0.1). */
|
|
593
|
+
slack?: number;
|
|
594
|
+
}
|
|
595
|
+
/** World-space solid collider (OBB on the floor plane plus a height range). */
|
|
596
|
+
interface WorldCollider {
|
|
597
|
+
id: string;
|
|
598
|
+
object: string;
|
|
599
|
+
cx: number;
|
|
600
|
+
cz: number;
|
|
601
|
+
hw: number;
|
|
602
|
+
hd: number;
|
|
603
|
+
ry: number;
|
|
604
|
+
y0: number;
|
|
605
|
+
y1: number;
|
|
606
|
+
}
|
|
607
|
+
interface ActiveEmitter {
|
|
608
|
+
id: string;
|
|
609
|
+
object: string;
|
|
610
|
+
kind: EmitterKind;
|
|
611
|
+
pos: Vec3;
|
|
612
|
+
dir: Vec3;
|
|
613
|
+
size: number;
|
|
614
|
+
/** Meters a water stream falls before it hits something; omitted = until the floor. */
|
|
615
|
+
reach?: number;
|
|
616
|
+
/** 0..1. */
|
|
617
|
+
intensity: number;
|
|
618
|
+
}
|
|
619
|
+
interface SeatResult {
|
|
620
|
+
/** World-space eye position and facing for the camera. */
|
|
621
|
+
eye: Vec3;
|
|
622
|
+
yaw: number;
|
|
623
|
+
pose: SeatPose;
|
|
624
|
+
}
|
|
625
|
+
interface WorldObject {
|
|
626
|
+
id: string;
|
|
627
|
+
spec: ObjectSpec;
|
|
628
|
+
transform: Transform;
|
|
629
|
+
/** Part t values right now (0..1). */
|
|
630
|
+
parts: Record<string, number>;
|
|
631
|
+
}
|
|
632
|
+
interface World {
|
|
633
|
+
/** Adds an object. `id` must be unique; returns it. */
|
|
634
|
+
add(id: string, spec: ObjectSpec, transform: Transform): WorldObject;
|
|
635
|
+
remove(id: string): void;
|
|
636
|
+
get(id: string): WorldObject | undefined;
|
|
637
|
+
objects(): WorldObject[];
|
|
638
|
+
/** Advance animations, sway, fuel, water and effects by `dt` seconds. */
|
|
639
|
+
update(dt: number): void;
|
|
640
|
+
/** Every interaction in world space, with current labels. */
|
|
641
|
+
interactables(): Interactable[];
|
|
642
|
+
/** Best interaction for an eye looking along yaw/pitch (radians, yaw 0 = -z), within reach. */
|
|
643
|
+
target(eye: {
|
|
644
|
+
x: number;
|
|
645
|
+
y: number;
|
|
646
|
+
z: number;
|
|
647
|
+
yaw: number;
|
|
648
|
+
pitch: number;
|
|
649
|
+
}, options?: TargetOptions): Interactable | null;
|
|
650
|
+
act(interactableId: string, actor?: string): boolean;
|
|
651
|
+
/** Parts */
|
|
652
|
+
partT(objectId: string, partId: string): number;
|
|
653
|
+
setPart(objectId: string, partId: string, target: number, instant?: boolean): void;
|
|
654
|
+
/**
|
|
655
|
+
* Turn a device on or off without an interaction (same effects and events as the toggle: part, `device` event, `no_power` message).
|
|
656
|
+
* Nothing happens (false) for an unknown device; setting the state it already has is a quiet `true`.
|
|
657
|
+
*/
|
|
658
|
+
setDevice(objectId: string, deviceId: string, on: boolean): boolean;
|
|
659
|
+
/** Same for a fixture (tap, shower, flush). */
|
|
660
|
+
setFixture(objectId: string, fixtureId: string, on: boolean): boolean;
|
|
661
|
+
/** Same for a burner; turning on a burner that needs ignition lights it (needs fuel). */
|
|
662
|
+
setBurner(objectId: string, burnerId: string, on: boolean): boolean;
|
|
663
|
+
/**
|
|
664
|
+
* Largest t in [0, 1] whose swept area stays clear. `blocked(x, z)` gets world coordinates. The world clamps the part to it.
|
|
665
|
+
* Call once after adding objects next to walls.
|
|
666
|
+
*/
|
|
667
|
+
fitSweep(objectId: string, partId: string, blocked: (x: number, z: number) => boolean): number;
|
|
668
|
+
/** Containers */
|
|
669
|
+
contents(objectId: string, containerId: string): Array<ItemStack | null>;
|
|
670
|
+
accessible(objectId: string, containerId: string): boolean;
|
|
671
|
+
take(objectId: string, containerId: string, slot: number, actor?: string): ItemStack | null;
|
|
672
|
+
put(objectId: string, containerId: string, stack: ItemStack): number | null;
|
|
673
|
+
/** World-space position of a slot right now (follows drawers and doors). */
|
|
674
|
+
slotPosition(objectId: string, containerId: string, slot: number): Vec3;
|
|
675
|
+
/** Power */
|
|
676
|
+
power: {
|
|
677
|
+
grid: boolean;
|
|
678
|
+
setGrid(on: boolean): void;
|
|
679
|
+
setBreaker(circuit: string, on: boolean): void;
|
|
680
|
+
breaker(circuit: string): boolean;
|
|
681
|
+
isPowered(objectId: string, deviceId: string): boolean;
|
|
682
|
+
isOn(objectId: string, deviceId: string): boolean;
|
|
683
|
+
/** Socket a device ended up plugged into (`objectId:socketId`) or null. */
|
|
684
|
+
pluggedInto(objectId: string, deviceId: string): string | null;
|
|
685
|
+
channel(objectId: string, deviceId: string): number;
|
|
686
|
+
};
|
|
687
|
+
/** Fuel */
|
|
688
|
+
fuelLevel(objectId: string, fuelId: string): number;
|
|
689
|
+
isLit(objectId: string, burnerId: string): boolean;
|
|
690
|
+
/** Water */
|
|
691
|
+
water: {
|
|
692
|
+
/** Default tank of the building (used by fixtures with `tank: 'auto'`). World-wide id `objectId:tankId`. */
|
|
693
|
+
setDefaultTank(tankId: string | null): void;
|
|
694
|
+
level(tankId: string): number;
|
|
695
|
+
refill(tankId: string, liters: number): number;
|
|
696
|
+
setRain(mmPerHour: number): void;
|
|
697
|
+
isFlowing(objectId: string, fixtureId: string): boolean;
|
|
698
|
+
};
|
|
699
|
+
/** Seats */
|
|
700
|
+
sit(objectId: string, seatId: string, actor?: string): SeatResult | null;
|
|
701
|
+
stand(actor?: string): Vec3 | null;
|
|
702
|
+
seatOf(actor?: string): {
|
|
703
|
+
object: string;
|
|
704
|
+
seat: string;
|
|
705
|
+
} | null;
|
|
706
|
+
/** Soft volumes: an actor at `pos` with `radius` moving at `vel` pushes nearby soft volumes. Never blocks. */
|
|
707
|
+
push(pos: Vec3, radius: number, vel: Vec3): void;
|
|
708
|
+
/** Current swing of a soft volume: rotation around the anchor line, radians, x (front/back) and z (sideways). */
|
|
709
|
+
sway(objectId: string, softId: string): {
|
|
710
|
+
ax: number;
|
|
711
|
+
az: number;
|
|
712
|
+
};
|
|
713
|
+
setWind(x: number, z: number): void;
|
|
714
|
+
/** Effects the host should draw now. */
|
|
715
|
+
emitters(): ActiveEmitter[];
|
|
716
|
+
/** Mirrors facing `eye` within `maxDistance`, nearest first (world ids `objectId:mirrorId`). */
|
|
717
|
+
mirrors(eye: Vec3, maxDistance?: number, count?: number): Array<{
|
|
718
|
+
id: string;
|
|
719
|
+
center: Vec3;
|
|
720
|
+
normal: Vec3;
|
|
721
|
+
w: number;
|
|
722
|
+
h: number;
|
|
723
|
+
distance: number;
|
|
724
|
+
}>;
|
|
725
|
+
/** Solid colliders in world space (OBB on the floor plane plus height range). Soft volumes never appear here. */
|
|
726
|
+
colliders(options?: ColliderOptions): WorldCollider[];
|
|
727
|
+
/** Damage */
|
|
728
|
+
/** @deprecated Use the destruction SDK (`@adatechnology/game-destruction`). */
|
|
729
|
+
damage(objectId: string, target: string, amount: number, kind?: string): {
|
|
730
|
+
hp: number;
|
|
731
|
+
destroyed: boolean;
|
|
732
|
+
} | null;
|
|
733
|
+
hp(objectId: string, target: string): number | null;
|
|
734
|
+
/** Localized text. */
|
|
735
|
+
t(key: string, vars?: Record<string, string | number>): string;
|
|
736
|
+
setLocale(locale: string): void;
|
|
737
|
+
/** Plain JSON state (parts, contents, power, fuel, water, seats) for saves and LAN sync. */
|
|
738
|
+
serialize(): WorldState;
|
|
739
|
+
load(state: WorldState): void;
|
|
740
|
+
}
|
|
741
|
+
interface WorldState {
|
|
742
|
+
version: 1;
|
|
743
|
+
objects: Record<string, {
|
|
744
|
+
parts: Record<string, number>;
|
|
745
|
+
contents: Record<string, Array<ItemStack | null>>;
|
|
746
|
+
devices: Record<string, {
|
|
747
|
+
on: boolean;
|
|
748
|
+
channel: number;
|
|
749
|
+
}>;
|
|
750
|
+
fuels: Record<string, {
|
|
751
|
+
level: number;
|
|
752
|
+
open: boolean;
|
|
753
|
+
}>;
|
|
754
|
+
burners: Record<string, {
|
|
755
|
+
on: boolean;
|
|
756
|
+
lit: boolean;
|
|
757
|
+
}>;
|
|
758
|
+
tanks: Record<string, number>;
|
|
759
|
+
fixtures: Record<string, boolean>;
|
|
760
|
+
hp: Record<string, number>;
|
|
761
|
+
}>;
|
|
762
|
+
grid: boolean;
|
|
763
|
+
breakers: Record<string, boolean>;
|
|
764
|
+
seats: Record<string, {
|
|
765
|
+
object: string;
|
|
766
|
+
seat: string;
|
|
767
|
+
}>;
|
|
768
|
+
defaultTank: string | null;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
declare function createWorld(options?: WorldOptions): World;
|
|
772
|
+
|
|
773
|
+
/** FNV-1a hash of a string to a 32-bit unsigned integer. */
|
|
774
|
+
declare function hashString(text: string): number;
|
|
775
|
+
/** Deterministic random generator (mulberry32). Returns a function producing floats in [0, 1). Numbers and strings are accepted as seeds. */
|
|
776
|
+
declare function rng(seed?: number | string): () => number;
|
|
777
|
+
|
|
778
|
+
/** True when an item of `size` [w, h, d] fits in a slot of `max`; width and depth may be swapped (the item is turned). */
|
|
779
|
+
declare function fitsSize(size: Vec3, max: Vec3): boolean;
|
|
780
|
+
/** Does the item type fit the slot. Types missing from the catalog are accepted (the host owns unknown items). */
|
|
781
|
+
declare function fitsSlot(type: string, slot: SlotSpec, items?: ItemCatalog): boolean;
|
|
782
|
+
/**
|
|
783
|
+
* Deterministic contents for a container: one entry per slot. A slot is filled with probability `fill`; the entry is a weighted pick
|
|
784
|
+
* among the table entries whose item fits the slot. Same seed, same table and same slots always give the same result.
|
|
785
|
+
*/
|
|
786
|
+
declare function generateLoot(tables: LootTables | undefined, tableId: string, slots: SlotSpec[], seed: number | string, items?: ItemCatalog): Array<ItemStack | null>;
|
|
787
|
+
|
|
788
|
+
interface Pose {
|
|
789
|
+
/** Translation relative to the pivot. */
|
|
790
|
+
position: Vec3;
|
|
791
|
+
/** Rotation around `axis` (in the part frame) by `angle` radians. */
|
|
792
|
+
rotation: {
|
|
793
|
+
axis: Vec3;
|
|
794
|
+
angle: number;
|
|
795
|
+
};
|
|
796
|
+
scale: Vec3;
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* Pose of a part at animation value `t` (0..1), relative to its pivot, so any renderer can apply it:
|
|
800
|
+
* `position`, then `rotation` around the pivot, then `scale` along the axis.
|
|
801
|
+
*/
|
|
802
|
+
declare function poseOf(motion: Motion, t: number): Pose;
|
|
803
|
+
/** Rotate a vector around +y by `ry` radians (same convention as three.js `rotation.y`). */
|
|
804
|
+
declare function rotY(v: Vec3, ry: number): Vec3;
|
|
805
|
+
/** Object-local point to world space. */
|
|
806
|
+
declare function localToWorld(transform: Transform, v: Vec3): Vec3;
|
|
807
|
+
/** World point to object-local space. */
|
|
808
|
+
declare function worldToLocal(transform: Transform, v: Vec3): Vec3;
|
|
809
|
+
/** Rodrigues rotation of `v` around a unit-length-normalised `axis` by `angle`. */
|
|
810
|
+
declare function rotateAxis(v: Vec3, axis: Vec3, angle: number): Vec3;
|
|
811
|
+
|
|
812
|
+
/** Engine-level prompts and messages. Content packs add their own keys through `WorldOptions.strings`. */
|
|
813
|
+
declare const locales: Record<InteractablesLocale, Strings>;
|
|
814
|
+
/** Pick a built-in locale for an arbitrary tag (`pt`, `pt-br`, `en-GB`...). Unknown tags give `en`. */
|
|
815
|
+
declare function pickLocale(locale: string | undefined): InteractablesLocale;
|
|
816
|
+
/**
|
|
817
|
+
* Merged table for a locale: built-in `en`, then the built-in table of `locale`, then the extra strings for `en` and for `locale`.
|
|
818
|
+
* Lookup therefore falls back to English, and the caller never gets undefined for engine keys.
|
|
819
|
+
*/
|
|
820
|
+
declare function resolveStrings(locale?: string, extra?: Partial<Record<InteractablesLocale, Strings>>): Strings;
|
|
821
|
+
/** Replace `{name}` placeholders. Unknown placeholders are left untouched. */
|
|
822
|
+
declare function format(text: string, vars?: Record<string, string | number>): string;
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* Union overlapping or adjacent colliders of the same object (same rotation) into fewer OBBs.
|
|
826
|
+
* A merge happens only when the merged box adds at most `slack` extra volume over the real union, so coverage is never lost
|
|
827
|
+
* and never grows noticeably. Colliders of different objects or rotations are left alone.
|
|
828
|
+
*/
|
|
829
|
+
declare function mergeColliders(list: WorldCollider[], options?: Pick<ColliderOptions, 'gap' | 'slack'>): WorldCollider[];
|
|
830
|
+
|
|
831
|
+
export { type Action, type ActiveEmitter, type BurnerSpec, type ColliderOptions, type ColliderSpec, type ContainerSpec, type DamageKind, type DamageSpec, type DestructionDelegate, type DestructionJoint, type DeviceKind, type DeviceSpec, type EmitterKind, type EmitterSpec, type FixtureKind, type FixtureSpec, type FuelSourceSpec, type Interactable, type InteractablesLocale, type InteractionSpec, type ItemCatalog, type ItemDef, type ItemStack, type LootEntry, type LootTable, type LootTables, type MirrorSpec, type Motion, type MotionKind, type ObjectSpec, type PartDestruction, type PartSpec, type Pose, type Rect, type SeatPose, type SeatResult, type SeatSpec, type SlotSpec, type SocketSpec, type SoftSpec, type Strings, type SwitchSpec, type TankSpec, type TargetOptions, type Transform, type Vec3, type World, type WorldCollider, type WorldEvent, type WorldObject, type WorldOptions, type WorldState, createWorld, fitsSize, fitsSlot, format, generateLoot, hashString, localToWorld, locales, mergeColliders, pickLocale, poseOf, resolveStrings, rng, rotY, rotateAxis, worldToLocal };
|