@adatechnology/game-contracts 0.21.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -58,6 +58,8 @@ Hits arrive in world space and events go out in world space. `checkDestructible`
58
58
  well-formed and JSON-serializable. The contracts package does not know your materials: pass their ids (the world's `world.materials.keys()`) or
59
59
  leave `materials` out to skip that check.
60
60
 
61
+ **Cost contract (D8):** the host reads `describe()` and `state()` per part per frame, so both are O(1), allocation-free and cached between changes (the same object comes back until a hit, tool, fire or pose change). `checkDestructible(impl, { cost: true })` (or `cost: { reads, ceilingMs, allocationBytes }`) reads each 10 000 times and fails on a new object per read, on time over the ceiling (default 50 ms) and, in Node, on heap growth over the ceiling (default 1 MiB).
62
+
61
63
  ### Weapons
62
64
 
63
65
  ```ts
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export { w as warnOnce } from './testing-CJY18EZK.js';
2
+
1
3
  /**
2
4
  * Destruction contract: the types a game module and a destruction world share. A module (vehicle, furniture, plant, house, weapon) describes
3
5
  * itself with these and never needs the default destruction world; the world, the renderer and the test room consume them.
@@ -405,6 +407,8 @@ interface Hit {
405
407
  duration?: number;
406
408
  /** `world` (default) or `local` to the object. */
407
409
  space?: 'world' | 'local';
410
+ /** The normal of the surface at `point`, when the ray that found it knows it. */
411
+ normal?: Vec3;
408
412
  /** Who caused it (passed through to events). */
409
413
  source?: string;
410
414
  /** Projectile mass in grams (ballistic): the penetration of a body needs it, the energy alone does not say how much a bullet pushes. */
@@ -981,6 +985,15 @@ declare function blastShove(blast: BlastSource, target: {
981
985
  readonly mass: number;
982
986
  }, options?: BlastShoveOptions): BlastShove | undefined;
983
987
 
988
+ interface CostOptions {
989
+ /** Reads of `state()` and of `describe()` to time. Default 10 000. */
990
+ reads?: number;
991
+ /** Ceiling, in milliseconds, for all the reads of one method. Default 50 (5 microseconds per read). */
992
+ ceilingMs?: number;
993
+ /** Ceiling of heap growth, in bytes, over all the reads of one method (only where `process.memoryUsage` exists). Default 1 MiB. */
994
+ allocationBytes?: number;
995
+ }
996
+
984
997
  /**
985
998
  * What a game module implements for an object whose behaviour it owns (a vehicle with its own panel deformation, a creature, a machine). The
986
999
  * world (`DestructionWorld.register`) hosts it next to its own objects: raycast, shoot, explode, hit, disassemble, extinguish, update, state,
@@ -990,17 +1003,47 @@ declare function blastShove(blast: BlastSource, target: {
990
1003
  * `setTransform` is only used by the world for raycasts and blast range). Every event must carry `object === id` and name parts listed by
991
1004
  * `describe()`.
992
1005
  */
1006
+ /** World-space ray for `DestructibleImpl.surfaceRay`. */
1007
+ interface SurfaceRay {
1008
+ readonly origin: Vec3;
1009
+ readonly direction: Vec3;
1010
+ readonly maxDistance: number;
1011
+ ignored?(part: string): boolean;
1012
+ }
1013
+ interface SurfaceRayHit {
1014
+ readonly part: string;
1015
+ readonly point: Vec3;
1016
+ readonly normal: Vec3;
1017
+ readonly distance: number;
1018
+ /** Thickness the ray crosses in this part, metres. */
1019
+ readonly pathLen: number;
1020
+ }
993
1021
  interface DestructibleImpl {
994
1022
  readonly id: string;
995
1023
  readonly name?: string;
996
- /** Parts, joints and structure in the impl's local space, for raycast, inspector and log. Called often: keep it cheap. */
1024
+ /**
1025
+ * Parts, joints and structure in the impl's local space, for raycast, inspector and log.
1026
+ * COST CONTRACT (D8): called per frame by the renderer, so it is O(1), allocation-free and cached between changes: the same object comes
1027
+ * back until a hit, tool, fire or pose change alters it. `checkDestructible(impl, { cost: true })` measures it.
1028
+ */
997
1029
  describe(): DestructibleSpec;
998
1030
  /** Apply one hit (see `IMPACT_CONTRACT` for the fields per type) and return the events it caused. */
999
1031
  hit(hit: Hit): DestructionEvent[];
1032
+ /**
1033
+ * The real surface a ray meets, for an impl whose drawn shape is not its boxes (a car body): the boxes of `describe()` only say where to look, and a shot that crosses
1034
+ * them without touching the drawn surface goes on. `ignored` answers for the parts the round already went through. Null when the ray meets nothing.
1035
+ */
1036
+ surfaceRay?(ray: SurfaceRay): SurfaceRayHit | null;
1000
1037
  /** Advance fire, melting, collapse and other timed behaviour. */
1001
1038
  update?(dt: number): DestructionEvent[];
1002
- state(): ObjectState;
1039
+ /**
1040
+ * COST CONTRACT (D8): the host reads it per part per frame, so it is O(1), allocation-free and cached between changes (see `describe()`).
1041
+ * The cached object is shared with every reader: treat it as read-only, copy before changing it.
1042
+ */
1043
+ state(): Readonly<ObjectState>;
1003
1044
  reset?(): void;
1045
+ /** The world took the object out (`DestructionWorld.remove`): the impl lets go of what it joined (shared queues, listeners). */
1046
+ dispose?(): void;
1004
1047
  /** Same contract as `DestructionWorld.disassemble`: progress 0..1, or -1 when the tool cannot undo the joint. */
1005
1048
  disassemble?(jointId: string, tool: ToolKind, dt: number): number;
1006
1049
  extinguish?(partId?: string): void;
@@ -1025,11 +1068,13 @@ interface CheckOptions {
1025
1068
  * `world.materials`, or the built-in plus your own). When omitted, the material check is skipped.
1026
1069
  */
1027
1070
  materials?: Iterable<string>;
1071
+ /** Opt-in cost measurement (D8): `true` for the defaults, or the limits to use. */
1072
+ cost?: boolean | CostOptions;
1028
1073
  }
1029
1074
  /**
1030
1075
  * Contract checker for the test room (it needs no world): `describe()` is valid, a 500 J ballistic hit at a part centre returns well-formed events of this impl, `state()`
1031
1076
  * matches `describe()`, hit points never go negative, `update(0.016)` returns an array and every event is JSON-serializable. It hits the impl
1032
- * (and calls `reset()` afterwards when there is one).
1077
+ * (and calls `reset()` afterwards when there is one). With `options.cost` it also times `state()` and `describe()` (the cost contract of D8).
1033
1078
  */
1034
1079
  declare const checkDestructible: (impl: DestructibleImpl, options?: CheckOptions) => {
1035
1080
  ok: boolean;
@@ -1715,6 +1760,8 @@ interface SoundRequest {
1715
1760
  readonly params?: Readonly<Record<string, number>>;
1716
1761
  /** Seed for the sound's own random stream: same seed, same sound. */
1717
1762
  readonly seed?: number;
1763
+ /** Seconds from now (the hit of a blow after its swing); the host schedules it on the audio clock, not on a timer. */
1764
+ readonly delay?: number;
1718
1765
  }
1719
1766
  /** What `AudioSink.play` hands back; opaque to the module, given back to `stop`. */
1720
1767
  interface SoundHandle {
@@ -1785,6 +1832,143 @@ interface EnvironmentBus {
1785
1832
  /** A plain store that implements the bus; the test room and tests use it, a game may bring its own. */
1786
1833
  declare function createEnvironmentBus(initial?: Partial<EnvironmentState>): EnvironmentBus;
1787
1834
 
1835
+ /**
1836
+ * The sounds of a body (footsteps, jumps, landings, blows, hurt), as ids every package agrees on: the rule that knows what the body did
1837
+ * (`game-player`, a host's own player) names the sound, and the bank that knows how it sounds (`game-audio`'s `BODY_FOLEY_BANK`) answers it.
1838
+ * A game swaps the sound of an id (a sample instead of the synthesis) without touching the rule.
1839
+ */
1840
+ /** What the feet touch, by how it sounds (not by what it is made of: a wooden floor and a plywood board both sound `wood`). */
1841
+ declare const SURFACE_IDS: readonly ["concrete", "asphalt", "wood", "tile", "dirt", "grass", "gravel", "sand", "metal", "water", "glass", "carpet"];
1842
+ type SurfaceId = (typeof SURFACE_IDS)[number];
1843
+ /** The surface a body stands on when nobody says (the test room's floor is a concrete slab). */
1844
+ declare const DEFAULT_SURFACE: SurfaceId;
1845
+ /** How the feet move: a run hits harder and shorter; a crouched step is the walk, quieter. */
1846
+ declare const GAIT_IDS: readonly ["walk", "run"];
1847
+ type GaitId = (typeof GAIT_IDS)[number];
1848
+ /** How hard a landing is: `light` for a jump on the spot or a step down (up to about 5 m/s), `heavy` for a drop of more than a metre and a half. */
1849
+ declare const LANDING_IDS: readonly ["light", "heavy"];
1850
+ type LandingId = (typeof LANDING_IDS)[number];
1851
+ /** The fall speed (m/s) from which a landing is `heavy`. */
1852
+ declare const HEAVY_LANDING_SPEED = 5.5;
1853
+ type FootstepSoundId = `footstep_${SurfaceId}_${GaitId}`;
1854
+ type LandSoundId = `land_${SurfaceId}_${LandingId}`;
1855
+ /**
1856
+ * How a blow is struck, by the body part or the tool that does it. `blade` stabs or slashes, `blunt` is a club, a bat, a pipe or a hammer, `chop` an
1857
+ * axe or a machete driven down.
1858
+ */
1859
+ declare const BLOW_IDS: readonly ["punch", "kick", "shove", "blade", "blunt", "chop"];
1860
+ type BlowId = (typeof BLOW_IDS)[number];
1861
+ /** What the blow meets: a body (flesh and bone, the head apart), something else (the material answers with its own impact), or nothing. */
1862
+ type BlowTarget = 'body' | 'head' | 'object' | 'air';
1863
+ /** The sounds of the body that are not a footstep or a landing. */
1864
+ declare const BODY_SOUND_IDS: readonly ["jump", "cloth_rustle", "body_fall", "fall_damage", "player_hurt", "player_breath_run", "player_death", "bite", "grab", "punch_swing", "punch_hit_body", "punch_hit_face", "punch_hit_object", "kick_swing", "kick_hit", "kick_hit_object", "shove_two_hands", "knife_swing", "knife_stab", "knife_slash", "knife_hit_object", "blunt_swing", "blunt_hit", "blunt_hit_object", "axe_swing", "axe_chop", "axe_hit_object"];
1865
+ type BodySoundId = (typeof BODY_SOUND_IDS)[number];
1866
+ /** Every sound of a body: what a host plays for the player, a survivor or a zombie. */
1867
+ type BodyFoleyId = FootstepSoundId | LandSoundId | BodySoundId;
1868
+ declare const footstepSoundId: (surface: SurfaceId, gait: GaitId) => FootstepSoundId;
1869
+ declare const landSoundId: (surface: SurfaceId, fallSpeed: number) => LandSoundId;
1870
+ /** Every footstep and landing id, in the order of the surfaces. */
1871
+ declare const FOOTSTEP_SOUND_IDS: readonly FootstepSoundId[];
1872
+ declare const LAND_SOUND_IDS: readonly LandSoundId[];
1873
+ declare const BODY_FOLEY_IDS: readonly BodyFoleyId[];
1874
+ /**
1875
+ * Seconds from the start of a swing's sound to its loudest point (the limb or the tool at full speed, just before the contact). A host that knows when the
1876
+ * blow lands starts the swing this long before; one that does not plays the swing now and the hit this long after.
1877
+ */
1878
+ declare const SWING_LEAD_SECONDS: Readonly<Record<BlowId, number>>;
1879
+ /** The swing through the air, played as the blow starts (`null`: the blow has none). */
1880
+ declare const swingSoundId: (blow: BlowId) => BodySoundId | null;
1881
+ /**
1882
+ * The body's side of a blow that lands: the knuckles, the shoe, the blade or the club meeting what it hit. On an object the material's own impact
1883
+ * plays too (the wood, the metal); this is the part that says it was a punch and not a shot.
1884
+ */
1885
+ declare const hitSoundId: (blow: BlowId, target: Exclude<BlowTarget, "air">) => BodySoundId;
1886
+ /**
1887
+ * The surface a material sounds like underfoot, by the material ids of `game-destruction` and `game-terrain` (unknown ids: `fallback`). Data, so
1888
+ * a game with its own materials passes its own table to `surfaceOfMaterial`.
1889
+ */
1890
+ declare const MATERIAL_SURFACES: Readonly<Record<string, SurfaceId>>;
1891
+ declare const isSurfaceId: (value: unknown) => value is SurfaceId;
1892
+ /** The surface of a material id; a surface id passes through. */
1893
+ declare function surfaceOfMaterial(material: string | undefined, table?: Readonly<Record<string, SurfaceId>>, fallback?: SurfaceId): SurfaceId;
1894
+
1895
+ declare const FRAME_PHASES: readonly ["input", "fixedSimulate", "lateSimulate", "present", "render", "idle"];
1896
+ type FramePhase = (typeof FRAME_PHASES)[number];
1897
+ /**
1898
+ * Presentation work a system leaves for later frames, run in small units within a shared time budget.
1899
+ * Never simulation: nothing that consumes a seeded generator or decides an outcome may wait in a queue.
1900
+ */
1901
+ interface DeferredQueue {
1902
+ /** Stable name for stats and logs (see `DEFERRED_QUEUE_ID`). */
1903
+ readonly id: string;
1904
+ /**
1905
+ * Units waiting. 0 means idle; the budget skips the queue without calling `run`. `frame` is the budget's frame counter: a queue may
1906
+ * report 0 for the rest of a frame (the crease queue does in the frame a panel was torn). Same value for repeated calls in one frame.
1907
+ */
1908
+ pending(frame?: number): number;
1909
+ /**
1910
+ * Runs units in order until `clock() >= deadline`. Contract: when `pending() > 0` it runs **at least one** unit, even with a deadline
1911
+ * already past; it never runs a unit after it saw the deadline pass. Returns how many units it ran.
1912
+ */
1913
+ run(deadline: number, clock: () => number): number;
1914
+ /** Runs everything now (synchronous step, clear, dispose). */
1915
+ flush(): void;
1916
+ /**
1917
+ * Called by `budget.register`: from now on the owner stops draining on its own (no MessageChannel, no drain inside `update`).
1918
+ * Never called by a getter; a queue nobody registered keeps today's internal draining.
1919
+ */
1920
+ attach?(): void;
1921
+ /** Called by the unregister function and by `budget.dispose`: the owner goes back to its internal draining. */
1922
+ detach?(): void;
1923
+ }
1924
+ /** Where a module registers a deferred queue with the host's budget. */
1925
+ interface DeferredQueueOptions {
1926
+ /** Higher runs first. See DEFERRED_PRIORITY. */
1927
+ readonly priority: number;
1928
+ /** `present` runs before the render (the work must show this frame); `idle` runs after it. Default `idle`. */
1929
+ readonly phase?: 'present' | 'idle';
1930
+ /** Starvation guard: the queue runs at least one unit every this many frames, even with the budget spent. Default 4. */
1931
+ readonly minEveryFrames?: number;
1932
+ /** Milliseconds of every frame kept for this queue before the others share the rest (when it has work). Default 0. */
1933
+ readonly reserveMs?: number;
1934
+ }
1935
+ /** The ids of the kit's queues: what `DeferredQueue.id` says and what `DEFERRED_PRIORITY` is keyed by. */
1936
+ declare const DEFERRED_QUEUE_ID: {
1937
+ readonly DESTRUCTION_EVENTS: "destruction.events";
1938
+ readonly BREACH_PAINT: "floorplan.breach-paint";
1939
+ readonly AUDIO_VOICES: "audio.voices";
1940
+ readonly VEHICLE_CREASE: "vehicles.crease";
1941
+ };
1942
+ /** Default priorities and reserves of the kit's queues; a host may override any of them. */
1943
+ declare const DEFERRED_PRIORITY: {
1944
+ readonly "destruction.events": {
1945
+ readonly priority: 300;
1946
+ readonly phase: "present";
1947
+ };
1948
+ readonly "floorplan.breach-paint": {
1949
+ readonly priority: 250;
1950
+ readonly phase: "present";
1951
+ };
1952
+ readonly "audio.voices": {
1953
+ readonly priority: 200;
1954
+ readonly phase: "idle";
1955
+ readonly reserveMs: 1;
1956
+ };
1957
+ readonly "vehicles.crease": {
1958
+ readonly priority: 100;
1959
+ readonly phase: "idle";
1960
+ };
1961
+ };
1962
+ interface DeferredQueueReport {
1963
+ readonly ok: boolean;
1964
+ readonly problems: readonly string[];
1965
+ }
1966
+ /**
1967
+ * Checks the `DeferredQueue` contract. `fill` leaves the queue with at least two units waiting (the same call is made on a fresh queue).
1968
+ * It cannot prove the queue only carries presentation work: that is a rule of review.
1969
+ */
1970
+ declare function checkDeferredQueue(queue: DeferredQueue, fill: () => void): DeferredQueueReport;
1971
+
1788
1972
  /** An item that holds a liquid (a cup, a bottle, a fuel tank). `part` is the destruction part that is the container; a hole in it makes it leak. */
1789
1973
  interface ModuleItemFluid {
1790
1974
  container: ContainerSpec;
@@ -2048,6 +2232,17 @@ type HostEvent =
2048
2232
  /** The player crouched or stood up, or the camera mode changed; read the new state with `host.player()`. */
2049
2233
  | {
2050
2234
  type: 'player';
2235
+ }
2236
+ /**
2237
+ * A foot of the player's body touched the ground, at the frame the body's walk puts it down (the host's avatar, or the host's own stride without one):
2238
+ * `surface` is what is under it. A module that owns the footsteps (their sound and their noise) steps on this instead of its own timer.
2239
+ */
2240
+ | {
2241
+ type: 'footfall';
2242
+ foot: 'left' | 'right';
2243
+ surface: SurfaceId;
2244
+ gait: GaitId;
2245
+ position: Vec3;
2051
2246
  };
2052
2247
  /** The tool in hand as the host sees it. */
2053
2248
  interface HostTool {
@@ -2140,10 +2335,21 @@ interface HostReach {
2140
2335
  /** The hand is on the handle. */
2141
2336
  onGrip?(): void;
2142
2337
  }
2338
+ interface FrameOptions {
2339
+ /** Default `lateSimulate`, which is where every `onFrame` runs without options. */
2340
+ readonly phase?: Exclude<FramePhase, 'render'>;
2341
+ /** Lower runs first inside the phase; ties keep the order of registration. Default 0. */
2342
+ readonly order?: number;
2343
+ }
2143
2344
  /**
2144
2345
  * What the host lends a module that brings its own presentation (a weapon in the hands, sounds, ejected casings). `THREE`, `scene` and `camera`
2145
2346
  * are the host's three.js namespace, scene and camera: `unknown` here because the contracts do not depend on three.js.
2146
2347
  */
2348
+ interface HostGraphics {
2349
+ hordeDetail(): 'auto' | number;
2350
+ onChange(listener: () => void): () => void;
2351
+ report(key: string, value: number): void;
2352
+ }
2147
2353
  interface ModuleHost {
2148
2354
  THREE: unknown;
2149
2355
  scene: unknown;
@@ -2151,13 +2357,17 @@ interface ModuleHost {
2151
2357
  locale: string;
2152
2358
  /** Height of whatever things rest on at (x, z): the floor, a table, a counter. */
2153
2359
  groundAt(x: number, z: number): number;
2360
+ /** Material id of the floor at (x, z) (`concrete`, `soil`, `wood_hard`...): what a dropped case or a footstep lands on. Optional; undefined where the host does not know. */
2361
+ surfaceAt?(x: number, z: number): string | undefined;
2154
2362
  tool(): HostTool;
2155
2363
  /** The player now: where, which way, crouching, how fast and how the camera follows. A `player` event tells when crouching or the camera mode changes. */
2156
2364
  player(): PlayerState;
2157
2365
  /** Follow the player's tool events. Returns the unsubscribe function. */
2158
2366
  on(listener: (event: HostEvent) => void): () => void;
2159
- /** Run every simulated frame with the frame's seconds. Returns the unsubscribe function. */
2160
- onFrame(update: (dt: number) => void): () => void;
2367
+ /** Run every simulated frame with the frame's seconds (in the given phase, `lateSimulate` by default). Returns the unsubscribe function. */
2368
+ onFrame(update: (dt: number) => void, options?: FrameOptions): () => void;
2369
+ /** Registers a deferred queue with the host's frame budget. Returns the function that takes it out. A host without a budget leaves it out. */
2370
+ defer?(queue: DeferredQueue, options: DeferredQueueOptions): () => void;
2161
2371
  /**
2162
2372
  * Follow the host clearing its area (`clear()`, opening an area, running scenarios): everything the module put in the world on its own (not as items) is to be taken away or put back. Returns the
2163
2373
  * unsubscribe function. A host that never clears leaves it out.
@@ -2170,6 +2380,12 @@ interface ModuleHost {
2170
2380
  onReset?(listener: () => void): () => void;
2171
2381
  /** Write a line to the host's behaviour log; `type` is the kind of entry (default `module_note`), so a module can log what a filter looks for (`sound`). */
2172
2382
  log(text: string, data?: Record<string, unknown>, type?: string): void;
2383
+ /**
2384
+ * The player's graphics settings, for what a module draws on its own (a horde): `hordeDetail` is `auto` (the module's renderer adapts by itself) or the share of
2385
+ * its level-of-detail budget the player fixed, 0.1 to 1. `onChange` tells when it changes; `report` says what an adapting renderer draws now, so the settings
2386
+ * screen can show it (`hordeDetail`: the share in use). A host without graphics settings leaves it out.
2387
+ */
2388
+ graphics?: HostGraphics;
2173
2389
  /**
2174
2390
  * Sets what the host lets a module tune on its tools, keyed by the id of the module's own control (`ModuleControl.id`) with the id of the option as the value; the tool in hand changes at once and the
2175
2391
  * ones taken later start that way. A host applies the ids it knows and ignores the rest. The test room knows `condition` (how worn the tools are) and `ammo_quality` (how good what they load is).
@@ -2220,6 +2436,12 @@ interface ModuleHost {
2220
2436
  environment?: EnvironmentBus;
2221
2437
  /** The host's effects (smoke, sparks, blast, impacts): a module asks for them by id instead of drawing its own. Absent when the host has none. */
2222
2438
  effects?: EffectSink;
2439
+ /** The most loose bodies a module may keep alive at once (ejected casings, dropped magazines), read at each spawn: the host's one budget. Absent when the host keeps no budget of its own. */
2440
+ particleLimit?: () => number | undefined;
2441
+ /** The host's light budget (`LightBudget` of `@adatechnology/game-render-three`; `unknown` here because the contracts do not depend on three.js): the one owner of point and spot lights. Read it with `isLightBudget`. Absent when the host has none. */
2442
+ lights?: unknown;
2443
+ /** The host's pools of geometries and materials (`RenderPools` of `@adatechnology/game-render-three`; `unknown` here because the contracts do not depend on three.js): what an effect asks for instead of making its own, so its shader programs stay linked. Read it with `isRenderPools`. Absent when the host has none. */
2444
+ pools?: unknown;
2223
2445
  /**
2224
2446
  * The numbers of the shove a blast gives to a body. A module that moves bodies of its own (people, vehicles) answers the `explosion` host event with `blastShove(event, body, host.blastShove)`
2225
2447
  * so that it throws things the way the host throws its loose items. Absent when the host keeps the defaults.
@@ -2352,8 +2574,9 @@ type DeepPartial<TValue> = TValue extends (...args: never[]) => unknown ? TValue
2352
2574
  declare const deepMerge: <TBase extends object>(base: TBase, patch: object | undefined) => TBase;
2353
2575
  /** The shipped entries with the ones from `extra` added or, when the id exists, replaced. */
2354
2576
  declare const mergeById: <TEntry extends Entry>(shipped: readonly TEntry[], extra: readonly TEntry[] | undefined) => Map<string, TEntry>;
2355
- /** Applies `patch` by id; a patch for an id that does not exist is ignored. */
2577
+ /** Applies `patch` by id; a patch for an id that does not exist is ignored (and warned about once, in development). */
2356
2578
  declare const applyPatches: <TEntry extends Entry>(entries: Map<string, TEntry>, patches: Readonly<Record<string, DeepPartial<TEntry> | Partial<TEntry>>> | undefined) => void;
2579
+ /** Takes the ids out; an id that does not exist is ignored (and warned about once, in development). */
2357
2580
  declare const removeIds: (entries: Map<string, unknown>, ids: readonly string[] | undefined) => void;
2358
2581
 
2359
2582
  /** One category (kind) of items. Defaults and required contracts are inherited from the `extends` chain. */
@@ -2470,4 +2693,12 @@ interface FootprintObject {
2470
2693
  */
2471
2694
  declare function footprintBlocker(object: FootprintObject | (() => FootprintObject | null | undefined), footprint: Footprint | (() => Footprint | null | undefined)): (x: number, z: number, radius: number) => boolean;
2472
2695
 
2473
- export { type ActionControl, type AnimationClipSpec, type AnimationEventSpec, type AnimationKey, type AnimationPose, type AreaPlacement, type AudioListener, type AudioSink, type BallisticExtras, type BenchChange, type BenchDeclaration, type BenchReport, type BenchSheet, type BlastOptions, type BlastReport, type BlastShove, type BlastShoveOptions, type BlastSource, type BodyRegion, type BodySlot, type BooleanControl, type BusyOptions, type BusySink, type BusyTask, type CategorizedOptions, type CategorizedReport, type CategoryDef, type CategoryOptions, type CategoryRegistry, type ChainDelay, type CheckOptions, type CheckSpecOptions, type ChoiceControl, type ChoiceOption, type ConfinementOptions, type ContainerSpec, type ContractChecker, type ContractContext, type ControlPatch, type ControlValue, type Crack, DEFAULT_BLAST_SHOVE, DEFAULT_ENVIRONMENT, DEFAULT_IGNITION_RULES, type DamageStage, type DamageType, type DebrisKind, type DeepPartial, type Dent, type DestructibleImpl, type DestructibleSpec, type DestructionEvent, type DestructionEventType, type EffectHandle, type EffectRequest, type EffectSink, type Enclosure, type EnclosureBox, type EnvironmentBus, type EnvironmentKey, type EnvironmentState, type ExplosionChain, type FluidKind, type Footprint, type FootprintObject, type FractureStyle, type Fragment, type FragmentHitOptions, type FragmentMark, type GroundLayout, type GroundZone, type HandPose, type HandTargetSource, type HandTargets, type Hit, type HitIgnition, type HitResult, type Hole, type HostEvent, type HostReach, type HostTool, type HostToolAttachment, IMPACT_CONTRACT, type IgnitionRules, type ImpactContract, type ItemAnimationContract, type ItemSeat, type ItemUseDef, type JointKind, type JointSpec, type JointState, KIT_ORIGIN_KEY, type KitOrigin, type LiquidId, type LoopHandle, MISSING_BITS, type MaterialId, type ModuleArea, type ModuleBench, type ModuleControl, type ModuleHost, type ModuleItemFluid, type ModuleItemSeal, type ModuleLayer, type ModuleMetric, type ModuleScenario, type NumberControl, type ObjectState, type PartBreach, type PartShape, type PartSpec, type PartState, type PartStatus, type PartUnits, type PileSpec, type PlayerState, type Quat, type RayHit, type Reinforcement, STAGE_EVENT, type SealBlock, type SealSpec, type SealState, type SegmentKind, type ShelterOptions, type Shot, type SoilLayer, type SoilProfile, type SoilState, type SoundHandle, type SoundRequest, type SpecReport, type StructureRole, type SurfaceLayer, TOOL_CLIP, TWIST_LIFT, type TensionRebar, type TestableItem, type TestableModule, type Thumbnail, type ToolAnimationStep, type ToolAnimator, type ToolClipId, type ToolClipPlayer, type ToolClipPlayerOptions, type ToolClipSet, type ToolCommand, type ToolCommandResult, type ToolKind, type ToolRig, type TunedMassDamper, type TwistOptions, type TwistStroke, type UnmarkedDrawing, type Use, type Vec3, type WarmUpProbes, type WindExposure, type WindState, applyPatches, blastShove, checkAnimation, checkBench, checkCategorized, checkDestructible, checkHit, checkSpec, checkToolClips, createEnvironmentBus, createToolClipPlayer, deepMerge, defineCategories, fillFactor, footprintBlocker, ignitionChance, kitOriginOf, markKitOrigin, mergeById, removeIds, resolveEntry, resolveIgnitionRules, sampleClip, scaleClip, sealBlock, sealOpener, shotExtras, shotToHit, sparkTargetFactor, toolAnimationStep, twistStroke, unmarkedDrawings, useToHit };
2696
+ /**
2697
+ * @adatechnology/game-contracts: the contracts every game module (vehicles, furniture, plants, houses, weapons) depends on, and nothing else.
2698
+ * Types plus tiny pure checkers, no runtime dependencies. The default destruction world, the renderers and the test room are optional.
2699
+ */
2700
+
2701
+ /** @deprecated Import it from `@adatechnology/game-contracts/testing`. */
2702
+ declare const resetWarnOnce: () => void;
2703
+
2704
+ export { type ActionControl, type AnimationClipSpec, type AnimationEventSpec, type AnimationKey, type AnimationPose, type AreaPlacement, type AudioListener, type AudioSink, BLOW_IDS, BODY_FOLEY_IDS, BODY_SOUND_IDS, type BallisticExtras, type BenchChange, type BenchDeclaration, type BenchReport, type BenchSheet, type BlastOptions, type BlastReport, type BlastShove, type BlastShoveOptions, type BlastSource, type BlowId, type BlowTarget, type BodyFoleyId, type BodyRegion, type BodySlot, type BodySoundId, type BooleanControl, type BusyOptions, type BusySink, type BusyTask, type CategorizedOptions, type CategorizedReport, type CategoryDef, type CategoryOptions, type CategoryRegistry, type ChainDelay, type CheckOptions, type CheckSpecOptions, type ChoiceControl, type ChoiceOption, type ConfinementOptions, type ContainerSpec, type ContractChecker, type ContractContext, type ControlPatch, type ControlValue, type CostOptions, type Crack, DEFAULT_BLAST_SHOVE, DEFAULT_ENVIRONMENT, DEFAULT_IGNITION_RULES, DEFAULT_SURFACE, DEFERRED_PRIORITY, DEFERRED_QUEUE_ID, type DamageStage, type DamageType, type DebrisKind, type DeepPartial, type DeferredQueue, type DeferredQueueOptions, type DeferredQueueReport, type Dent, type DestructibleImpl, type DestructibleSpec, type DestructionEvent, type DestructionEventType, type EffectHandle, type EffectRequest, type EffectSink, type Enclosure, type EnclosureBox, type EnvironmentBus, type EnvironmentKey, type EnvironmentState, type ExplosionChain, FOOTSTEP_SOUND_IDS, FRAME_PHASES, type FluidKind, type Footprint, type FootprintObject, type FootstepSoundId, type FractureStyle, type Fragment, type FragmentHitOptions, type FragmentMark, type FrameOptions, type FramePhase, GAIT_IDS, type GaitId, type GroundLayout, type GroundZone, HEAVY_LANDING_SPEED, type HandPose, type HandTargetSource, type HandTargets, type Hit, type HitIgnition, type HitResult, type Hole, type HostEvent, type HostGraphics, type HostReach, type HostTool, type HostToolAttachment, IMPACT_CONTRACT, type IgnitionRules, type ImpactContract, type ItemAnimationContract, type ItemSeat, type ItemUseDef, type JointKind, type JointSpec, type JointState, KIT_ORIGIN_KEY, type KitOrigin, LANDING_IDS, LAND_SOUND_IDS, type LandSoundId, type LandingId, type LiquidId, type LoopHandle, MATERIAL_SURFACES, MISSING_BITS, type MaterialId, type ModuleArea, type ModuleBench, type ModuleControl, type ModuleHost, type ModuleItemFluid, type ModuleItemSeal, type ModuleLayer, type ModuleMetric, type ModuleScenario, type NumberControl, type ObjectState, type PartBreach, type PartShape, type PartSpec, type PartState, type PartStatus, type PartUnits, type PileSpec, type PlayerState, type Quat, type RayHit, type Reinforcement, STAGE_EVENT, SURFACE_IDS, SWING_LEAD_SECONDS, type SealBlock, type SealSpec, type SealState, type SegmentKind, type ShelterOptions, type Shot, type SoilLayer, type SoilProfile, type SoilState, type SoundHandle, type SoundRequest, type SpecReport, type StructureRole, type SurfaceId, type SurfaceLayer, type SurfaceRay, type SurfaceRayHit, TOOL_CLIP, TWIST_LIFT, type TensionRebar, type TestableItem, type TestableModule, type Thumbnail, type ToolAnimationStep, type ToolAnimator, type ToolClipId, type ToolClipPlayer, type ToolClipPlayerOptions, type ToolClipSet, type ToolCommand, type ToolCommandResult, type ToolKind, type ToolRig, type TunedMassDamper, type TwistOptions, type TwistStroke, type UnmarkedDrawing, type Use, type Vec3, type WarmUpProbes, type WindExposure, type WindState, applyPatches, blastShove, checkAnimation, checkBench, checkCategorized, checkDeferredQueue, checkDestructible, checkHit, checkSpec, checkToolClips, createEnvironmentBus, createToolClipPlayer, deepMerge, defineCategories, fillFactor, footprintBlocker, footstepSoundId, hitSoundId, ignitionChance, isSurfaceId, kitOriginOf, landSoundId, markKitOrigin, mergeById, removeIds, resetWarnOnce, resolveEntry, resolveIgnitionRules, sampleClip, scaleClip, sealBlock, sealOpener, shotExtras, shotToHit, sparkTargetFactor, surfaceOfMaterial, swingSoundId, toolAnimationStep, twistStroke, unmarkedDrawings, useToHit };