dredless 0.2.0 → 0.3.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.
Files changed (80) hide show
  1. package/README.md +65 -48
  2. package/dist/browser/dredless.global.js +12047 -0
  3. package/dist/browser/dredless.global.js.map +7 -0
  4. package/docs/API_REFERENCE.md +2481 -2481
  5. package/docs/BROWSER_API.md +98 -98
  6. package/docs/NODE_API.md +359 -359
  7. package/package.json +40 -35
  8. package/src/browser-global.js +3 -0
  9. package/src/browser.d.ts +212 -212
  10. package/src/browser.js +133 -133
  11. package/src/client/core.js +1202 -1202
  12. package/src/client/domains/index.js +1818 -1818
  13. package/src/client/index.d.ts +2 -2
  14. package/src/client/index.js +1 -1
  15. package/src/compression/lz4.d.ts +1 -1
  16. package/src/compression/lz4.js +112 -112
  17. package/src/constants.js +74 -74
  18. package/src/crypto/chacha-native.d.ts +9 -9
  19. package/src/crypto/chacha-native.js +48 -48
  20. package/src/crypto/chacha.d.ts +25 -25
  21. package/src/crypto/chacha.js +274 -274
  22. package/src/events.js +39 -39
  23. package/src/index.d.ts +2277 -2277
  24. package/src/index.js +125 -125
  25. package/src/network/browser-session.js +291 -291
  26. package/src/network/connection.d.ts +1 -1
  27. package/src/network/connection.js +31 -31
  28. package/src/network/cookies.js +85 -85
  29. package/src/network/http.js +34 -34
  30. package/src/network/index.d.ts +4 -4
  31. package/src/network/index.js +4 -4
  32. package/src/network/servers.d.ts +7 -7
  33. package/src/network/servers.js +133 -133
  34. package/src/network/session.d.ts +7 -7
  35. package/src/network/session.js +320 -320
  36. package/src/network/ships.d.ts +12 -12
  37. package/src/network/ships.js +73 -73
  38. package/src/node.d.ts +2 -2
  39. package/src/node.js +8 -8
  40. package/src/protocol/codec/binary.d.ts +3 -3
  41. package/src/protocol/codec/binary.js +52 -52
  42. package/src/protocol/codec/msgpack.d.ts +3 -3
  43. package/src/protocol/codec/msgpack.js +555 -555
  44. package/src/protocol/inbound/frame.d.ts +1 -1
  45. package/src/protocol/inbound/frame.js +8 -8
  46. package/src/protocol/inbound/world-payload.d.ts +3 -3
  47. package/src/protocol/inbound/world-payload.js +21 -21
  48. package/src/protocol/index.d.ts +11 -11
  49. package/src/protocol/index.js +19 -19
  50. package/src/protocol/outbound/blueprint.d.ts +22 -22
  51. package/src/protocol/outbound/blueprint.js +36 -36
  52. package/src/protocol/outbound/commands.d.ts +3 -3
  53. package/src/protocol/outbound/commands.js +149 -149
  54. package/src/protocol/outbound/comms.d.ts +28 -28
  55. package/src/protocol/outbound/comms.js +40 -40
  56. package/src/protocol/outbound/inventory.d.ts +64 -64
  57. package/src/protocol/outbound/inventory.js +147 -147
  58. package/src/protocol/outbound/ship-management.d.ts +84 -84
  59. package/src/protocol/outbound/ship-management.js +221 -221
  60. package/src/protocol/outbound/sign.d.ts +18 -18
  61. package/src/protocol/outbound/sign.js +45 -45
  62. package/src/protocol/outbound/ui-config.d.ts +157 -157
  63. package/src/protocol/outbound/ui-config.js +578 -578
  64. package/src/runtime.js +36 -36
  65. package/src/state/generator-maze.d.ts +32 -32
  66. package/src/state/generator-maze.js +370 -370
  67. package/src/state/index.d.ts +3 -3
  68. package/src/state/index.js +3 -3
  69. package/src/state/items.js +20 -20
  70. package/src/state/model/decoder.js +1554 -1554
  71. package/src/state/model/index.d.ts +33 -33
  72. package/src/state/model/index.js +2 -2
  73. package/src/state/model/loader-config.js +1020 -1020
  74. package/src/state/model/reader.js +69 -69
  75. package/src/state/model/state.js +1257 -1257
  76. package/src/state/overworld.js +72 -72
  77. package/src/state/tilesets.js +53 -53
  78. package/src/state/world/index.d.ts +29 -29
  79. package/src/state/world/index.js +180 -180
  80. package/src/state/world/state.js +297 -297
@@ -1,2481 +1,2481 @@
1
- # Dredless API Reference
2
-
3
- This document describes the public JavaScript API exposed by the package.
4
- Here, "endpoint" means a public method, constructor, domain method, or exported
5
- helper function. The actual browser/game wire protocol remains an implementation
6
- detail unless a helper explicitly builds or decodes protocol payloads.
7
-
8
- Use the runtime-specific top-level API references for session, token, and start/join helpers:
9
-
10
- - [NODE_API.md](./NODE_API.md): explicit multi-session `Session` / `AnonSession` API for Node.
11
- - [BROWSER_API.md](./BROWSER_API.md): ambient browser-session API for browser contexts.
12
-
13
- This shared reference covers common input/output shapes, `DredlessClient`, world/entity/domain APIs, protocol helpers, and other runtime-neutral APIs.
14
-
15
- Subpath imports are available for focused low-level helpers:
16
-
17
- ```js
18
- import { DredlessClient } from "dredless/client";
19
- import { WorldStore, WorldState } from "dredless/world";
20
- import { generateGeneratorMaze } from "dredless/game/generator-maze";
21
- import { encodeMsgpack, decodeMsgpack, decodeIncomingFrame } from "dredless/protocol";
22
- ```
23
-
24
- ## Public Package Exports
25
-
26
- `package.json` currently exposes these module specifiers:
27
-
28
- ```txt
29
- dredless
30
- dredless/browser
31
- dredless/node
32
- dredless/client
33
- dredless/network
34
- dredless/state
35
- dredless/session
36
- dredless/servers
37
- dredless/ships
38
- dredless/connection
39
- dredless/world
40
- dredless/model
41
- dredless/game/generator-maze
42
- dredless/game/model
43
- dredless/protocol
44
- dredless/protocol/blueprint
45
- dredless/protocol/comms
46
- dredless/protocol/commands
47
- dredless/protocol/inventory
48
- dredless/protocol/ship-management
49
- dredless/protocol/sign
50
- dredless/protocol/ui-config
51
- dredless/crypto/chacha
52
- dredless/compression/lz4
53
- ```
54
-
55
- The root module defaults to the Node API for types and direct Node imports. Browser bundlers may use the root `browser` condition for JavaScript, but `dredless/browser` is the reliable import for browser IntelliSense.
56
-
57
- Both runtime entrypoints re-export world/model classes, protocol builders, config builders, codec helpers, and common type shapes.
58
-
59
- ## Common Input Types
60
-
61
- ### `Server`
62
-
63
- Returned by `fetchServers()`.
64
-
65
- ```ts
66
- interface Server {
67
- index: number;
68
- domain: string;
69
- description: string;
70
- playerCount: number;
71
- maxPlayerCount: number;
72
- ping: number | null;
73
- }
74
- ```
75
-
76
- ### `ServerRef`
77
-
78
- Accepted anywhere a server is required.
79
-
80
- ```ts
81
- type ServerRef = number | Server;
82
- ```
83
-
84
- Passing a number selects a server index. Passing a `Server` object uses its
85
- domain and index directly.
86
-
87
- ### `Ship`
88
-
89
- Returned by ship list reads.
90
-
91
- ```ts
92
- interface Ship {
93
- id: number | null;
94
- hexCode: string | null;
95
- name: string;
96
- iconUrl: string | null;
97
- playerCount: number;
98
- owned: boolean;
99
- saved: boolean;
100
- color: string;
101
- time: number | null;
102
- }
103
- ```
104
-
105
- ### `ShipList`
106
-
107
- Returned by `fetchShipList()`.
108
-
109
- ```ts
110
- interface ShipList {
111
- playerCount?: number;
112
- maxPlayerCount?: number;
113
- isMuted?: boolean;
114
- ships: Ship[];
115
- }
116
- ```
117
-
118
- ### `ShipSpec`, `ShipRef`
119
-
120
- Accepted by join/start methods.
121
-
122
- ```ts
123
- type ShipSpec =
124
- | { type: "join_or_load"; id: number | string }
125
- | { type: "new"; name?: string | null; color?: string | null }
126
- | { type: "invite"; code: string };
127
-
128
- type ShipRef = number | string | Ship | ShipSpec | null;
129
- ```
130
-
131
- Useful interpretations:
132
-
133
- ```txt
134
- number -> ship id
135
- string -> ship id/hex-like selector, depending on server API
136
- Ship -> ship from fetchShips/fetchShipList
137
- { type: "new" } -> create or start a new ship
138
- { type: "invite" } -> join by invite code
139
- null or undefined -> default behavior for the method
140
- ```
141
-
142
- ## Runtime Top-Level APIs
143
-
144
- Top-level runtime APIs are split by environment:
145
-
146
- - Node explicit session/token/start helpers: [NODE_API.md](./NODE_API.md)
147
- - Browser ambient session/start helpers: [BROWSER_API.md](./BROWSER_API.md)
148
-
149
- `Connection`, `Session`, `AnonSession`, `BrowserSession`, `Dredless`, and `DredlessBrowser` are documented in those runtime-specific files.
150
-
151
- ## `DredlessClient`
152
-
153
- `DredlessClient` owns the websocket, outgoing commands, incoming packets, and
154
- decoded state domains.
155
-
156
- ```ts
157
- class DredlessClient {
158
- constructor(connection: Connection, options?: { connect?: boolean });
159
- static attachWebSocket(websocket: unknown, options?: AttachWebSocketOptions): DredlessClient;
160
-
161
- connection: Connection | null;
162
- session: Session | null;
163
- baseUrl: string | null;
164
- attachMode: "observe" | "bootstrap" | "readonly" | null;
165
- attached: boolean;
166
- serverId: number | null;
167
- server: Server | null;
168
- netPort: number | null;
169
- gameToken: string;
170
- ws: unknown;
171
- sid: number | null;
172
- connected: boolean;
173
- ready: boolean;
174
- packetCount: number;
175
- lastPacket: unknown;
176
-
177
- net: ClientNetDomain;
178
- debug: ClientDebugDomain;
179
- player: PlayerDomain;
180
- inventory: InventoryDomain;
181
- management: ShipManagementDomain;
182
- readyPromise: Promise<this>;
183
-
184
- whenReady(): Promise<this>;
185
- close(code?: number, reason?: string): this;
186
- disconnect(code?: number, reason?: string): this;
187
-
188
- currentShip(): ShipDomain | null;
189
- ship(): ShipDomain | null;
190
- overworld(): OverworldDomain | null;
191
- world(id: number): WorldDomain | null;
192
- shipWorld(options?: { includeTiles?: boolean; includeModel?: boolean }): WorldSnapshot | null;
193
- state(options?: { includeTiles?: boolean; includeModel?: boolean }): ClientSnapshot;
194
- entities(scope?: number | string): EntitySummary[];
195
- entity(entityId: number, scope?: number | string): EntitySnapshot | null;
196
- currentPlayerEntity(): EntityHandle | null;
197
-
198
- on(type: string, callback: (...args: unknown[]) => void): this;
199
- off(type: string, callback: (...args: unknown[]) => void): this;
200
- once(type: string, callback: (...args: unknown[]) => void): this;
201
- }
202
- ```
203
-
204
- ### Constructor
205
-
206
- ```js
207
- const client = new DredlessClient(connection);
208
- ```
209
-
210
- By default the constructor opens the websocket. For tests or offline state
211
- inspection, pass `{ connect: false }`:
212
-
213
- ```js
214
- const client = new DredlessClient(connection, { connect: false });
215
- ```
216
-
217
- ### `DredlessClient.attachWebSocket(websocket, options?)`
218
-
219
- ```ts
220
- type WebSocketAttachMode = "observe" | "bootstrap" | "readonly";
221
-
222
- interface AttachWebSocketOptions {
223
- mode?: WebSocketAttachMode;
224
- connected?: boolean | null;
225
- ready?: boolean;
226
- sid?: number | null;
227
- baseUrl?: string | null;
228
- session?: Session | null;
229
- serverId?: number | null;
230
- server?: Server | null;
231
- netPort?: number | null;
232
- gameToken?: string;
233
- }
234
- ```
235
-
236
- Attaches Dredless to an existing websocket without requiring a `Connection`.
237
- This is intended for observing or integrating with an already-open browser/game websocket.
238
-
239
- Modes:
240
-
241
- - `"observe"` default: decodes incoming packets and allows explicit writes through normal handle/client methods, but does not send hello, bootstrap, or keepalive automatically.
242
- - `"bootstrap"`: treats the websocket like a normally owned Dredless socket; sends hello on open and runs bootstrap, keepalive, and queued-message flushing on ready.
243
- - `"readonly"`: decodes incoming packets only and rejects all write methods. `close()` is a no-op in this mode.
244
-
245
- Optional metadata such as `server`, `serverId`, and `netPort` is only used for snapshots/logging; it is not required to attach.
246
-
247
- ```js
248
- const client = DredlessClient.attachWebSocket(window.tpgaClient.repsocket.websocket);
249
- client.on("packet", (packet) => console.log(packet.type));
250
- ```
251
-
252
- ### Lifecycle endpoints
253
-
254
- ```ts
255
- whenReady(): Promise<this>;
256
- close(code?: number, reason?: string): this;
257
- disconnect(code?: number, reason?: string): this;
258
- ```
259
-
260
- `whenReady()` resolves once the ready packet is received. For normally-owned clients and `attachWebSocket(..., { mode: "bootstrap" })`, bootstrap commands have also been sent.
261
-
262
- ### World/domain endpoints
263
-
264
- ```ts
265
- currentShip(): ShipDomain | null;
266
- ship(): ShipDomain | null;
267
- currentPlayerEntity(): EntityHandle | null;
268
- overworld(): OverworldDomain | null;
269
- world(id: number): WorldDomain | null;
270
- shipWorld(options?): WorldSnapshot | null;
271
- ```
272
-
273
- Use `currentShip()` for the currently loaded ship world. Use `overworld()` for
274
- zone-level objects such as nearby ships and overworld entities.
275
-
276
- `currentPlayerEntity()` returns the current player entity handle in the loaded
277
- ship world, or `null` before the player entity is known.
278
-
279
- ### Compatibility entity endpoints
280
-
281
- ```ts
282
- entities(scope?: number | string): EntitySummary[];
283
- entity(entityId: number, scope?: number | string): EntitySnapshot | null;
284
- ```
285
-
286
- Prefer `client.currentShip()?.entities` and `client.overworld()?.entities` for
287
- new code. These compatibility methods use `"ship"` by default.
288
-
289
- Valid common scopes are:
290
-
291
- ```txt
292
- "ship"
293
- "current"
294
- "overworld"
295
- number world id
296
- ```
297
-
298
- ### Events
299
-
300
- ```ts
301
- on(type: string, callback: (...args: unknown[]) => void): this;
302
- off(type: string, callback: (...args: unknown[]) => void): this;
303
- once(type: string, callback: (...args: unknown[]) => void): this;
304
- ```
305
-
306
- Events are implementation-defined strings emitted by the client event bus.
307
-
308
- ## `client.state()` Output
309
-
310
- ```ts
311
- interface ClientSnapshot {
312
- baseUrl: string;
313
- session: SessionSnapshot;
314
- connection: ConnectionSnapshot | null;
315
- attachMode: "observe" | "bootstrap" | "readonly" | null;
316
- serverId: number | null;
317
- server: Server | null;
318
- netPort: number | null;
319
- sid: number | null;
320
- ready: boolean;
321
- connected: boolean;
322
- currentWorldId: number | null;
323
- worlds: WorldSnapshot[];
324
- cpuLoad: number | null;
325
- inventory: InventoryState | null;
326
- puiPanels: PuiEvent[];
327
- commsPanels: CommsEvent[];
328
- currentCommsPanel: CommsEvent | null;
329
- warnings: unknown[];
330
- effects: unknown[];
331
- chat: unknown[];
332
- motd: unknown[];
333
- sessionMessages: unknown[];
334
- scannerResults: ScannerResult[];
335
- lastScannerResult: ScannerResult | null;
336
- shipConfig: ShipConfig | null;
337
- captainSubrank: CaptainSubrank | null;
338
- playerList: ShipPlayerList | null;
339
- outfits: { sid: number; outfit: unknown }[];
340
- commandAcks: CommandAck[];
341
- lastCommandAck: CommandAck | null;
342
- decodeErrors: unknown[];
343
- packetCount: number;
344
- lastPacket: unknown;
345
- }
346
- ```
347
-
348
- ## Client Domain APIs
349
-
350
- ### `client.net`
351
-
352
- Low-level outgoing network domain.
353
-
354
- ```ts
355
- interface ClientNetDomain {
356
- connected: boolean;
357
- ready: boolean;
358
- sid: number | null;
359
- packetCount: number;
360
- lastPacket: unknown;
361
- send(command?: Command): DredlessClient;
362
- sendMessage(message: unknown, options?: { afterReady?: boolean }): DredlessClient;
363
- sendRaw(message: unknown, options?: { afterReady?: boolean }): DredlessClient;
364
- sendEntityCommand(cmd: string, args?: unknown[]): DredlessClient;
365
- sendUiConfig(data: unknown): DredlessClient;
366
- sendBlueprintPlacement(placement: BlueprintPlacement): DredlessClient;
367
- setOutfit(outfit: unknown): DredlessClient;
368
- }
369
- ```
370
-
371
- `send()` signs and sends a command-like packet. `sendMessage()` sends a decoded
372
- protocol message. `sendRaw()` sends already-built/raw content. The specialized
373
- helpers build the corresponding protocol command and return the client for
374
- chaining.
375
-
376
- ### `Command`
377
-
378
- General command shape for movement, actions, UI focus, and drag operations.
379
-
380
- ```ts
381
- interface Command {
382
- type?: number;
383
- n?: number | null;
384
- x?: number;
385
- y?: number;
386
- mx?: number;
387
- my?: number;
388
- vx?: number;
389
- vy?: number;
390
- jump?: boolean;
391
- jump_held?: boolean;
392
- drop?: boolean;
393
- act1?: boolean;
394
- act1_held?: boolean;
395
- exit?: boolean;
396
- act2?: boolean;
397
- act_alt?: boolean;
398
- act_alt_held?: boolean;
399
- wrench_mode?: number;
400
- turret_mode?: number;
401
- scr_w?: number;
402
- scr_h?: number;
403
- motion?: number;
404
- focus_ent?: number | null;
405
- config_ent?: number | null;
406
- tip_select?: number | null;
407
- inv_slot?: number;
408
- blur?: boolean;
409
- drag?: DragPayload | null;
410
- }
411
- ```
412
-
413
- ### `client.debug`
414
-
415
- Read-only debugging and raw-state access.
416
-
417
- ```ts
418
- interface ClientDebugDomain {
419
- packets(): unknown[];
420
- decodeErrors(): unknown[];
421
- worldStore(): WorldStore;
422
- modelTable(worldId: number, tableId: number): Map<number, ModelRecord>;
423
- modelRecord(worldId: number, tableId: number, entityId: number): ModelRecord | null;
424
- puiPanels(): PuiEvent[];
425
- commsPanels(): CommsEvent[];
426
- }
427
- ```
428
-
429
- ### `client.player`
430
-
431
- Player input and action domain.
432
-
433
- ```ts
434
- interface PlayerDomain {
435
- current(): PlayerSummary | null;
436
- entity(): EntityHandle | null;
437
- name(): string | null;
438
- rank(): CurrentPlayerRank;
439
- move(vector?: { x?: number; y?: number }, command?: Command): DredlessClient;
440
- aim(point?: { x?: number; y?: number; mx?: number; my?: number }, command?: Command): DredlessClient;
441
- action(flags?: Command, command?: Command): DredlessClient;
442
- useEntity(entity: number | EntityHandle | EntitySummary, options?: { invSlot?: number; hold?: boolean }, command?: Command): DredlessClient;
443
- useHeldItem(options?: { invSlot?: number; hold?: boolean }, command?: Command): DredlessClient;
444
- placeHeldItem(options?: { invSlot?: number; hold?: boolean }, command?: Command): DredlessClient;
445
- placeBlueprint(placement: BlueprintPlacement, options?: { invSlot?: number; hold?: boolean; mx?: number; my?: number }, command?: Command): DredlessClient;
446
- rotateHeldItem(options?: { invSlot?: number; hold?: boolean }, command?: Command): DredlessClient;
447
- selectSlot(invSlot?: number, command?: Command): DredlessClient;
448
- inputSettings(): CurrentInputSettings;
449
- setInputSettings(settings?: InputSettings, options?: { send?: boolean }): DredlessClient;
450
- setView(width: number, height: number, options?: { send?: boolean }): DredlessClient;
451
- setScreenSize(width: number, height: number, options?: { send?: boolean }): DredlessClient;
452
- setWrenchMode(mode: WrenchMode, options?: { send?: boolean }): DredlessClient;
453
- setTurretMode(mode: TurretMode, options?: { send?: boolean }): DredlessClient;
454
- }
455
- ```
456
-
457
- ### Input setting shapes
458
-
459
- ```ts
460
- const WrenchMode = { DropAllItems: "drop-all-items", GrabPrimaryItems: "grab-primary-items", GrabAllItems: "grab-all-items" } as const;
461
- type WrenchMode = typeof WrenchMode[keyof typeof WrenchMode];
462
-
463
- const TurretMode = { ContinuousFire: "continuous-fire", VolleyFire: "volley-fire" } as const;
464
- type TurretMode = typeof TurretMode[keyof typeof TurretMode];
465
-
466
- interface InputSettings {
467
- wrenchMode?: WrenchMode;
468
- turretMode?: TurretMode;
469
- viewWidth?: number;
470
- viewHeight?: number;
471
- screenWidth?: number;
472
- screenHeight?: number;
473
- }
474
-
475
- interface CurrentInputSettings {
476
- wrenchMode: "drop-all-items" | "grab-primary-items" | "grab-all-items" | null;
477
- turretMode: "continuous-fire" | "volley-fire" | null;
478
- viewWidth: number | null;
479
- viewHeight: number | null;
480
- screenWidth: number | null;
481
- screenHeight: number | null;
482
- }
483
- ```
484
-
485
- ### `client.inventory`
486
-
487
- Inventory read and slot movement domain.
488
-
489
- ```ts
490
- type InventoryArea = "all" | "hotbar" | "equipment";
491
- type InventorySlotRef = number | EquipmentSlot | InventorySlotHandle | InventorySlotSnapshot;
492
- const EquipmentSlot = { Head: "head", Face: "face", Body: "body", Back: "back", Hands: "hands", Feet: "feet" } as const;
493
- type EquipmentSlot = typeof EquipmentSlot[keyof typeof EquipmentSlot];
494
-
495
- interface InventoryDomain {
496
- state(): InventoryState | null;
497
- hotbarSize(): number;
498
- allSlots(): InventorySlotHandle[];
499
- slot(ref: InventorySlotRef): InventorySlotHandle;
500
- hotbarSlots(): InventorySlotHandle[];
501
- equipmentSlots(): { head: InventorySlotHandle; face: InventorySlotHandle; body: InventorySlotHandle; back: InventorySlotHandle; hands: InventorySlotHandle; feet: InventorySlotHandle };
502
- findItem(itemId: number, options?: { area?: InventoryArea }): InventorySlotHandle | null;
503
- findItems(itemId: number, options?: { area?: InventoryArea }): InventorySlotHandle[];
504
- firstEmpty(options?: { area?: InventoryArea }): InventorySlotHandle | null;
505
- move(source: InventorySlotRef, target: InventorySlotRef, options?: { split?: boolean }, command?: Command): DredlessClient;
506
- equip(source: InventorySlotRef, equipmentSlot?: EquipmentSlot | { split?: boolean }, options?: { split?: boolean } | Command, command?: Command): DredlessClient;
507
- unequip(equipmentSlot: EquipmentSlot, target?: InventorySlotRef, options?: { split?: boolean }, command?: Command): DredlessClient;
508
- select(slot: InventorySlotRef, command?: Command): DredlessClient;
509
- }
510
- ```
511
-
512
- Slot handles expose live slot reads and convenience actions:
513
-
514
- ```ts
515
- interface InventorySlotHandle {
516
- index: number;
517
- kind: "hotbar" | "equipment" | null;
518
- equipmentSlot: "head" | "face" | "body" | "back" | "hands" | "feet" | null;
519
- itemId: number | null;
520
- itemName: string | null;
521
- count: number;
522
- empty: boolean;
523
- exists(): boolean;
524
- snapshot(): InventorySlotSnapshot | null;
525
- moveTo(target: InventorySlotRef, options?: { split?: boolean }, command?: Command): DredlessClient;
526
- equip(equipmentSlot?: EquipmentSlot | { split?: boolean }, options?: { split?: boolean } | Command, command?: Command): DredlessClient;
527
- unequip(target?: InventorySlotRef, options?: { split?: boolean }, command?: Command): DredlessClient;
528
- select(command?: Command): DredlessClient;
529
- }
530
- ```
531
-
532
- Inventory state is normalized and does not expose raw `items`, `item_counts`, or `general_slots` arrays. `hotbarSize` is the protocol-provided hotbar slot count from `general_slots`; equipment slots are separate fixed absolute indexes (`16`, `17`, `18`, `19`, `20`, `21`). `equip()` may omit the equipment slot; in that case it infers the target from the item schema and throws if the source slot is empty or the item is not equipment.
533
-
534
- ```ts
535
- interface InventorySlotSnapshot {
536
- index: number;
537
- itemId: number | null;
538
- itemName: string | null;
539
- count: number;
540
- kind: "hotbar" | "equipment";
541
- equipmentSlot: "head" | "face" | "body" | "back" | "hands" | "feet" | null;
542
- empty: boolean;
543
- }
544
-
545
- interface InventoryState {
546
- type: "inventory";
547
- filter?: number;
548
- hotbarSize: number;
549
- slots: InventorySlotSnapshot[];
550
- hotbar: InventorySlotSnapshot[];
551
- equipment: {
552
- head: InventorySlotSnapshot;
553
- face: InventorySlotSnapshot;
554
- body: InventorySlotSnapshot;
555
- back: InventorySlotSnapshot;
556
- hands: InventorySlotSnapshot;
557
- feet: InventorySlotSnapshot;
558
- };
559
- }
560
- ```
561
- ### `client.management`
562
-
563
- Ship-management command and state domain.
564
-
565
- ```ts
566
- interface ShipManagementDomain {
567
- requestPlayerList(): DredlessClient;
568
- resetInvite(): DredlessClient;
569
- setPrivacy(privacy: ShipPrivacy): DredlessClient;
570
- recoverStarterItem(itemId: number): DredlessClient;
571
- setPlayerRank(refId: number, rank: ShipPlayerRank): DredlessClient;
572
- kickPlayer(refId: number): DredlessClient;
573
- banPlayer(refId: number): DredlessClient;
574
- demoteSelf(): DredlessClient;
575
- config(): ShipConfig | null;
576
- hasCheats(): boolean;
577
- playerList(): ShipPlayerList | null;
578
- }
579
- ```
580
-
581
- Input aliases:
582
-
583
- ```ts
584
- type ShipPrivacy = 0 | 1 | boolean | "public" | "private";
585
- type ShipPlayerRank = 0 | 1 | 3 | "guest" | "crew" | "captain";
586
- type PlayerShipRank = "guest" | "crew" | "crew-invite-pending-deprecated" | "captain" | "banned";
587
- ```
588
-
589
- Output shapes:
590
-
591
- ```ts
592
- interface ShipConfig {
593
- privacy: number | null;
594
- privacyName: "public" | "private" | null;
595
- inviteKey: string | null;
596
- teamId: number | null;
597
- patronPerks: unknown[];
598
- }
599
-
600
- interface CaptainSubrank {
601
- subrank: number | null;
602
- enableCheats: boolean;
603
- }
604
-
605
- interface CurrentPlayerRank {
606
- shipRank: PlayerShipRank | null;
607
- subrank: number | null;
608
- isCaptain: boolean;
609
- patronTier: "bronze" | "silver" | "gold" | "plat" | "flux" | null;
610
- }
611
-
612
- interface PlayerListEntry {
613
- refId: number | null;
614
- discrim: string | null;
615
- discrimColor: number | null;
616
- teamRank: number | null;
617
- captainRank: number | null;
618
- isCaptain: boolean;
619
- isShipOwner: boolean;
620
- canBeManaged: boolean;
621
- time: number | null;
622
- items: unknown[];
623
- aliasDiscrims: unknown[];
624
- extraAliasCount: number;
625
- onlineCount: number | null;
626
- }
627
-
628
- interface ShipPlayerList {
629
- ownerCaptainRank: number | null;
630
- shipOwners: PlayerListEntry[];
631
- players: PlayerListEntry[];
632
- changes: PlayerListEntry[];
633
- removedPlayers: number[];
634
- }
635
- ```
636
-
637
- ## World Domains
638
-
639
- ### `WorldDomain`
640
-
641
- Available from `client.currentShip()`, `client.overworld()`, and
642
- `client.world(id)`.
643
-
644
- ```ts
645
- interface WorldDomain {
646
- id: number | null;
647
- entities: EntityCollection;
648
- machines: MachineCollection;
649
- players: PlayerCollection;
650
- blocks: BlockCollection;
651
- materials: MaterialCollection;
652
- exists(): boolean;
653
- snapshot(options?: { includeTiles?: boolean; includeModel?: boolean }): WorldSnapshot | null;
654
- }
655
- ```
656
-
657
- ### `ShipDomain`
658
-
659
- ```ts
660
- interface ShipDomain extends WorldDomain {
661
- metadata: ShipWorldMetadataSummary | null;
662
- entity(): EntityHandle | null;
663
- overworldEntity: EntityHandle | null;
664
- }
665
- ```
666
-
667
- `entity()` returns the current ship's overworld entity handle, not a ship-world
668
- placed entity.
669
-
670
- ### `OverworldDomain`
671
-
672
- ```ts
673
- interface OverworldDomain extends WorldDomain {
674
- ships(options?: ShipReadOptions): ShipHandle[];
675
- shipByHex(hexCode: string, options?: ShipReadOptions): ShipHandle | null;
676
- shipByEntity(entity: number | EntityHandle | EntitySummary, options?: ShipReadOptions): ShipHandle | null;
677
- }
678
- ```
679
-
680
- Ship read options:
681
-
682
- ```ts
683
- interface ShipReadOptions {
684
- includeWorld?: boolean;
685
- includeTiles?: boolean;
686
- includeModel?: boolean;
687
- sort?: "distance" | null;
688
- }
689
- ```
690
-
691
- ## Entity API
692
-
693
- Entity ids are scoped to their world. Overworld entities and ship-world entities
694
- do not share one global id pool.
695
-
696
- ### `EntityCollection`
697
-
698
- ```ts
699
- interface EntityCollection {
700
- all(): EntityHandle[];
701
- snapshots(): EntitySnapshot[];
702
- states(): EntitySnapshot[];
703
- raw(): EntitySummary[];
704
- get(entity: number | EntityHandle | EntitySummary): EntityHandle;
705
- }
706
- ```
707
-
708
- Use:
709
-
710
- ```js
711
- const shipEntity = client.currentShip().entities.get(14);
712
- const overworldEntity = client.overworld().entities.get(2495754);
713
- ```
714
-
715
- Costs:
716
-
717
- ```txt
718
- all() -> creates lightweight handles
719
- raw() -> returns current summary objects
720
- snapshots() -> clones and freezes summaries
721
- states() -> alias of snapshots()
722
- get(id) -> creates one lightweight handle
723
- ```
724
-
725
- ### `EntityHandle`
726
-
727
- ```ts
728
- interface EntityHandle {
729
- /** @deprecated Use id. */
730
- entity: number;
731
- id: number;
732
- position: TransformSummary | null;
733
- health: HealthSummary | null;
734
- contents: EntityContentsSummary | null;
735
- exists(): boolean;
736
- snapshot(): EntitySnapshot | null;
737
- is(type: EntityTypeName): boolean;
738
- has(feature: EntityFeatureName): boolean;
739
- feature(feature: EntityFeatureName): unknown | null;
740
- as(type: EntityTypeName): MachineHandle | null;
741
- asLoader(): LoaderHandle | null;
742
- asPusher(): PusherHandle | null;
743
- asLauncher(): LauncherHandle | null;
744
- asNavigationUnit(): NavigationUnitHandle | null;
745
- asCommsStation(): CommsStationHandle | null;
746
- asSign(): SignHandle | null;
747
- asGenerator(): GeneratorHandle | null;
748
- asCargoHatch(): CargoHatchHandle | null;
749
- asCannon(): CannonHandle | null;
750
- asThruster(): ThrusterHandle | null;
751
- asHelm(): HelmHandle | null;
752
- asDoor(): DoorHandle | null;
753
- asSpawnPoint(): SpawnPointHandle | null;
754
- asShieldProjector(): ShieldProjectorHandle | null;
755
- asFluidTank(): FluidTankHandle | null;
756
- asCargoEjector(): CargoEjectorHandle | null;
757
- asExpandoBox(): ExpandoBoxHandle | null;
758
- use(options?: { invSlot?: number; hold?: boolean }, command?: Command): DredlessClient;
759
- }
760
- ```
761
-
762
- ### `EntitySnapshot`
763
-
764
- Frozen point-in-time entity read.
765
-
766
- ```ts
767
- interface EntitySnapshot extends EntitySummary {
768
- id: number;
769
- position: TransformSummary | null;
770
- rotation: number | null;
771
- type: EntitySnapshotType;
772
- is(type: EntityTypeName): boolean;
773
- has(feature: EntityFeatureName): boolean;
774
- feature(feature: EntityFeatureName): unknown | null;
775
- }
776
-
777
- interface EntitySnapshotType {
778
- category: EntitySummary["category"] | null;
779
- machine: string | null;
780
- item: string | null;
781
- components: string[];
782
- }
783
- ```
784
-
785
- ### `EntitySummary`
786
-
787
- Raw normalized entity shape.
788
-
789
- ```ts
790
- interface EntitySummary {
791
- entity: number;
792
- category:
793
- | "placed_entity"
794
- | "loose_item"
795
- | "untyped_holder"
796
- | "metadata"
797
- | "player"
798
- | "ship_control"
799
- | "blueprint_preview"
800
- | "entity";
801
- typeId: number | null;
802
- typeName: string | null;
803
- markerTypeId: number | null;
804
- markerTypeName: string | null;
805
- label: string;
806
- kind: string[];
807
- transform: TransformSummary | null;
808
- footprint: {
809
- width: number;
810
- height: number;
811
- source:
812
- | "type"
813
- | "marker"
814
- | "heuristic"
815
- | "default"
816
- | "crate"
817
- | "huge_thruster"
818
- | "hover_outline";
819
- };
820
- contents: EntityContentsSummary | null;
821
- occupies: { x: number; y: number }[];
822
- tables: { tableId: number; name: string | null; record: ModelRecord }[];
823
- }
824
- ```
825
-
826
- ### `EntityContentsSummary`
827
-
828
- Feature/component container for an entity.
829
-
830
- ```ts
831
- interface EntityContentsSummary {
832
- itemHolder?: ItemHolderSummary;
833
- expandoBox?: ExpandoBoxSummary;
834
- hoverOutline?: HoverOutlineSummary;
835
- mapMarker?: MapMarkerSummary;
836
- dockingSpring?: DockingSpringSummary;
837
- hugeThruster?: HugeThrusterSummary;
838
- blueprintPreview?: BlueprintPreviewSummary;
839
- itemCrate?: ItemCrateSummary;
840
- health?: HealthSummary;
841
- bot?: BotSummary;
842
- fabricator?: FabricatorSummary;
843
- cargoEjector?: CargoEjectorSummary;
844
- cannon?: CannonSummary;
845
- thruster?: ThrusterSummary;
846
- pusher?: PusherSummary;
847
- pusherBeam?: PusherBeamSummary;
848
- launcher?: LauncherSummary;
849
- loader?: LoaderSummary;
850
- cargoHatch?: CargoHatchSummary;
851
- navigationUnit?: NavigationUnitSummary;
852
- commsStation?: CommsStationSummary;
853
- fluidTank?: FluidTankSummary;
854
- shieldGenerator?: ShieldGeneratorSummary;
855
- shieldProjector?: ShieldProjectorSummary;
856
- helm?: HelmSummary;
857
- player?: PlayerSummary;
858
- shipControl?: ShipControlSummary;
859
- sign?: SignSummary;
860
- spawnPoint?: SpawnPointSummary;
861
- door?: DoorSummary;
862
- shipSize?: ShipSizeSummary;
863
- }
864
- ```
865
-
866
- Feature lookup accepts the canonical component names above and selected aliases
867
- such as `outline`, `beam`, `inventory`, `filter`, `filterMode`, `filterSlots`,
868
- `occupied`, `mapMarker`, and `blueprint`.
869
-
870
- ## Machine API
871
-
872
- ### `MachineCollection`
873
-
874
- ```ts
875
- interface MachineCollection {
876
- state(): MachineSummary;
877
- raw(): MachineSummary;
878
- loaders(): LoaderHandle[];
879
- loader(entity: number | EntityHandle | EntitySummary): LoaderHandle;
880
- pushers(): PusherHandle[];
881
- pusher(entity: number | EntityHandle | EntitySummary): PusherHandle;
882
- launchers(): LauncherHandle[];
883
- launcher(entity: number | EntityHandle | EntitySummary): LauncherHandle;
884
- navigationUnits(): NavigationUnitHandle[];
885
- navigationUnit(entity?: number | EntityHandle | EntitySummary | null): NavigationUnitHandle | null;
886
- fabricators(): FabricatorHandle[];
887
- fabricator(entity: number | EntityHandle | EntitySummary): FabricatorHandle;
888
- commsStations(): CommsStationHandle[];
889
- commsStation(entity?: number | EntityHandle | EntitySummary | null): CommsStationHandle | null;
890
- signs(): SignHandle[];
891
- sign(entity: number | EntityHandle | EntitySummary): SignHandle;
892
- generators(): GeneratorHandle[];
893
- generator(entity: number | EntityHandle | EntitySummary): GeneratorHandle;
894
- cargoHatches(): CargoHatchHandle[];
895
- cargoHatch(entity: number | EntityHandle | EntitySummary): CargoHatchHandle;
896
- cargoEjectors(): CargoEjectorHandle[];
897
- cargoEjector(entity: number | EntityHandle | EntitySummary): CargoEjectorHandle;
898
- cannons(): CannonHandle[];
899
- cannon(entity: number | EntityHandle | EntitySummary): CannonHandle;
900
- thrusters(): ThrusterHandle[];
901
- thruster(entity: number | EntityHandle | EntitySummary): ThrusterHandle;
902
- helms(): HelmHandle[];
903
- helm(entity: number | EntityHandle | EntitySummary): HelmHandle;
904
- doors(): DoorHandle[];
905
- door(entity: number | EntityHandle | EntitySummary): DoorHandle;
906
- spawnPoints(): SpawnPointHandle[];
907
- spawnPoint(entity: number | EntityHandle | EntitySummary): SpawnPointHandle;
908
- shieldProjectors(): ShieldProjectorHandle[];
909
- shieldProjector(entity: number | EntityHandle | EntitySummary): ShieldProjectorHandle;
910
- fluidTanks(): FluidTankHandle[];
911
- fluidTank(entity: number | EntityHandle | EntitySummary): FluidTankHandle;
912
- expandoBoxes(): ExpandoBoxHandle[];
913
- expandoBox(entity: number | EntityHandle | EntitySummary): ExpandoBoxHandle;
914
- }
915
- ```
916
-
917
- ### `MachineSummary`
918
-
919
- Grouped machine/component state.
920
-
921
- ```ts
922
- interface MachineSummary {
923
- itemHolders: ItemHolderSummary[];
924
- health: HealthSummary[];
925
- fabricators: FabricatorSummary[];
926
- cargoEjectors: CargoEjectorSummary[];
927
- cannons: CannonSummary[];
928
- thrusters: ThrusterSummary[];
929
- pushers: PusherSummary[];
930
- pusherBeams: PusherBeamSummary[];
931
- launchers: LauncherSummary[];
932
- loaders: LoaderSummary[];
933
- cargoHatches: CargoHatchSummary[];
934
- navigationUnits: NavigationUnitSummary[];
935
- commsStations: CommsStationSummary[];
936
- fluidTanks: FluidTankSummary[];
937
- shieldGenerators: ShieldGeneratorSummary[];
938
- shieldProjectors: ShieldProjectorSummary[];
939
- helms: HelmSummary[];
940
- signs: SignSummary[];
941
- spawnPoints: SpawnPointSummary[];
942
- doors: DoorSummary[];
943
- expandoBoxes: ExpandoBoxSummary[];
944
- }
945
- ```
946
-
947
- ### Common machine handle
948
-
949
- ```ts
950
- interface MachineHandle extends EntityHandle {
951
- open(options?: { invSlot?: number; hold?: boolean }, command?: Command): DredlessClient;
952
- }
953
- ```
954
-
955
- `open()` focuses/uses the entity through the player command path.
956
-
957
- ### `LoaderHandle`
958
-
959
- ```ts
960
- interface LoaderHandle extends MachineHandle {
961
- state: LoaderSummary | null;
962
- configure(config?: LoaderConfig): DredlessClient;
963
- configureFull(config?: LoaderFullConfig): DredlessClient;
964
- copy(config?: LoaderFullConfig): DredlessClient;
965
- setPickPlace(pick: LoaderPosition, place: LoaderPosition, config?: LoaderConfig): DredlessClient;
966
- setPriority(priority: LoaderPriority, config?: LoaderConfig): DredlessClient;
967
- setStack(stack: number, config?: LoaderConfig): DredlessClient;
968
- setCycle(cycle: number, config?: LoaderConfig): DredlessClient;
969
- setRequireOutput(requireOutput: boolean, config?: LoaderConfig): DredlessClient;
970
- setWaitForStack(waitForStack: boolean, config?: LoaderConfig): DredlessClient;
971
- setFilterMode(filterMode: LoaderFilterMode): DredlessClient;
972
- setFilterItems(filterSlots?: Array<number | null | undefined>): DredlessClient;
973
- pick: number | undefined;
974
- place: number | undefined;
975
- priority: number | undefined;
976
- stack: number | undefined;
977
- cycle: number | undefined;
978
- requireOutput: boolean | undefined;
979
- waitForStack: boolean | undefined;
980
- filterMode: number | undefined;
981
- filterSlots: Array<number | null>;
982
- }
983
- ```
984
-
985
- Config inputs:
986
-
987
- ```ts
988
- const LoaderPosition = { TopLeft: "top-left", TopMiddle: "top-middle", TopRight: "top-right", MiddleLeft: "middle-left", MiddleRight: "middle-right", BottomLeft: "bottom-left", BottomMiddle: "bottom-middle", BottomRight: "bottom-right" } as const;
989
- type LoaderPosition = typeof LoaderPosition[keyof typeof LoaderPosition];
990
-
991
- const LoaderPriority = { Low: "low", Normal: "normal", High: "high" } as const;
992
- type LoaderPriority = typeof LoaderPriority[keyof typeof LoaderPriority];
993
-
994
- const LoaderFilterMode = { AllowAll: "allow-all", BlockFilter: "block-filter", AllowFilter: "allow-filter", BlockAll: "block-all" } as const;
995
- type LoaderFilterMode = typeof LoaderFilterMode[keyof typeof LoaderFilterMode];
996
-
997
- interface LoaderConfig {
998
- pick?: LoaderPosition;
999
- place?: LoaderPosition;
1000
- priority?: LoaderPriority;
1001
- stack?: number;
1002
- cycle?: number;
1003
- requireOutput?: boolean;
1004
- waitForStack?: boolean;
1005
- }
1006
-
1007
- interface LoaderFullConfig extends LoaderConfig {
1008
- filterMode?: LoaderFilterMode;
1009
- filterSlots?: Array<number | null | undefined>;
1010
- }
1011
- ```
1012
-
1013
- State output:
1014
-
1015
- ```ts
1016
- interface LoaderSummary {
1017
- entity: number;
1018
- pick: number | null;
1019
- pickName: string | null;
1020
- place: number | null;
1021
- placeName: string | null;
1022
- priority: number | null;
1023
- priorityName: string | null;
1024
- requireOutput: boolean | null;
1025
- waitForStack: boolean | null;
1026
- stack: number | null;
1027
- cycle: number | null;
1028
- filterMode: number | null;
1029
- filterModeName: string | null;
1030
- filterSlots: (number | null)[] | null;
1031
- heldItemId: number | null;
1032
- heldItemName: string | null;
1033
- heldCount: number | null;
1034
- active: boolean;
1035
- progress: number | null;
1036
- state: ModelRecord;
1037
- filterState: ModelRecord;
1038
- filterSlotsState: ModelRecord;
1039
- }
1040
- ```
1041
-
1042
- ### `PusherHandle`
1043
-
1044
- ```ts
1045
- interface PusherHandle extends MachineHandle {
1046
- state: PusherSummary | null;
1047
- beam: PusherBeamSummary | null;
1048
- configure(config?: PusherConfig): DredlessClient;
1049
- setAngle(angle: number, config?: PusherConfig): DredlessClient;
1050
- setSpeed(speed: number, config?: PusherConfig): DredlessClient;
1051
- setLength(length: number, config?: PusherConfig): DredlessClient;
1052
- setMode(mode: PusherMode, config?: PusherConfig): DredlessClient;
1053
- setFilteredMode(mode: PusherMode, config?: PusherConfig): DredlessClient;
1054
- setFilterInventory(filterInventory: boolean, config?: PusherConfig): DredlessClient;
1055
- setFilterItems(filterSlots?: Array<number | null | undefined>): DredlessClient;
1056
- angle: number | undefined;
1057
- speed: number | undefined;
1058
- length: number | undefined;
1059
- mode: number | undefined;
1060
- filteredMode: number | undefined;
1061
- }
1062
- ```
1063
-
1064
- Config input:
1065
-
1066
- ```ts
1067
- const PusherMode = { Push: "push", Pull: "pull", DoNothing: "do-nothing" } as const;
1068
- type PusherMode = typeof PusherMode[keyof typeof PusherMode];
1069
-
1070
- interface PusherConfig {
1071
- mode?: PusherMode;
1072
- filteredMode?: PusherMode;
1073
- angle?: number;
1074
- speed?: number;
1075
- filterInventory?: boolean;
1076
- length?: number;
1077
- }
1078
- ```
1079
-
1080
- State output:
1081
-
1082
- ```ts
1083
- interface PusherSummary {
1084
- entity: number;
1085
- mode: number;
1086
- modeName: string | null;
1087
- filteredMode: number;
1088
- filteredModeName: string | null;
1089
- angle: number | null;
1090
- speed: number;
1091
- length: number;
1092
- filterInventory: boolean;
1093
- filterSlots: (number | null)[] | null;
1094
- state: ModelRecord;
1095
- filterSlotsState: ModelRecord;
1096
- }
1097
-
1098
- interface PusherBeamSummary {
1099
- entity: number;
1100
- active: boolean;
1101
- mode: number;
1102
- modeName: string | null;
1103
- lengthRaw: number;
1104
- length: number;
1105
- state: ModelRecord;
1106
- }
1107
- ```
1108
-
1109
- Pusher beams are associated with the same entity as their parent pusher, exposed
1110
- as `pusher.beam`, `entity.feature("beam")`, and `machines.state().pusherBeams`.
1111
-
1112
- ### `LauncherHandle`
1113
-
1114
- ```ts
1115
- interface LauncherHandle extends MachineHandle {
1116
- state: LauncherSummary | null;
1117
- setAngle(angle: number): DredlessClient;
1118
- setPower(power: number): DredlessClient;
1119
- angleDegrees: number | undefined;
1120
- angleRadians: number | undefined;
1121
- angleRaw: number | null | undefined;
1122
- }
1123
-
1124
- interface LauncherSummary {
1125
- entity: number;
1126
- angleRaw: number | null;
1127
- angleRadians: number | null;
1128
- angleDegrees: number | null;
1129
- state: ModelRecord;
1130
- }
1131
- ```
1132
-
1133
- Launcher power may not be present until the relevant UI has exposed it.
1134
-
1135
- ### `NavigationUnitHandle`
1136
-
1137
- ```ts
1138
- interface NavigationUnitHandle extends MachineHandle {
1139
- state: NavigationUnitSummary | null;
1140
- configure(config?: NavigationUnitConfig): DredlessClient;
1141
- copy(config?: NavigationUnitConfig): DredlessClient;
1142
- paste(config?: NavigationUnitConfig): DredlessClient;
1143
- setDestination(destination: number, config?: NavigationUnitConfig): DredlessClient;
1144
- setAutoWarp(config?: NavigationUnitConfig): DredlessClient;
1145
- startWarp(config?: NavigationUnitConfig): DredlessClient;
1146
- cancelWarp(config?: NavigationUnitConfig): DredlessClient;
1147
- destination: number | undefined;
1148
- autoWarpOnShieldFailure: boolean | undefined;
1149
- autoWarpOnNoCaptains: boolean | undefined;
1150
- warp: string | undefined;
1151
- }
1152
- ```
1153
-
1154
- Config and state:
1155
-
1156
- ```ts
1157
- interface NavigationUnitConfig {
1158
- destination?: number;
1159
- page?: number;
1160
- warp?: boolean | "start" | "idle" | "cancel";
1161
- autoWarpOnShieldFailure?: boolean;
1162
- autoWarpOnNoCaptains?: boolean;
1163
- }
1164
-
1165
- interface NavigationUnitSummary {
1166
- entity: number;
1167
- destination: number;
1168
- destinationName: string | null;
1169
- autoWarpOnShieldFailure: boolean | null;
1170
- autoWarpOnNoCaptains: boolean | null;
1171
- state: ModelRecord;
1172
- }
1173
- ```
1174
-
1175
- ### `FabricatorHandle`
1176
-
1177
- ```ts
1178
- interface FabricatorHandle extends MachineHandle {
1179
- state: FabricatorSummary | null;
1180
- panel(): PuiEvent | null;
1181
- add(itemId: number, count?: number, index?: number): DredlessClient;
1182
- sub(itemId: number, count?: number, index?: number): DredlessClient;
1183
- clearQueue(): DredlessClient;
1184
- toggleRepeat(): DredlessClient;
1185
- lockResource(row: number): DredlessClient;
1186
- unlockResource(row: number): DredlessClient;
1187
- eject(row: number): DredlessClient;
1188
- }
1189
-
1190
- const FabricatorType = { Starter: "starter", Munitions: "munitions", Engineering: "engineering", Equipment: "equipment" } as const;
1191
- type FabricatorType = typeof FabricatorType[keyof typeof FabricatorType];
1192
-
1193
- interface FabricatorSummary {
1194
- entity: number;
1195
- type: FabricatorType | null;
1196
- typeIndex: number | null;
1197
- state: ModelRecord;
1198
- rows: { itemId: number | null; itemName: string | null; count: number | null }[];
1199
- progress: number | null;
1200
- progressRaw: number | null;
1201
- active: boolean;
1202
- craftingItemId: number | null;
1203
- craftingItemName: string | null;
1204
- craftingCount: number | null;
1205
- }
1206
- ```
1207
-
1208
- ### `CommsStationHandle`
1209
-
1210
- ```ts
1211
- interface CommsStationHandle extends MachineHandle {
1212
- state: CommsStationSummary | null;
1213
- panel(): CommsEvent | null;
1214
- sendMessage(message?: string): DredlessClient;
1215
- }
1216
-
1217
- interface CommsStationSummary {
1218
- entity: number;
1219
- typeId: number;
1220
- typeName: string | null;
1221
- charges: number | null;
1222
- maxCharges: number;
1223
- chargeRatio: number | null;
1224
- occupied: boolean;
1225
- state: ModelRecord;
1226
- }
1227
- ```
1228
-
1229
- ### `SignHandle`
1230
-
1231
- ```ts
1232
- interface SignHandle extends MachineHandle {
1233
- state: SignSummary | null;
1234
- setText(text?: string, mode?: SignDisplayMode): DredlessClient;
1235
- text: string | undefined;
1236
- mode: number | undefined;
1237
- }
1238
-
1239
- const SignDisplayMode = { Always: "always", WhenNear: "when-near", OnHover: "on-hover" } as const;
1240
- type SignDisplayMode = typeof SignDisplayMode[keyof typeof SignDisplayMode];
1241
-
1242
- interface SignSummary {
1243
- entity: number;
1244
- text: string;
1245
- displayMode: number;
1246
- displayModeName: string | null;
1247
- state: ModelRecord;
1248
- }
1249
- ```
1250
-
1251
- ### `GeneratorHandle`
1252
-
1253
- ```ts
1254
- interface GeneratorHandle extends MachineHandle {
1255
- state: ShieldGeneratorSummary | null;
1256
- solvePuzzle(solution: string | number): DredlessClient;
1257
- }
1258
-
1259
- interface ShieldGeneratorSummary {
1260
- entity: number;
1261
- charge: number;
1262
- maxCharge: number;
1263
- chargeRatio: number | null;
1264
- efficiencyPercent: number | null;
1265
- efficiency: number | null;
1266
- storedItemId: number | null;
1267
- storedItemName: string | null;
1268
- storedItemCount: number | null;
1269
- hasShieldCore: boolean;
1270
- boostState: number;
1271
- boostStateName: string | null;
1272
- boostTimer: number;
1273
- boostActive: boolean;
1274
- puzzleSeed: number | null;
1275
- puzzleSolution: string | null;
1276
- state: ModelRecord;
1277
- itemState: ModelRecord;
1278
- boostStateRaw: ModelRecord;
1279
- }
1280
- ```
1281
-
1282
- ### `CargoHatchHandle`
1283
-
1284
- ```ts
1285
- interface CargoHatchHandle extends MachineHandle {
1286
- state: CargoHatchSummary | null;
1287
- configure(config?: Pick<LoaderFullConfig, "filterMode" | "filterSlots">): DredlessClient;
1288
- copy(config?: Pick<LoaderFullConfig, "filterMode" | "filterSlots">): DredlessClient;
1289
- paste(config?: Pick<LoaderFullConfig, "filterMode" | "filterSlots">): DredlessClient;
1290
- setFilterMode(filterMode: LoaderFilterMode): DredlessClient;
1291
- setFilterItems(filterSlots?: Array<number | null | undefined>): DredlessClient;
1292
- }
1293
-
1294
- interface CargoHatchSummary {
1295
- entity: number;
1296
- typeId: number;
1297
- typeName: string | null;
1298
- filterMode: number;
1299
- filterModeName: string | null;
1300
- filterSlots: (number | null)[] | null;
1301
- openFraction: number | null;
1302
- filterState: ModelRecord;
1303
- filterSlotsState: ModelRecord;
1304
- }
1305
- ```
1306
-
1307
- ### Other machine handles
1308
-
1309
- ```ts
1310
- interface CannonHandle extends MachineHandle {
1311
- state: CannonSummary | null;
1312
- }
1313
-
1314
- interface ThrusterHandle extends MachineHandle {
1315
- state: ThrusterSummary | null;
1316
- }
1317
-
1318
- interface HelmHandle extends MachineHandle {
1319
- state: HelmSummary | null;
1320
- occupied: boolean | undefined;
1321
- }
1322
-
1323
- interface DoorHandle extends MachineHandle {
1324
- state: DoorSummary | null;
1325
- rank: number | undefined;
1326
- open: boolean | undefined;
1327
- }
1328
-
1329
- interface SpawnPointHandle extends MachineHandle {
1330
- state: SpawnPointSummary | null;
1331
- rank: number | undefined;
1332
- }
1333
-
1334
- interface ShieldProjectorHandle extends MachineHandle {
1335
- state: ShieldProjectorSummary | null;
1336
- active: boolean | undefined;
1337
- }
1338
-
1339
- interface FluidTankHandle extends MachineHandle {
1340
- state: FluidTankSummary | null;
1341
- amount: number | null | undefined;
1342
- }
1343
-
1344
- interface ExpandoBoxHandle extends MachineHandle {
1345
- state: ExpandoBoxSummary | null;
1346
- item: number | null | undefined;
1347
- count: number | null | undefined;
1348
- }
1349
-
1350
- interface CargoEjectorSummary {
1351
- entity: number;
1352
- typeId: number;
1353
- typeName: string | null;
1354
- progress: number | null;
1355
- active: boolean | null;
1356
- }
1357
-
1358
- interface CargoEjectorHandle extends MachineHandle {
1359
- state: CargoEjectorSummary | null;
1360
- progress: number | null | undefined;
1361
- active: boolean | null | undefined;
1362
- setDirection(direction: FixedAngleDirection): DredlessClient;
1363
- copy(direction?: FixedAngleDirection): DredlessClient;
1364
- paste(direction?: FixedAngleDirection): DredlessClient;
1365
- }
1366
- ```
1367
-
1368
- Associated summary shapes:
1369
-
1370
- ```ts
1371
- interface CannonSummary {
1372
- entity: number;
1373
- typeId: number;
1374
- typeName: string | null;
1375
- ammoItemId: number | null;
1376
- ammoName: string | null;
1377
- ammoCount: number;
1378
- aim: number | null;
1379
- recoil: number | null;
1380
- recoil2: number | null;
1381
- recoils: [number | null, number | null];
1382
- charge: number | null;
1383
- charged: boolean | null;
1384
- spin: number | null;
1385
- coolingCellCount: number;
1386
- state: ModelRecord;
1387
- }
1388
-
1389
- interface ThrusterSummary {
1390
- entity: number;
1391
- typeId: number;
1392
- typeName: string | null;
1393
- facing: number;
1394
- facingName:
1395
- | "bottom"
1396
- | "top"
1397
- | "right"
1398
- | "left"
1399
- | "bottom-right"
1400
- | "bottom-left"
1401
- | "top-right"
1402
- | "top-left"
1403
- | null;
1404
- fuel: number | null;
1405
- state: ModelRecord;
1406
- }
1407
-
1408
- interface HelmSummary {
1409
- entity: number;
1410
- typeId: number;
1411
- typeName: string | null;
1412
- occupied: boolean;
1413
- }
1414
-
1415
- interface DoorSummary {
1416
- entity: number;
1417
- rank: number;
1418
- rankName: string | null;
1419
- open: boolean;
1420
- rankState: ModelRecord;
1421
- state: ModelRecord;
1422
- }
1423
-
1424
- interface SpawnPointSummary {
1425
- entity: number;
1426
- rank: number;
1427
- rankName: string | null;
1428
- state: ModelRecord;
1429
- }
1430
-
1431
- interface ShieldProjectorSummary {
1432
- entity: number;
1433
- active: boolean;
1434
- state: ModelRecord;
1435
- }
1436
-
1437
- interface FluidTankSummary {
1438
- entity: number;
1439
- amount: number | null;
1440
- state: ModelRecord;
1441
- }
1442
-
1443
- interface ExpandoBoxSummary {
1444
- entity: number;
1445
- itemId: number | null;
1446
- itemName: string | null;
1447
- count: number | null;
1448
- width: number | null;
1449
- height: number | null;
1450
- rawWidth: number | null;
1451
- rawHeight: number | null;
1452
- itemState: ModelRecord;
1453
- sizeState: ModelRecord;
1454
- }
1455
- ```
1456
-
1457
- ## Ship Reads
1458
-
1459
- ### `ShipHandle`
1460
-
1461
- Returned by `client.overworld()?.ships()`.
1462
-
1463
- ```ts
1464
- interface ShipHandle {
1465
- entity: number;
1466
- name: string | null;
1467
- hexCode: string | null;
1468
- distance: number | null;
1469
- worldId: number | null;
1470
- hasWorldData: boolean;
1471
- world(): WorldDomain | null;
1472
- snapshot(): ShipReadSummary;
1473
- }
1474
- ```
1475
-
1476
- ### `ShipReadSummary`
1477
-
1478
- ```ts
1479
- interface ShipReadSummary {
1480
- entity: number;
1481
- name: string | null;
1482
- hexCode: string | null;
1483
- color: number | null;
1484
- colorCss: string | null;
1485
- position: { x: number | null; y: number | null; rot: number | null } | null;
1486
- distance: number | null;
1487
- footprint: EntitySummary["footprint"];
1488
- label: string;
1489
- kind: string[];
1490
- thrust: { x: number | null; y: number | null };
1491
- shield: ShipShieldSummary | null;
1492
- warp: ShipWarpSummary | null;
1493
- worldId: number | null;
1494
- hasWorldData: boolean;
1495
- world: WorldSnapshot | null;
1496
- control: ShipControlSummary;
1497
- entitySummary: EntitySummary;
1498
- }
1499
- ```
1500
-
1501
- ### `ShipControlSummary`
1502
-
1503
- ```ts
1504
- interface ShipControlSummary {
1505
- entity: number;
1506
- name: string | null;
1507
- hexCode: string | null;
1508
- shipWorldId: number | null;
1509
- color: number | null;
1510
- colorCss: string | null;
1511
- thrustX: number | null;
1512
- thrustY: number | null;
1513
- value52: number | null;
1514
- value84: number | null;
1515
- value96: number | null;
1516
- shield: ShipShieldSummary | null;
1517
- warp: ShipWarpSummary | null;
1518
- state: ModelRecord;
1519
- }
1520
- ```
1521
-
1522
- ### Ship shield and warp summaries
1523
-
1524
- ```ts
1525
- interface ShipShieldSummary {
1526
- maxHp: number | null;
1527
- baseHp: number | null;
1528
- activeTankHp: number | null;
1529
- inactiveTankHp: number | null;
1530
- tankValues: number[];
1531
- }
1532
-
1533
- interface ShipWarpSummary {
1534
- active: boolean;
1535
- ticks: number;
1536
- elapsedSeconds: number;
1537
- durationSeconds: number;
1538
- remainingSeconds: number;
1539
- }
1540
- ```
1541
-
1542
- ## Player, Blocks, Materials
1543
-
1544
- ```ts
1545
- interface PlayerCollection {
1546
- all(): PlayerSummary[];
1547
- current(): PlayerSummary | null;
1548
- }
1549
-
1550
- interface BlockCollection {
1551
- all(): BlockSummary[];
1552
- at(x: number, y: number): BlockSummary | null;
1553
- }
1554
-
1555
- interface MaterialCollection {
1556
- all(): MaterialSummary[];
1557
- }
1558
- ```
1559
-
1560
- ### `PlayerSummary`
1561
-
1562
- ```ts
1563
- interface PlayerSummary {
1564
- entity: number;
1565
- name: string | null;
1566
- heldItemId: number | null;
1567
- heldItemName: string | null;
1568
- repairTargetDistance: number | null;
1569
- repairTargetAngle: number | null;
1570
- shipRank: PlayerShipRank | null;
1571
- patronTier: "bronze" | "silver" | "gold" | "plat" | "flux" | null;
1572
- isDeveloper: boolean;
1573
- isPatron: boolean;
1574
- piloting: boolean;
1575
- muted: boolean;
1576
- actionPreview: PlayerActionPreviewSummary | null;
1577
- state: ModelRecord;
1578
- }
1579
- ```
1580
-
1581
- ### `PlayerActionPreviewSummary`
1582
-
1583
- ```ts
1584
- interface PlayerActionPreviewSummary {
1585
- entity: number;
1586
- active: boolean;
1587
- x: number | null;
1588
- y: number | null;
1589
- width: number | null;
1590
- height: number | null;
1591
- progress: number | null;
1592
- color: number | null;
1593
- colorCss: string | null;
1594
- actionName: "place" | "break" | "blueprint" | null;
1595
- blueprintId: number | null;
1596
- blueprintItems: BlueprintPreviewSummary[];
1597
- state: ModelRecord;
1598
- }
1599
- ```
1600
-
1601
- ### `BlockSummary`
1602
-
1603
- ```ts
1604
- interface BlockSummary {
1605
- x: number;
1606
- y: number;
1607
- entities: EntitySummary[];
1608
- }
1609
- ```
1610
-
1611
- ### `MaterialSummary`
1612
-
1613
- ```ts
1614
- interface MaterialSummary {
1615
- material: number;
1616
- name: string | null;
1617
- count: number;
1618
- solid: boolean | null;
1619
- hp: number | null;
1620
- }
1621
- ```
1622
-
1623
- ## World State Classes
1624
-
1625
- These classes are public mostly for inspection, replay, testing, and lower-level
1626
- tooling.
1627
-
1628
- ### `WorldStore`
1629
-
1630
- ```ts
1631
- class WorldStore {
1632
- currentWorldId: number | null;
1633
- worlds: Map<number, WorldState>;
1634
-
1635
- get(id: number): WorldState;
1636
- apply(packet: unknown): WorldUpdate | null;
1637
- snapshot(options?: { includeTiles?: boolean; includeModel?: boolean }): WorldSnapshot[];
1638
- ids(): number[];
1639
- overworld(): WorldState | null;
1640
- shipWorld(): WorldState | null;
1641
- currentShipEntity(): EntitySummary | null;
1642
- }
1643
- ```
1644
-
1645
- ### `WorldState`
1646
-
1647
- ```ts
1648
- class WorldState {
1649
- constructor(id: number);
1650
-
1651
- id: number;
1652
- seed: number | null;
1653
- isOverworld: boolean | null;
1654
- tileset: Tileset | null;
1655
- blockWidth: number | null;
1656
- blockHeight: number | null;
1657
- parentWorld: number | null;
1658
- parentEntity: number | null;
1659
- tiles: Map<string, Tile>;
1660
- chunks: unknown[];
1661
- events: unknown[];
1662
- modelPackets: unknown[];
1663
- commsBubbles: CommsBubbleSummary[];
1664
- model: ModelState;
1665
- lastChunkPatch: unknown;
1666
- lastPacket: unknown;
1667
- meta: unknown;
1668
-
1669
- readMeta(packet: unknown): void;
1670
- addCommsBubble(packet: unknown): CommsBubbleSummary;
1671
- decodeEncrypted(data: Uint8Array | ArrayBuffer | number[]): unknown;
1672
- applyTile(value: unknown): Tile | null;
1673
- applyChunk(value: unknown): Tile[] | null;
1674
- setTile(tile: Tile): Tile;
1675
- normalizeTile(tile: Tile): Tile;
1676
- materials(): MaterialSummary[];
1677
- snapshot(options?: { includeTiles?: boolean; includeModel?: boolean }): WorldSnapshot;
1678
- table(id: number): Map<number, ModelRecord>;
1679
- record(tableId: number, entityId: number): ModelRecord | null;
1680
- tileDefinition(material: number): TileDefinition | null;
1681
- entity(entityId: number): EntitySummary | null;
1682
- entities(): EntitySummary[];
1683
- blocks(): BlockSummary[];
1684
- }
1685
- ```
1686
-
1687
- ### `ModelState`
1688
-
1689
- ```ts
1690
- class ModelState {
1691
- generation: number | null;
1692
- tables: Map<number, Map<number, ModelRecord>>;
1693
- removedEntities: number[];
1694
- lastUpdate: unknown;
1695
- errors: unknown[];
1696
-
1697
- table(id: number): Map<number, ModelRecord>;
1698
- record(tableId: number, entityId: number): ModelRecord | null;
1699
- entity(entityId: number): EntitySummary | null;
1700
- entities(): EntitySummary[];
1701
- blocks(): BlockSummary[];
1702
- apply(bytes: Uint8Array | ArrayBuffer | number[]): unknown;
1703
- snapshot(options?: { includeTables?: boolean }): ModelSnapshot;
1704
- tablesSnapshot(): unknown[];
1705
- transforms(): TransformSummary[];
1706
- itemHolders(): ItemHolderSummary[];
1707
- fabricators(): FabricatorSummary[];
1708
- players(): PlayerSummary[];
1709
- shipControls(): ShipControlSummary[];
1710
- shipMetadata(): ShipWorldMetadataSummary | null;
1711
- machines(): MachineSummary;
1712
- }
1713
-
1714
- type ModelRecord = Record<string, unknown>;
1715
- ```
1716
-
1717
- ### `WorldSnapshot`
1718
-
1719
- ```ts
1720
- interface WorldSnapshot {
1721
- id: number;
1722
- is_overworld: boolean | null;
1723
- overworldZone: OverworldZoneSummary | null;
1724
- shipMetadata: ShipWorldMetadataSummary | null;
1725
- tileset: Tileset | null;
1726
- seed: number | null;
1727
- block_w: number | null;
1728
- block_h: number | null;
1729
- parent_world: number | null;
1730
- parent_ent: number | null;
1731
- tileCount: number;
1732
- chunkCount: number;
1733
- lastChunkPatch: unknown;
1734
- lastPacket: unknown;
1735
- meta: unknown;
1736
- materials: MaterialSummary[];
1737
- model: ModelSnapshot;
1738
- entities: EntitySummary[];
1739
- blocks: BlockSummary[];
1740
- transforms: TransformSummary[];
1741
- machines: MachineSummary;
1742
- players: PlayerSummary[];
1743
- shipControls: ShipControlSummary[];
1744
- commsBubbles: CommsBubbleSummary[];
1745
- tiles?: Tile[];
1746
- }
1747
- ```
1748
-
1749
- ### World metadata
1750
-
1751
- ```ts
1752
- interface OverworldZoneSummary {
1753
- id: number;
1754
- baseId: number;
1755
- layer: number;
1756
- key: string;
1757
- name: string;
1758
- tiered: boolean;
1759
- displayName: string;
1760
- }
1761
-
1762
- interface ShipWorldMetadataSummary {
1763
- name: string | null;
1764
- color: number | null;
1765
- colorCss: string | null;
1766
- width: number | null;
1767
- height: number | null;
1768
- lockdownTimerSeconds: number | null;
1769
- lockdownCountdownSeconds: number | null;
1770
- onlineShipOwnerCount: number | null;
1771
- requiredShipOwnerCount: number | null;
1772
- allShipOwnersOnline: boolean | null;
1773
- lockdownEngaged: boolean | null;
1774
- lockdownState: ModelRecord;
1775
- shipState: ModelRecord;
1776
- }
1777
-
1778
- interface WorldUpdate {
1779
- type: string;
1780
- world: WorldState | null;
1781
- packet?: unknown;
1782
- bubble?: CommsBubbleSummary;
1783
- decoded?: unknown;
1784
- updates?: unknown[];
1785
- result?: unknown;
1786
- }
1787
- ```
1788
-
1789
- ### Tiles
1790
-
1791
- ```ts
1792
- interface Tile {
1793
- x: number;
1794
- y: number;
1795
- material: number;
1796
- materialName?: string | null;
1797
- shape: number;
1798
- shapeName?: string | null;
1799
- hp: number;
1800
- /** @deprecated Use hp. Raw 0-255 HP fraction byte, not absolute integrity. */
1801
- integrity: number;
1802
- color: number | null;
1803
- solid?: boolean | null;
1804
- maxHp?: number | null;
1805
- hpRatio?: number | null;
1806
- hpValue?: number | null;
1807
- }
1808
-
1809
- interface TilePhysics {
1810
- filter?: {
1811
- categoryBits: number;
1812
- maskBits: number;
1813
- groupIndex: number;
1814
- };
1815
- transparent?: boolean;
1816
- walkway?: boolean;
1817
- restitution?: number;
1818
- friction?: number;
1819
- }
1820
-
1821
- interface TileDefinition {
1822
- name?: string;
1823
- solid: boolean;
1824
- destruct_item?: number;
1825
- blocks_bullets?: boolean;
1826
- hp?: number;
1827
- no_build_surface?: boolean;
1828
- physics?: TilePhysics;
1829
- }
1830
-
1831
- interface Tileset {
1832
- scale: number;
1833
- atlas: string;
1834
- tile_width: number;
1835
- tiles: TileDefinition[];
1836
- }
1837
- ```
1838
-
1839
- ### `ModelSnapshot`
1840
-
1841
- ```ts
1842
- interface ModelSnapshot {
1843
- generation: number | null;
1844
- tableCount: number;
1845
- entityCount: number;
1846
- removedEntities: number[];
1847
- lastUpdate: unknown;
1848
- errors: unknown[];
1849
- entities: EntitySummary[];
1850
- blocks: BlockSummary[];
1851
- transforms: TransformSummary[];
1852
- players: PlayerSummary[];
1853
- shipControls: ShipControlSummary[];
1854
- machines: MachineSummary;
1855
- tables: unknown[];
1856
- }
1857
- ```
1858
-
1859
- ## Additional Entity Component Shapes
1860
-
1861
- ```ts
1862
- interface TransformSummary {
1863
- entity: number;
1864
- x: number | null;
1865
- y: number | null;
1866
- rot: number | null;
1867
- flags: unknown[];
1868
- }
1869
-
1870
- interface ItemHolderSummary {
1871
- entity: number;
1872
- itemId: number | null;
1873
- itemName: string | null;
1874
- count: number | null;
1875
- }
1876
-
1877
- interface ItemCrateSummary {
1878
- entity: number;
1879
- itemId: number | null;
1880
- itemName: string | null;
1881
- count: number | null;
1882
- width: number | null;
1883
- height: number | null;
1884
- itemState: ModelRecord;
1885
- sizeState: ModelRecord;
1886
- }
1887
-
1888
- interface HoverOutlineSummary {
1889
- entity: number;
1890
- width: number | null;
1891
- height: number | null;
1892
- rawWidth: number | null;
1893
- rawHeight: number | null;
1894
- state: ModelRecord;
1895
- }
1896
-
1897
- interface MapMarkerSummary {
1898
- entity: number;
1899
- kind: string;
1900
- title: string | null;
1901
- key: string | null;
1902
- description: string | null;
1903
- color: number | null;
1904
- colorCss: string | null;
1905
- accentColor: number | null;
1906
- accentColorCss: string | null;
1907
- width: number | null;
1908
- height: number | null;
1909
- labelState: ModelRecord;
1910
- zoneState: ModelRecord;
1911
- }
1912
-
1913
- interface DockingSpringSummary {
1914
- entity: number;
1915
- id: number | null;
1916
- width: number;
1917
- height: number;
1918
- state: ModelRecord;
1919
- }
1920
-
1921
- interface HugeThrusterSummary {
1922
- entity: number;
1923
- width: number;
1924
- height: number;
1925
- state: ModelRecord;
1926
- }
1927
-
1928
- interface ShipSizeSummary {
1929
- entity: number;
1930
- width: number | null;
1931
- height: number | null;
1932
- rawWidth: number | null;
1933
- rawHeight: number | null;
1934
- state: ModelRecord;
1935
- }
1936
-
1937
- interface HealthSummary {
1938
- entity: number;
1939
- hp: number | null;
1940
- maxHp: number | null;
1941
- ratio: number | null;
1942
- state: ModelRecord;
1943
- }
1944
-
1945
- interface BotSummary {
1946
- entity: number;
1947
- className: string;
1948
- identifier: string;
1949
- typeA: number | null;
1950
- typeB: number | null;
1951
- }
1952
- ```
1953
-
1954
- ## Blueprint Shapes
1955
-
1956
- ### Placement request
1957
-
1958
- ```ts
1959
- interface BlueprintPlacement {
1960
- x: number;
1961
- y: number;
1962
- width?: number;
1963
- height?: number;
1964
- w?: number;
1965
- h?: number;
1966
- source: string;
1967
- }
1968
-
1969
- interface BlueprintPlacementMessage {
1970
- type: 9;
1971
- x: number;
1972
- y: number;
1973
- w: number;
1974
- h: number;
1975
- source: string;
1976
- }
1977
- ```
1978
-
1979
- ### Preview state
1980
-
1981
- ```ts
1982
- interface BlueprintPreviewSummary {
1983
- entity: number;
1984
- itemId: number;
1985
- itemName: string | null;
1986
- bits: number;
1987
- rawBits: number | null;
1988
- placementOffsets: number[];
1989
- placementCount: number;
1990
- placements: {
1991
- offset: number;
1992
- x: number | null;
1993
- y: number | null;
1994
- itemId: number;
1995
- itemName: string | null;
1996
- }[];
1997
- x: number | null;
1998
- y: number | null;
1999
- rot: number | null;
2000
- state: ModelRecord;
2001
- }
2002
- ```
2003
-
2004
- ## PUI And Comms Shapes
2005
-
2006
- ```ts
2007
- interface PuiEvent {
2008
- type: "pui";
2009
- filter?: number;
2010
- ent_id?: number;
2011
- update?: boolean;
2012
- data?: unknown;
2013
- world?: number | null;
2014
- }
2015
-
2016
- interface CommsMessage {
2017
- type: 3;
2018
- msg: string;
2019
- }
2020
-
2021
- interface NormalizedCommsMessage {
2022
- raw: unknown;
2023
- text: string;
2024
- }
2025
-
2026
- interface CommsEvent {
2027
- type: "comms";
2028
- filter?: number;
2029
- ent_id: number | null;
2030
- entity: number | null;
2031
- msgs_text: unknown[];
2032
- rawMessages: unknown[];
2033
- messages: NormalizedCommsMessage[];
2034
- update?: boolean;
2035
- world?: number | null;
2036
- }
2037
-
2038
- interface CommsBubbleSummary {
2039
- sequence: number;
2040
- worldId: number;
2041
- entity: number | null;
2042
- modelId: number | null;
2043
- message: string;
2044
- color: number | null;
2045
- colorCss: string | null;
2046
- durationSeconds: number | null;
2047
- raw: unknown;
2048
- }
2049
- ```
2050
-
2051
- ## Scanner And Ack Shapes
2052
-
2053
- ```ts
2054
- interface CommandAck {
2055
- world: number;
2056
- commandNumber: number;
2057
- }
2058
-
2059
- interface ScannerResult {
2060
- kind: "manifest" | "bom" | "unknown";
2061
- sid: number | null;
2062
- shipHex: string | null;
2063
- shipName: string | null;
2064
- blocks: Record<string, number> | null;
2065
- objects: Record<string, number> | null;
2066
- inventories: Record<string, number> | null;
2067
- materials: Record<string, number> | null;
2068
- }
2069
- ```
2070
-
2071
- ## Helper Function Exports
2072
-
2073
- These are public lower-level helpers. Prefer the object/domain methods unless
2074
- you explicitly need protocol payloads or decoded utility functions.
2075
-
2076
- ### Msgpack
2077
-
2078
- Module: `dredless/protocol/msgpack` or root.
2079
-
2080
- ```ts
2081
- function decodeMsgpack(bytes: Uint8Array | ArrayBuffer | number[]): unknown;
2082
- function encodeMsgpack(value: unknown): Uint8Array;
2083
- ```
2084
-
2085
- ### Commands
2086
-
2087
- Module: `dredless/protocol/commands` or root.
2088
-
2089
- ```ts
2090
- function buildSignedCommandPacket(command: Command, sessionId: number): Uint8Array;
2091
- ```
2092
-
2093
- ### Inventory helpers
2094
-
2095
- Module: `dredless/protocol/inventory` or root.
2096
-
2097
- ```ts
2098
- function normalizeEquipmentSlot(slot: EquipmentSlot): 16 | 17 | 18 | 19 | 20 | 21;
2099
- function equipmentSlotName(slot: number): "head" | "face" | "body" | "back" | "hands" | "feet" | null;
2100
- function buildInventoryDragCommand(source: number, target: number, split?: boolean): InventoryDragCommand;
2101
- function buildEquipItemCommand(source: number, slot: EquipmentSlot, split?: boolean): InventoryDragCommand;
2102
- function buildUnequipItemCommand(slot: EquipmentSlot, target?: number, split?: boolean): InventoryDragCommand;
2103
- function normalizeInventoryEvent(event: unknown): InventoryState;
2104
- ```
2105
-
2106
- Inventory drag output remains protocol-shaped:
2107
-
2108
- ```ts
2109
- interface InventoryDragCommand {
2110
- drag: {
2111
- source: number;
2112
- target: number;
2113
- split: boolean;
2114
- };
2115
- }
2116
- ```
2117
-
2118
- `normalizeInventoryEvent()` returns the normalized `InventoryState` shape documented under `client.inventory`.
2119
-
2120
- ### Comms helpers
2121
-
2122
- Module: `dredless/protocol/comms` or root.
2123
-
2124
- ```ts
2125
- function buildCommsMessage(message?: string): CommsMessage;
2126
- function normalizeCommsEvent(event: unknown): CommsEvent;
2127
- function flattenRichText(value: unknown): string;
2128
- ```
2129
-
2130
- ### Sign helpers
2131
-
2132
- Module: `dredless/protocol/sign` or root.
2133
-
2134
- ```ts
2135
- function buildSignTextMessage(text?: string, mode?: SignDisplayMode): SignTextMessage;
2136
- function normalizeSignDisplayMode(mode?: SignDisplayMode): 0 | 1 | 2;
2137
- function signDisplayModeName(mode: number): SignDisplayMode | null;
2138
- ```
2139
-
2140
- Output:
2141
-
2142
- ```ts
2143
- interface SignTextMessage {
2144
- type: 5;
2145
- cmd: "sign_text";
2146
- args: [string, 0 | 1 | 2];
2147
- }
2148
- ```
2149
-
2150
- ### Ship-management helpers
2151
-
2152
- Module: `dredless/protocol/ship-management` or root.
2153
-
2154
- ```ts
2155
- function buildShipManagementMessage(act: string, arg?: unknown, extra?: Record<string, unknown> | null): ShipManagementMessage;
2156
- function buildShipPrivacyMessage(privacy: ShipPrivacy): ShipManagementMessage;
2157
- function buildStarterRecoveryMessage(itemId: number): ShipManagementMessage;
2158
- function buildPlayerListMessage(): ShipManagementMessage;
2159
- function buildInviteResetMessage(): ShipManagementMessage;
2160
- function buildSetPlayerRankMessage(refId: number, rank: ShipPlayerRank): ShipManagementMessage;
2161
- function buildKickPlayerMessage(refId: number): ShipManagementMessage;
2162
- function buildBanPlayerMessage(refId: number): ShipManagementMessage;
2163
- function buildDemoteSelfMessage(): ShipManagementMessage;
2164
- function normalizePrivacy(privacy: ShipPrivacy): 0 | 1;
2165
- function normalizePlayerRank(rank: ShipPlayerRank): 0 | 1 | 3;
2166
- function normalizeShipConfig(event: unknown): ShipConfig;
2167
- function normalizeCaptainSubrank(event: unknown): CaptainSubrank;
2168
- function normalizeShipPlayerList(event: unknown, previous?: ShipPlayerList | null, currentCaptainSubrank?: CaptainSubrank | null): ShipPlayerList;
2169
- ```
2170
-
2171
- Message output:
2172
-
2173
- ```ts
2174
- interface ShipManagementMessage {
2175
- type: 4;
2176
- act: string;
2177
- arg: unknown;
2178
- rank?: unknown;
2179
- }
2180
- ```
2181
-
2182
- ### Blueprint helpers
2183
-
2184
- Module: `dredless/protocol/blueprint` or root.
2185
-
2186
- ```ts
2187
- function buildBlueprintPlacementMessage(placement: BlueprintPlacement): BlueprintPlacementMessage;
2188
- ```
2189
-
2190
- ### UI config helpers
2191
-
2192
- Module: `dredless/protocol/ui-config` or root.
2193
-
2194
- ```ts
2195
- function buildNavigationUnitConfigData(entity: number, config: NavigationUnitConfig & { destination: number }): Uint8Array;
2196
- function buildNavigationUnitClipboardConfigData(config: NavigationUnitConfig & { destination: number }): Uint8Array;
2197
- function buildNavigationUnitPasteConfigData(entity: number, config: NavigationUnitConfig & { destination: number }): Uint8Array;
2198
- function buildGeneratorMazePuzzleData(entity: number, solution: string | number): Uint8Array;
2199
- function buildCargoHatchFilterConfigData(entity: number, filterMode?: LoaderFilterMode): Uint8Array;
2200
- function buildCargoHatchFilterItemsData(entity: number, filterSlots?: Array<number | null | undefined>): Uint8Array;
2201
- function buildCargoHatchFullConfigData(entity: number, config?: Pick<LoaderFullConfig, "filterMode" | "filterSlots">): Uint8Array;
2202
- function buildCargoHatchCopyConfigData(config?: Pick<LoaderFullConfig, "filterMode" | "filterSlots">): Uint8Array;
2203
- function buildClipboardConfigData(target: ClipboardTarget, commandName: string, values?: Iterable<number>): Uint8Array;
2204
- function buildClipboardFixedAngleData(target: ClipboardTarget, direction: FixedAngleDirection): Uint8Array;
2205
- function buildGeneratorClipboardDirectionData(direction: FixedAngleDirection): Uint8Array;
2206
- function buildCargoEjectorDirectionData(entity: number, direction: FixedAngleDirection): Uint8Array;
2207
- function buildCargoEjectorPasteConfigData(entity: number, direction: FixedAngleDirection): Uint8Array;
2208
- function buildCargoEjectorCopyConfigData(direction: FixedAngleDirection): Uint8Array;
2209
- function buildCargoEjectorClipboardDirectionData(direction: FixedAngleDirection): Uint8Array;
2210
- function buildExpandoClipboardAngleData(angle: number): Uint8Array;
2211
- function buildLoaderClipboardConfigData(config?: LoaderConfig): Uint8Array;
2212
- function buildLoaderConfigData(entity: number, config?: LoaderConfig): Uint8Array;
2213
- function buildLoaderCopyConfigData(config?: LoaderFullConfig): Uint8Array;
2214
- function buildLoaderFilterConfigData(entity: number, filterMode?: LoaderFilterMode): Uint8Array;
2215
- function buildLoaderFilterItemsData(entity: number, filterSlots?: Array<number | null | undefined>): Uint8Array;
2216
- function buildLoaderFullConfigData(entity: number, config?: LoaderFullConfig): Uint8Array;
2217
- function buildPusherConfigData(entity: number, config?: PusherConfig): Uint8Array;
2218
- function buildPusherFilterItemsData(entity: number, filterSlots?: Array<number | null | undefined>): Uint8Array;
2219
- ```
2220
-
2221
- Clipboard/config input types:
2222
-
2223
- ```ts
2224
- type ClipboardTarget =
2225
- | number
2226
- | "loader" | "loader-config" | "loaderConfig"
2227
- | "hatch" | "cargo-hatch" | "cargoHatch"
2228
- | "ejector" | "cargo-ejector" | "cargoEjector"
2229
- | "expando" | "expando-box" | "expandoBox"
2230
- | "generator" | "shield-generator" | "shieldGenerator"
2231
- | "navigation" | "navigation-unit" | "navigationUnit"
2232
- | "nav" | "nav-unit" | "navUnit";
2233
-
2234
- const FixedAngleDirection = { Right: "right", Up: "up", Left: "left", Down: "down" } as const;
2235
- type FixedAngleDirection = typeof FixedAngleDirection[keyof typeof FixedAngleDirection];
2236
- ```
2237
-
2238
- ### Generator maze helpers
2239
-
2240
- Module: `dredless/game/generator-maze` or root.
2241
-
2242
- ```ts
2243
- function generateGeneratorMaze(seed: number): GeneratorMaze;
2244
- function solveGeneratorMazeSeed(seed: number): string;
2245
- function maybeSolveGeneratorMazeSeed(seed: number | null | undefined): string | null;
2246
- ```
2247
-
2248
- Output:
2249
-
2250
- ```ts
2251
- interface GeneratorMazeCellWalls {
2252
- up: boolean;
2253
- down: boolean;
2254
- left: boolean;
2255
- right: boolean;
2256
- }
2257
-
2258
- interface GeneratorMazeCell {
2259
- x: number;
2260
- y: number;
2261
- value: number;
2262
- hex: string;
2263
- digit: number;
2264
- walls: GeneratorMazeCellWalls;
2265
- backtrackDirection: number;
2266
- marker: number;
2267
- }
2268
-
2269
- interface GeneratorMaze {
2270
- seed: number;
2271
- width: number;
2272
- height: number;
2273
- cells: GeneratorMazeCell[];
2274
- rows: GeneratorMazeCell[][];
2275
- solution: string;
2276
- }
2277
- ```
2278
-
2279
- ### Crypto, compression, and model decoding
2280
-
2281
- Modules: `dredless/crypto/chacha`, `dredless/compression/lz4`,
2282
- `dredless/model`, and root.
2283
-
2284
- ```ts
2285
- function decryptPayload(
2286
- wireBytes: Uint8Array | ArrayBuffer | number[],
2287
- worldId: number,
2288
- seed: number
2289
- ): Uint8Array;
2290
-
2291
- function decompressLz4Frame(bytes: Uint8Array | ArrayBuffer | number[]): Uint8Array;
2292
-
2293
- function decodeModelData(bytes: Uint8Array | ArrayBuffer | number[]): unknown;
2294
- ```
2295
-
2296
- ### Ship spec helpers
2297
-
2298
- Module: `dredless/ships`.
2299
-
2300
- ```ts
2301
- function createShipSpec(name?: string, color?: string): ShipSpec;
2302
- function createInviteShipSpec(code: string): ShipSpec;
2303
- ```
2304
-
2305
- `createShipSpec()` returns a `{ type: "new", ... }` ship spec.
2306
- `createInviteShipSpec()` returns a `{ type: "invite", code }` ship spec.
2307
-
2308
- ## Public Constants From Subpath Modules
2309
-
2310
- These constants are exported by helper subpaths for consumers that need protocol
2311
- symbols. They are not required for normal object-domain use.
2312
-
2313
- ### `dredless/protocol/blueprint`
2314
-
2315
- ```ts
2316
- const BLUEPRINT_PLACEMENT_TYPE: 9;
2317
- ```
2318
-
2319
- ### `dredless/protocol/comms`
2320
-
2321
- ```ts
2322
- const COMMS_MESSAGE_TYPE: 3;
2323
- ```
2324
-
2325
- ### `dredless/protocol/inventory`
2326
-
2327
- ```ts
2328
- const EQUIPMENT_SLOT_INDEXES: Readonly<{
2329
- head: 16;
2330
- face: 17;
2331
- body: 18;
2332
- back: 19;
2333
- hands: 20;
2334
- feet: 21;
2335
- }>;
2336
- ```
2337
-
2338
- ### `dredless/protocol/ship-management`
2339
-
2340
- ```ts
2341
- const BAN_ACTION: "ban";
2342
- const DEMOTE_SELF_ACTION: "demote_self";
2343
- const KICK_ACTION: "kick";
2344
- const PLAYER_LIST_ACTION: "player_list";
2345
- const INVITE_RESET_ACTION: "invite_reset";
2346
- const SET_PRIVACY_ACTION: "set_privacy";
2347
- const SET_RANK_ACTION: "set_rank";
2348
- const SHIP_MANAGEMENT_TYPE: 4;
2349
- const STARTER_RECOVERY_ACTION: "starter_recovery";
2350
- ```
2351
-
2352
- ### `dredless/protocol/sign`
2353
-
2354
- ```ts
2355
- const SIGN_TEXT_COMMAND: "sign_text";
2356
- const SIGN_DISPLAY_MODES: Map<0 | 1 | 2, "always" | "when-near" | "on-hover">;
2357
- ```
2358
-
2359
- ### `dredless/protocol/ui-config`
2360
-
2361
- ```ts
2362
- const CLIPBOARD_ACTION: 1;
2363
- const CLIPBOARD_ANGLE_COMMAND: "angle";
2364
- const CLIPBOARD_FIXED_ANGLE_COMMAND: "angle_fixed";
2365
- const CLIPBOARD_TARGET_VALUES: Map<string, number>;
2366
- const FIXED_ANGLE_VALUES: Map<string, 0 | 1 | 2 | 3>;
2367
- const GENERATOR_MAZE_PUZZLE_COMMAND: "maze_puzzle";
2368
- const LOADER_CONFIG_COMMAND: "config_loader";
2369
- const LOADER_FALSE: 0x8e;
2370
- const LOADER_FILTER_CONFIG_COMMAND: "filter_config";
2371
- const LOADER_FILTER_ITEMS_COMMAND: "filter_items";
2372
- const LOADER_TRUE: 0x8d;
2373
- const NAV_UNIT_COMMAND: "config_nav_unit";
2374
- const NAV_UNIT_FALSE: 0x8d;
2375
- const NAV_UNIT_TRUE: 0x8e;
2376
- const PUSHER_CONFIG_COMMAND: "config_pusher";
2377
- const PUSHER_FILTER_ITEMS_COMMAND: "filter_items";
2378
- ```
2379
-
2380
- ## Usage Patterns
2381
-
2382
- ### Read loaders from a live client
2383
-
2384
- Use [NODE_API.md](./NODE_API.md) or [BROWSER_API.md](./BROWSER_API.md) to start a client for the current runtime.
2385
-
2386
- ```js
2387
- await client.whenReady();
2388
-
2389
- for (const loader of client.currentShip().machines.loaders()) {
2390
- console.log(loader.id, loader.pick, loader.place, loader.cycle);
2391
- }
2392
- ```
2393
-
2394
- ### Read all nearby ships, including detailed loaded worlds when available
2395
-
2396
- ```js
2397
- const ships = client.overworld().ships({
2398
- includeWorld: true,
2399
- includeModel: true,
2400
- sort: "distance"
2401
- });
2402
-
2403
- for (const ship of ships) {
2404
- const snapshot = ship.snapshot();
2405
- console.log(snapshot.name, snapshot.hexCode, snapshot.hasWorldData);
2406
- }
2407
- ```
2408
-
2409
- ### Use generic features before narrowing to a machine type
2410
-
2411
- ```js
2412
- const entity = client.currentShip().entities.get(14);
2413
-
2414
- if (entity.has("loader")) {
2415
- const loader = entity.asLoader();
2416
- loader.setCycle(10);
2417
- }
2418
-
2419
- if (entity.has("outline")) {
2420
- console.log(entity.feature("outline"));
2421
- }
2422
- ```
2423
-
2424
- ### Configure a pusher
2425
-
2426
- ```js
2427
- const pusher = client.currentShip().machines.pusher(27);
2428
-
2429
- pusher.configure({
2430
- mode: "push",
2431
- filteredMode: "pull",
2432
- angle: 90,
2433
- speed: 20,
2434
- length: 30,
2435
- filterInventory: true
2436
- });
2437
- ```
2438
-
2439
- ### Configure a navigation unit
2440
-
2441
- ```js
2442
- const nav = client.currentShip().machines.navigationUnit();
2443
-
2444
- nav.setDestination(30, {
2445
- autoWarpOnShieldFailure: true,
2446
- autoWarpOnNoCaptains: false
2447
- });
2448
- ```
2449
-
2450
- ## Cost Guidelines
2451
-
2452
- Use handles for normal live code:
2453
-
2454
- ```js
2455
- client.currentShip().entities.get(id);
2456
- client.currentShip().machines.loader(id);
2457
- ```
2458
-
2459
- Use raw grouped state for display, sorting, and cheap bulk reads:
2460
-
2461
- ```js
2462
- client.currentShip().entities.raw();
2463
- client.currentShip().machines.state();
2464
- ```
2465
-
2466
- Use snapshots when you need immutable point-in-time data:
2467
-
2468
- ```js
2469
- entity.snapshot();
2470
- client.currentShip().entities.snapshots();
2471
- client.state({ includeModel: true });
2472
- ```
2473
-
2474
- Use debug and world/model classes when reverse engineering, replaying captures,
2475
- or validating protocol assumptions:
2476
-
2477
- ```js
2478
- client.debug.modelRecord(worldId, tableId, entityId);
2479
- client.debug.decodeErrors();
2480
- client.debug.worldStore();
2481
- ```
1
+ # Dredless API Reference
2
+
3
+ This document describes the public JavaScript API exposed by the package.
4
+ Here, "endpoint" means a public method, constructor, domain method, or exported
5
+ helper function. The actual browser/game wire protocol remains an implementation
6
+ detail unless a helper explicitly builds or decodes protocol payloads.
7
+
8
+ Use the runtime-specific top-level API references for session, token, and start/join helpers:
9
+
10
+ - [NODE_API.md](./NODE_API.md): explicit multi-session `Session` / `AnonSession` API for Node.
11
+ - [BROWSER_API.md](./BROWSER_API.md): ambient browser-session API for browser contexts.
12
+
13
+ This shared reference covers common input/output shapes, `DredlessClient`, world/entity/domain APIs, protocol helpers, and other runtime-neutral APIs.
14
+
15
+ Subpath imports are available for focused low-level helpers:
16
+
17
+ ```js
18
+ import { DredlessClient } from "dredless/client";
19
+ import { WorldStore, WorldState } from "dredless/world";
20
+ import { generateGeneratorMaze } from "dredless/game/generator-maze";
21
+ import { encodeMsgpack, decodeMsgpack, decodeIncomingFrame } from "dredless/protocol";
22
+ ```
23
+
24
+ ## Public Package Exports
25
+
26
+ `package.json` currently exposes these module specifiers:
27
+
28
+ ```txt
29
+ dredless
30
+ dredless/browser
31
+ dredless/node
32
+ dredless/client
33
+ dredless/network
34
+ dredless/state
35
+ dredless/session
36
+ dredless/servers
37
+ dredless/ships
38
+ dredless/connection
39
+ dredless/world
40
+ dredless/model
41
+ dredless/game/generator-maze
42
+ dredless/game/model
43
+ dredless/protocol
44
+ dredless/protocol/blueprint
45
+ dredless/protocol/comms
46
+ dredless/protocol/commands
47
+ dredless/protocol/inventory
48
+ dredless/protocol/ship-management
49
+ dredless/protocol/sign
50
+ dredless/protocol/ui-config
51
+ dredless/crypto/chacha
52
+ dredless/compression/lz4
53
+ ```
54
+
55
+ The root module defaults to the Node API for types and direct Node imports. Browser bundlers may use the root `browser` condition for JavaScript, but `dredless/browser` is the reliable import for browser IntelliSense.
56
+
57
+ Both runtime entrypoints re-export world/model classes, protocol builders, config builders, codec helpers, and common type shapes.
58
+
59
+ ## Common Input Types
60
+
61
+ ### `Server`
62
+
63
+ Returned by `fetchServers()`.
64
+
65
+ ```ts
66
+ interface Server {
67
+ index: number;
68
+ domain: string;
69
+ description: string;
70
+ playerCount: number;
71
+ maxPlayerCount: number;
72
+ ping: number | null;
73
+ }
74
+ ```
75
+
76
+ ### `ServerRef`
77
+
78
+ Accepted anywhere a server is required.
79
+
80
+ ```ts
81
+ type ServerRef = number | Server;
82
+ ```
83
+
84
+ Passing a number selects a server index. Passing a `Server` object uses its
85
+ domain and index directly.
86
+
87
+ ### `Ship`
88
+
89
+ Returned by ship list reads.
90
+
91
+ ```ts
92
+ interface Ship {
93
+ id: number | null;
94
+ hexCode: string | null;
95
+ name: string;
96
+ iconUrl: string | null;
97
+ playerCount: number;
98
+ owned: boolean;
99
+ saved: boolean;
100
+ color: string;
101
+ time: number | null;
102
+ }
103
+ ```
104
+
105
+ ### `ShipList`
106
+
107
+ Returned by `fetchShipList()`.
108
+
109
+ ```ts
110
+ interface ShipList {
111
+ playerCount?: number;
112
+ maxPlayerCount?: number;
113
+ isMuted?: boolean;
114
+ ships: Ship[];
115
+ }
116
+ ```
117
+
118
+ ### `ShipSpec`, `ShipRef`
119
+
120
+ Accepted by join/start methods.
121
+
122
+ ```ts
123
+ type ShipSpec =
124
+ | { type: "join_or_load"; id: number | string }
125
+ | { type: "new"; name?: string | null; color?: string | null }
126
+ | { type: "invite"; code: string };
127
+
128
+ type ShipRef = number | string | Ship | ShipSpec | null;
129
+ ```
130
+
131
+ Useful interpretations:
132
+
133
+ ```txt
134
+ number -> ship id
135
+ string -> ship id/hex-like selector, depending on server API
136
+ Ship -> ship from fetchShips/fetchShipList
137
+ { type: "new" } -> create or start a new ship
138
+ { type: "invite" } -> join by invite code
139
+ null or undefined -> default behavior for the method
140
+ ```
141
+
142
+ ## Runtime Top-Level APIs
143
+
144
+ Top-level runtime APIs are split by environment:
145
+
146
+ - Node explicit session/token/start helpers: [NODE_API.md](./NODE_API.md)
147
+ - Browser ambient session/start helpers: [BROWSER_API.md](./BROWSER_API.md)
148
+
149
+ `Connection`, `Session`, `AnonSession`, `BrowserSession`, `Dredless`, and `DredlessBrowser` are documented in those runtime-specific files.
150
+
151
+ ## `DredlessClient`
152
+
153
+ `DredlessClient` owns the websocket, outgoing commands, incoming packets, and
154
+ decoded state domains.
155
+
156
+ ```ts
157
+ class DredlessClient {
158
+ constructor(connection: Connection, options?: { connect?: boolean });
159
+ static attachWebSocket(websocket: unknown, options?: AttachWebSocketOptions): DredlessClient;
160
+
161
+ connection: Connection | null;
162
+ session: Session | null;
163
+ baseUrl: string | null;
164
+ attachMode: "observe" | "bootstrap" | "readonly" | null;
165
+ attached: boolean;
166
+ serverId: number | null;
167
+ server: Server | null;
168
+ netPort: number | null;
169
+ gameToken: string;
170
+ ws: unknown;
171
+ sid: number | null;
172
+ connected: boolean;
173
+ ready: boolean;
174
+ packetCount: number;
175
+ lastPacket: unknown;
176
+
177
+ net: ClientNetDomain;
178
+ debug: ClientDebugDomain;
179
+ player: PlayerDomain;
180
+ inventory: InventoryDomain;
181
+ management: ShipManagementDomain;
182
+ readyPromise: Promise<this>;
183
+
184
+ whenReady(): Promise<this>;
185
+ close(code?: number, reason?: string): this;
186
+ disconnect(code?: number, reason?: string): this;
187
+
188
+ currentShip(): ShipDomain | null;
189
+ ship(): ShipDomain | null;
190
+ overworld(): OverworldDomain | null;
191
+ world(id: number): WorldDomain | null;
192
+ shipWorld(options?: { includeTiles?: boolean; includeModel?: boolean }): WorldSnapshot | null;
193
+ state(options?: { includeTiles?: boolean; includeModel?: boolean }): ClientSnapshot;
194
+ entities(scope?: number | string): EntitySummary[];
195
+ entity(entityId: number, scope?: number | string): EntitySnapshot | null;
196
+ currentPlayerEntity(): EntityHandle | null;
197
+
198
+ on(type: string, callback: (...args: unknown[]) => void): this;
199
+ off(type: string, callback: (...args: unknown[]) => void): this;
200
+ once(type: string, callback: (...args: unknown[]) => void): this;
201
+ }
202
+ ```
203
+
204
+ ### Constructor
205
+
206
+ ```js
207
+ const client = new DredlessClient(connection);
208
+ ```
209
+
210
+ By default the constructor opens the websocket. For tests or offline state
211
+ inspection, pass `{ connect: false }`:
212
+
213
+ ```js
214
+ const client = new DredlessClient(connection, { connect: false });
215
+ ```
216
+
217
+ ### `DredlessClient.attachWebSocket(websocket, options?)`
218
+
219
+ ```ts
220
+ type WebSocketAttachMode = "observe" | "bootstrap" | "readonly";
221
+
222
+ interface AttachWebSocketOptions {
223
+ mode?: WebSocketAttachMode;
224
+ connected?: boolean | null;
225
+ ready?: boolean;
226
+ sid?: number | null;
227
+ baseUrl?: string | null;
228
+ session?: Session | null;
229
+ serverId?: number | null;
230
+ server?: Server | null;
231
+ netPort?: number | null;
232
+ gameToken?: string;
233
+ }
234
+ ```
235
+
236
+ Attaches Dredless to an existing websocket without requiring a `Connection`.
237
+ This is intended for observing or integrating with an already-open browser/game websocket.
238
+
239
+ Modes:
240
+
241
+ - `"observe"` default: decodes incoming packets and allows explicit writes through normal handle/client methods, but does not send hello, bootstrap, or keepalive automatically.
242
+ - `"bootstrap"`: treats the websocket like a normally owned Dredless socket; sends hello on open and runs bootstrap, keepalive, and queued-message flushing on ready.
243
+ - `"readonly"`: decodes incoming packets only and rejects all write methods. `close()` is a no-op in this mode.
244
+
245
+ Optional metadata such as `server`, `serverId`, and `netPort` is only used for snapshots/logging; it is not required to attach.
246
+
247
+ ```js
248
+ const client = DredlessClient.attachWebSocket(window.tpgaClient.repsocket.websocket);
249
+ client.on("packet", (packet) => console.log(packet.type));
250
+ ```
251
+
252
+ ### Lifecycle endpoints
253
+
254
+ ```ts
255
+ whenReady(): Promise<this>;
256
+ close(code?: number, reason?: string): this;
257
+ disconnect(code?: number, reason?: string): this;
258
+ ```
259
+
260
+ `whenReady()` resolves once the ready packet is received. For normally-owned clients and `attachWebSocket(..., { mode: "bootstrap" })`, bootstrap commands have also been sent.
261
+
262
+ ### World/domain endpoints
263
+
264
+ ```ts
265
+ currentShip(): ShipDomain | null;
266
+ ship(): ShipDomain | null;
267
+ currentPlayerEntity(): EntityHandle | null;
268
+ overworld(): OverworldDomain | null;
269
+ world(id: number): WorldDomain | null;
270
+ shipWorld(options?): WorldSnapshot | null;
271
+ ```
272
+
273
+ Use `currentShip()` for the currently loaded ship world. Use `overworld()` for
274
+ zone-level objects such as nearby ships and overworld entities.
275
+
276
+ `currentPlayerEntity()` returns the current player entity handle in the loaded
277
+ ship world, or `null` before the player entity is known.
278
+
279
+ ### Compatibility entity endpoints
280
+
281
+ ```ts
282
+ entities(scope?: number | string): EntitySummary[];
283
+ entity(entityId: number, scope?: number | string): EntitySnapshot | null;
284
+ ```
285
+
286
+ Prefer `client.currentShip()?.entities` and `client.overworld()?.entities` for
287
+ new code. These compatibility methods use `"ship"` by default.
288
+
289
+ Valid common scopes are:
290
+
291
+ ```txt
292
+ "ship"
293
+ "current"
294
+ "overworld"
295
+ number world id
296
+ ```
297
+
298
+ ### Events
299
+
300
+ ```ts
301
+ on(type: string, callback: (...args: unknown[]) => void): this;
302
+ off(type: string, callback: (...args: unknown[]) => void): this;
303
+ once(type: string, callback: (...args: unknown[]) => void): this;
304
+ ```
305
+
306
+ Events are implementation-defined strings emitted by the client event bus.
307
+
308
+ ## `client.state()` Output
309
+
310
+ ```ts
311
+ interface ClientSnapshot {
312
+ baseUrl: string;
313
+ session: SessionSnapshot;
314
+ connection: ConnectionSnapshot | null;
315
+ attachMode: "observe" | "bootstrap" | "readonly" | null;
316
+ serverId: number | null;
317
+ server: Server | null;
318
+ netPort: number | null;
319
+ sid: number | null;
320
+ ready: boolean;
321
+ connected: boolean;
322
+ currentWorldId: number | null;
323
+ worlds: WorldSnapshot[];
324
+ cpuLoad: number | null;
325
+ inventory: InventoryState | null;
326
+ puiPanels: PuiEvent[];
327
+ commsPanels: CommsEvent[];
328
+ currentCommsPanel: CommsEvent | null;
329
+ warnings: unknown[];
330
+ effects: unknown[];
331
+ chat: unknown[];
332
+ motd: unknown[];
333
+ sessionMessages: unknown[];
334
+ scannerResults: ScannerResult[];
335
+ lastScannerResult: ScannerResult | null;
336
+ shipConfig: ShipConfig | null;
337
+ captainSubrank: CaptainSubrank | null;
338
+ playerList: ShipPlayerList | null;
339
+ outfits: { sid: number; outfit: unknown }[];
340
+ commandAcks: CommandAck[];
341
+ lastCommandAck: CommandAck | null;
342
+ decodeErrors: unknown[];
343
+ packetCount: number;
344
+ lastPacket: unknown;
345
+ }
346
+ ```
347
+
348
+ ## Client Domain APIs
349
+
350
+ ### `client.net`
351
+
352
+ Low-level outgoing network domain.
353
+
354
+ ```ts
355
+ interface ClientNetDomain {
356
+ connected: boolean;
357
+ ready: boolean;
358
+ sid: number | null;
359
+ packetCount: number;
360
+ lastPacket: unknown;
361
+ send(command?: Command): DredlessClient;
362
+ sendMessage(message: unknown, options?: { afterReady?: boolean }): DredlessClient;
363
+ sendRaw(message: unknown, options?: { afterReady?: boolean }): DredlessClient;
364
+ sendEntityCommand(cmd: string, args?: unknown[]): DredlessClient;
365
+ sendUiConfig(data: unknown): DredlessClient;
366
+ sendBlueprintPlacement(placement: BlueprintPlacement): DredlessClient;
367
+ setOutfit(outfit: unknown): DredlessClient;
368
+ }
369
+ ```
370
+
371
+ `send()` signs and sends a command-like packet. `sendMessage()` sends a decoded
372
+ protocol message. `sendRaw()` sends already-built/raw content. The specialized
373
+ helpers build the corresponding protocol command and return the client for
374
+ chaining.
375
+
376
+ ### `Command`
377
+
378
+ General command shape for movement, actions, UI focus, and drag operations.
379
+
380
+ ```ts
381
+ interface Command {
382
+ type?: number;
383
+ n?: number | null;
384
+ x?: number;
385
+ y?: number;
386
+ mx?: number;
387
+ my?: number;
388
+ vx?: number;
389
+ vy?: number;
390
+ jump?: boolean;
391
+ jump_held?: boolean;
392
+ drop?: boolean;
393
+ act1?: boolean;
394
+ act1_held?: boolean;
395
+ exit?: boolean;
396
+ act2?: boolean;
397
+ act_alt?: boolean;
398
+ act_alt_held?: boolean;
399
+ wrench_mode?: number;
400
+ turret_mode?: number;
401
+ scr_w?: number;
402
+ scr_h?: number;
403
+ motion?: number;
404
+ focus_ent?: number | null;
405
+ config_ent?: number | null;
406
+ tip_select?: number | null;
407
+ inv_slot?: number;
408
+ blur?: boolean;
409
+ drag?: DragPayload | null;
410
+ }
411
+ ```
412
+
413
+ ### `client.debug`
414
+
415
+ Read-only debugging and raw-state access.
416
+
417
+ ```ts
418
+ interface ClientDebugDomain {
419
+ packets(): unknown[];
420
+ decodeErrors(): unknown[];
421
+ worldStore(): WorldStore;
422
+ modelTable(worldId: number, tableId: number): Map<number, ModelRecord>;
423
+ modelRecord(worldId: number, tableId: number, entityId: number): ModelRecord | null;
424
+ puiPanels(): PuiEvent[];
425
+ commsPanels(): CommsEvent[];
426
+ }
427
+ ```
428
+
429
+ ### `client.player`
430
+
431
+ Player input and action domain.
432
+
433
+ ```ts
434
+ interface PlayerDomain {
435
+ current(): PlayerSummary | null;
436
+ entity(): EntityHandle | null;
437
+ name(): string | null;
438
+ rank(): CurrentPlayerRank;
439
+ move(vector?: { x?: number; y?: number }, command?: Command): DredlessClient;
440
+ aim(point?: { x?: number; y?: number; mx?: number; my?: number }, command?: Command): DredlessClient;
441
+ action(flags?: Command, command?: Command): DredlessClient;
442
+ useEntity(entity: number | EntityHandle | EntitySummary, options?: { invSlot?: number; hold?: boolean }, command?: Command): DredlessClient;
443
+ useHeldItem(options?: { invSlot?: number; hold?: boolean }, command?: Command): DredlessClient;
444
+ placeHeldItem(options?: { invSlot?: number; hold?: boolean }, command?: Command): DredlessClient;
445
+ placeBlueprint(placement: BlueprintPlacement, options?: { invSlot?: number; hold?: boolean; mx?: number; my?: number }, command?: Command): DredlessClient;
446
+ rotateHeldItem(options?: { invSlot?: number; hold?: boolean }, command?: Command): DredlessClient;
447
+ selectSlot(invSlot?: number, command?: Command): DredlessClient;
448
+ inputSettings(): CurrentInputSettings;
449
+ setInputSettings(settings?: InputSettings, options?: { send?: boolean }): DredlessClient;
450
+ setView(width: number, height: number, options?: { send?: boolean }): DredlessClient;
451
+ setScreenSize(width: number, height: number, options?: { send?: boolean }): DredlessClient;
452
+ setWrenchMode(mode: WrenchMode, options?: { send?: boolean }): DredlessClient;
453
+ setTurretMode(mode: TurretMode, options?: { send?: boolean }): DredlessClient;
454
+ }
455
+ ```
456
+
457
+ ### Input setting shapes
458
+
459
+ ```ts
460
+ const WrenchMode = { DropAllItems: "drop-all-items", GrabPrimaryItems: "grab-primary-items", GrabAllItems: "grab-all-items" } as const;
461
+ type WrenchMode = typeof WrenchMode[keyof typeof WrenchMode];
462
+
463
+ const TurretMode = { ContinuousFire: "continuous-fire", VolleyFire: "volley-fire" } as const;
464
+ type TurretMode = typeof TurretMode[keyof typeof TurretMode];
465
+
466
+ interface InputSettings {
467
+ wrenchMode?: WrenchMode;
468
+ turretMode?: TurretMode;
469
+ viewWidth?: number;
470
+ viewHeight?: number;
471
+ screenWidth?: number;
472
+ screenHeight?: number;
473
+ }
474
+
475
+ interface CurrentInputSettings {
476
+ wrenchMode: "drop-all-items" | "grab-primary-items" | "grab-all-items" | null;
477
+ turretMode: "continuous-fire" | "volley-fire" | null;
478
+ viewWidth: number | null;
479
+ viewHeight: number | null;
480
+ screenWidth: number | null;
481
+ screenHeight: number | null;
482
+ }
483
+ ```
484
+
485
+ ### `client.inventory`
486
+
487
+ Inventory read and slot movement domain.
488
+
489
+ ```ts
490
+ type InventoryArea = "all" | "hotbar" | "equipment";
491
+ type InventorySlotRef = number | EquipmentSlot | InventorySlotHandle | InventorySlotSnapshot;
492
+ const EquipmentSlot = { Head: "head", Face: "face", Body: "body", Back: "back", Hands: "hands", Feet: "feet" } as const;
493
+ type EquipmentSlot = typeof EquipmentSlot[keyof typeof EquipmentSlot];
494
+
495
+ interface InventoryDomain {
496
+ state(): InventoryState | null;
497
+ hotbarSize(): number;
498
+ allSlots(): InventorySlotHandle[];
499
+ slot(ref: InventorySlotRef): InventorySlotHandle;
500
+ hotbarSlots(): InventorySlotHandle[];
501
+ equipmentSlots(): { head: InventorySlotHandle; face: InventorySlotHandle; body: InventorySlotHandle; back: InventorySlotHandle; hands: InventorySlotHandle; feet: InventorySlotHandle };
502
+ findItem(itemId: number, options?: { area?: InventoryArea }): InventorySlotHandle | null;
503
+ findItems(itemId: number, options?: { area?: InventoryArea }): InventorySlotHandle[];
504
+ firstEmpty(options?: { area?: InventoryArea }): InventorySlotHandle | null;
505
+ move(source: InventorySlotRef, target: InventorySlotRef, options?: { split?: boolean }, command?: Command): DredlessClient;
506
+ equip(source: InventorySlotRef, equipmentSlot?: EquipmentSlot | { split?: boolean }, options?: { split?: boolean } | Command, command?: Command): DredlessClient;
507
+ unequip(equipmentSlot: EquipmentSlot, target?: InventorySlotRef, options?: { split?: boolean }, command?: Command): DredlessClient;
508
+ select(slot: InventorySlotRef, command?: Command): DredlessClient;
509
+ }
510
+ ```
511
+
512
+ Slot handles expose live slot reads and convenience actions:
513
+
514
+ ```ts
515
+ interface InventorySlotHandle {
516
+ index: number;
517
+ kind: "hotbar" | "equipment" | null;
518
+ equipmentSlot: "head" | "face" | "body" | "back" | "hands" | "feet" | null;
519
+ itemId: number | null;
520
+ itemName: string | null;
521
+ count: number;
522
+ empty: boolean;
523
+ exists(): boolean;
524
+ snapshot(): InventorySlotSnapshot | null;
525
+ moveTo(target: InventorySlotRef, options?: { split?: boolean }, command?: Command): DredlessClient;
526
+ equip(equipmentSlot?: EquipmentSlot | { split?: boolean }, options?: { split?: boolean } | Command, command?: Command): DredlessClient;
527
+ unequip(target?: InventorySlotRef, options?: { split?: boolean }, command?: Command): DredlessClient;
528
+ select(command?: Command): DredlessClient;
529
+ }
530
+ ```
531
+
532
+ Inventory state is normalized and does not expose raw `items`, `item_counts`, or `general_slots` arrays. `hotbarSize` is the protocol-provided hotbar slot count from `general_slots`; equipment slots are separate fixed absolute indexes (`16`, `17`, `18`, `19`, `20`, `21`). `equip()` may omit the equipment slot; in that case it infers the target from the item schema and throws if the source slot is empty or the item is not equipment.
533
+
534
+ ```ts
535
+ interface InventorySlotSnapshot {
536
+ index: number;
537
+ itemId: number | null;
538
+ itemName: string | null;
539
+ count: number;
540
+ kind: "hotbar" | "equipment";
541
+ equipmentSlot: "head" | "face" | "body" | "back" | "hands" | "feet" | null;
542
+ empty: boolean;
543
+ }
544
+
545
+ interface InventoryState {
546
+ type: "inventory";
547
+ filter?: number;
548
+ hotbarSize: number;
549
+ slots: InventorySlotSnapshot[];
550
+ hotbar: InventorySlotSnapshot[];
551
+ equipment: {
552
+ head: InventorySlotSnapshot;
553
+ face: InventorySlotSnapshot;
554
+ body: InventorySlotSnapshot;
555
+ back: InventorySlotSnapshot;
556
+ hands: InventorySlotSnapshot;
557
+ feet: InventorySlotSnapshot;
558
+ };
559
+ }
560
+ ```
561
+ ### `client.management`
562
+
563
+ Ship-management command and state domain.
564
+
565
+ ```ts
566
+ interface ShipManagementDomain {
567
+ requestPlayerList(): DredlessClient;
568
+ resetInvite(): DredlessClient;
569
+ setPrivacy(privacy: ShipPrivacy): DredlessClient;
570
+ recoverStarterItem(itemId: number): DredlessClient;
571
+ setPlayerRank(refId: number, rank: ShipPlayerRank): DredlessClient;
572
+ kickPlayer(refId: number): DredlessClient;
573
+ banPlayer(refId: number): DredlessClient;
574
+ demoteSelf(): DredlessClient;
575
+ config(): ShipConfig | null;
576
+ hasCheats(): boolean;
577
+ playerList(): ShipPlayerList | null;
578
+ }
579
+ ```
580
+
581
+ Input aliases:
582
+
583
+ ```ts
584
+ type ShipPrivacy = 0 | 1 | boolean | "public" | "private";
585
+ type ShipPlayerRank = 0 | 1 | 3 | "guest" | "crew" | "captain";
586
+ type PlayerShipRank = "guest" | "crew" | "crew-invite-pending-deprecated" | "captain" | "banned";
587
+ ```
588
+
589
+ Output shapes:
590
+
591
+ ```ts
592
+ interface ShipConfig {
593
+ privacy: number | null;
594
+ privacyName: "public" | "private" | null;
595
+ inviteKey: string | null;
596
+ teamId: number | null;
597
+ patronPerks: unknown[];
598
+ }
599
+
600
+ interface CaptainSubrank {
601
+ subrank: number | null;
602
+ enableCheats: boolean;
603
+ }
604
+
605
+ interface CurrentPlayerRank {
606
+ shipRank: PlayerShipRank | null;
607
+ subrank: number | null;
608
+ isCaptain: boolean;
609
+ patronTier: "bronze" | "silver" | "gold" | "plat" | "flux" | null;
610
+ }
611
+
612
+ interface PlayerListEntry {
613
+ refId: number | null;
614
+ discrim: string | null;
615
+ discrimColor: number | null;
616
+ teamRank: number | null;
617
+ captainRank: number | null;
618
+ isCaptain: boolean;
619
+ isShipOwner: boolean;
620
+ canBeManaged: boolean;
621
+ time: number | null;
622
+ items: unknown[];
623
+ aliasDiscrims: unknown[];
624
+ extraAliasCount: number;
625
+ onlineCount: number | null;
626
+ }
627
+
628
+ interface ShipPlayerList {
629
+ ownerCaptainRank: number | null;
630
+ shipOwners: PlayerListEntry[];
631
+ players: PlayerListEntry[];
632
+ changes: PlayerListEntry[];
633
+ removedPlayers: number[];
634
+ }
635
+ ```
636
+
637
+ ## World Domains
638
+
639
+ ### `WorldDomain`
640
+
641
+ Available from `client.currentShip()`, `client.overworld()`, and
642
+ `client.world(id)`.
643
+
644
+ ```ts
645
+ interface WorldDomain {
646
+ id: number | null;
647
+ entities: EntityCollection;
648
+ machines: MachineCollection;
649
+ players: PlayerCollection;
650
+ blocks: BlockCollection;
651
+ materials: MaterialCollection;
652
+ exists(): boolean;
653
+ snapshot(options?: { includeTiles?: boolean; includeModel?: boolean }): WorldSnapshot | null;
654
+ }
655
+ ```
656
+
657
+ ### `ShipDomain`
658
+
659
+ ```ts
660
+ interface ShipDomain extends WorldDomain {
661
+ metadata: ShipWorldMetadataSummary | null;
662
+ entity(): EntityHandle | null;
663
+ overworldEntity: EntityHandle | null;
664
+ }
665
+ ```
666
+
667
+ `entity()` returns the current ship's overworld entity handle, not a ship-world
668
+ placed entity.
669
+
670
+ ### `OverworldDomain`
671
+
672
+ ```ts
673
+ interface OverworldDomain extends WorldDomain {
674
+ ships(options?: ShipReadOptions): ShipHandle[];
675
+ shipByHex(hexCode: string, options?: ShipReadOptions): ShipHandle | null;
676
+ shipByEntity(entity: number | EntityHandle | EntitySummary, options?: ShipReadOptions): ShipHandle | null;
677
+ }
678
+ ```
679
+
680
+ Ship read options:
681
+
682
+ ```ts
683
+ interface ShipReadOptions {
684
+ includeWorld?: boolean;
685
+ includeTiles?: boolean;
686
+ includeModel?: boolean;
687
+ sort?: "distance" | null;
688
+ }
689
+ ```
690
+
691
+ ## Entity API
692
+
693
+ Entity ids are scoped to their world. Overworld entities and ship-world entities
694
+ do not share one global id pool.
695
+
696
+ ### `EntityCollection`
697
+
698
+ ```ts
699
+ interface EntityCollection {
700
+ all(): EntityHandle[];
701
+ snapshots(): EntitySnapshot[];
702
+ states(): EntitySnapshot[];
703
+ raw(): EntitySummary[];
704
+ get(entity: number | EntityHandle | EntitySummary): EntityHandle;
705
+ }
706
+ ```
707
+
708
+ Use:
709
+
710
+ ```js
711
+ const shipEntity = client.currentShip().entities.get(14);
712
+ const overworldEntity = client.overworld().entities.get(2495754);
713
+ ```
714
+
715
+ Costs:
716
+
717
+ ```txt
718
+ all() -> creates lightweight handles
719
+ raw() -> returns current summary objects
720
+ snapshots() -> clones and freezes summaries
721
+ states() -> alias of snapshots()
722
+ get(id) -> creates one lightweight handle
723
+ ```
724
+
725
+ ### `EntityHandle`
726
+
727
+ ```ts
728
+ interface EntityHandle {
729
+ /** @deprecated Use id. */
730
+ entity: number;
731
+ id: number;
732
+ position: TransformSummary | null;
733
+ health: HealthSummary | null;
734
+ contents: EntityContentsSummary | null;
735
+ exists(): boolean;
736
+ snapshot(): EntitySnapshot | null;
737
+ is(type: EntityTypeName): boolean;
738
+ has(feature: EntityFeatureName): boolean;
739
+ feature(feature: EntityFeatureName): unknown | null;
740
+ as(type: EntityTypeName): MachineHandle | null;
741
+ asLoader(): LoaderHandle | null;
742
+ asPusher(): PusherHandle | null;
743
+ asLauncher(): LauncherHandle | null;
744
+ asNavigationUnit(): NavigationUnitHandle | null;
745
+ asCommsStation(): CommsStationHandle | null;
746
+ asSign(): SignHandle | null;
747
+ asGenerator(): GeneratorHandle | null;
748
+ asCargoHatch(): CargoHatchHandle | null;
749
+ asCannon(): CannonHandle | null;
750
+ asThruster(): ThrusterHandle | null;
751
+ asHelm(): HelmHandle | null;
752
+ asDoor(): DoorHandle | null;
753
+ asSpawnPoint(): SpawnPointHandle | null;
754
+ asShieldProjector(): ShieldProjectorHandle | null;
755
+ asFluidTank(): FluidTankHandle | null;
756
+ asCargoEjector(): CargoEjectorHandle | null;
757
+ asExpandoBox(): ExpandoBoxHandle | null;
758
+ use(options?: { invSlot?: number; hold?: boolean }, command?: Command): DredlessClient;
759
+ }
760
+ ```
761
+
762
+ ### `EntitySnapshot`
763
+
764
+ Frozen point-in-time entity read.
765
+
766
+ ```ts
767
+ interface EntitySnapshot extends EntitySummary {
768
+ id: number;
769
+ position: TransformSummary | null;
770
+ rotation: number | null;
771
+ type: EntitySnapshotType;
772
+ is(type: EntityTypeName): boolean;
773
+ has(feature: EntityFeatureName): boolean;
774
+ feature(feature: EntityFeatureName): unknown | null;
775
+ }
776
+
777
+ interface EntitySnapshotType {
778
+ category: EntitySummary["category"] | null;
779
+ machine: string | null;
780
+ item: string | null;
781
+ components: string[];
782
+ }
783
+ ```
784
+
785
+ ### `EntitySummary`
786
+
787
+ Raw normalized entity shape.
788
+
789
+ ```ts
790
+ interface EntitySummary {
791
+ entity: number;
792
+ category:
793
+ | "placed_entity"
794
+ | "loose_item"
795
+ | "untyped_holder"
796
+ | "metadata"
797
+ | "player"
798
+ | "ship_control"
799
+ | "blueprint_preview"
800
+ | "entity";
801
+ typeId: number | null;
802
+ typeName: string | null;
803
+ markerTypeId: number | null;
804
+ markerTypeName: string | null;
805
+ label: string;
806
+ kind: string[];
807
+ transform: TransformSummary | null;
808
+ footprint: {
809
+ width: number;
810
+ height: number;
811
+ source:
812
+ | "type"
813
+ | "marker"
814
+ | "heuristic"
815
+ | "default"
816
+ | "crate"
817
+ | "huge_thruster"
818
+ | "hover_outline";
819
+ };
820
+ contents: EntityContentsSummary | null;
821
+ occupies: { x: number; y: number }[];
822
+ tables: { tableId: number; name: string | null; record: ModelRecord }[];
823
+ }
824
+ ```
825
+
826
+ ### `EntityContentsSummary`
827
+
828
+ Feature/component container for an entity.
829
+
830
+ ```ts
831
+ interface EntityContentsSummary {
832
+ itemHolder?: ItemHolderSummary;
833
+ expandoBox?: ExpandoBoxSummary;
834
+ hoverOutline?: HoverOutlineSummary;
835
+ mapMarker?: MapMarkerSummary;
836
+ dockingSpring?: DockingSpringSummary;
837
+ hugeThruster?: HugeThrusterSummary;
838
+ blueprintPreview?: BlueprintPreviewSummary;
839
+ itemCrate?: ItemCrateSummary;
840
+ health?: HealthSummary;
841
+ bot?: BotSummary;
842
+ fabricator?: FabricatorSummary;
843
+ cargoEjector?: CargoEjectorSummary;
844
+ cannon?: CannonSummary;
845
+ thruster?: ThrusterSummary;
846
+ pusher?: PusherSummary;
847
+ pusherBeam?: PusherBeamSummary;
848
+ launcher?: LauncherSummary;
849
+ loader?: LoaderSummary;
850
+ cargoHatch?: CargoHatchSummary;
851
+ navigationUnit?: NavigationUnitSummary;
852
+ commsStation?: CommsStationSummary;
853
+ fluidTank?: FluidTankSummary;
854
+ shieldGenerator?: ShieldGeneratorSummary;
855
+ shieldProjector?: ShieldProjectorSummary;
856
+ helm?: HelmSummary;
857
+ player?: PlayerSummary;
858
+ shipControl?: ShipControlSummary;
859
+ sign?: SignSummary;
860
+ spawnPoint?: SpawnPointSummary;
861
+ door?: DoorSummary;
862
+ shipSize?: ShipSizeSummary;
863
+ }
864
+ ```
865
+
866
+ Feature lookup accepts the canonical component names above and selected aliases
867
+ such as `outline`, `beam`, `inventory`, `filter`, `filterMode`, `filterSlots`,
868
+ `occupied`, `mapMarker`, and `blueprint`.
869
+
870
+ ## Machine API
871
+
872
+ ### `MachineCollection`
873
+
874
+ ```ts
875
+ interface MachineCollection {
876
+ state(): MachineSummary;
877
+ raw(): MachineSummary;
878
+ loaders(): LoaderHandle[];
879
+ loader(entity: number | EntityHandle | EntitySummary): LoaderHandle;
880
+ pushers(): PusherHandle[];
881
+ pusher(entity: number | EntityHandle | EntitySummary): PusherHandle;
882
+ launchers(): LauncherHandle[];
883
+ launcher(entity: number | EntityHandle | EntitySummary): LauncherHandle;
884
+ navigationUnits(): NavigationUnitHandle[];
885
+ navigationUnit(entity?: number | EntityHandle | EntitySummary | null): NavigationUnitHandle | null;
886
+ fabricators(): FabricatorHandle[];
887
+ fabricator(entity: number | EntityHandle | EntitySummary): FabricatorHandle;
888
+ commsStations(): CommsStationHandle[];
889
+ commsStation(entity?: number | EntityHandle | EntitySummary | null): CommsStationHandle | null;
890
+ signs(): SignHandle[];
891
+ sign(entity: number | EntityHandle | EntitySummary): SignHandle;
892
+ generators(): GeneratorHandle[];
893
+ generator(entity: number | EntityHandle | EntitySummary): GeneratorHandle;
894
+ cargoHatches(): CargoHatchHandle[];
895
+ cargoHatch(entity: number | EntityHandle | EntitySummary): CargoHatchHandle;
896
+ cargoEjectors(): CargoEjectorHandle[];
897
+ cargoEjector(entity: number | EntityHandle | EntitySummary): CargoEjectorHandle;
898
+ cannons(): CannonHandle[];
899
+ cannon(entity: number | EntityHandle | EntitySummary): CannonHandle;
900
+ thrusters(): ThrusterHandle[];
901
+ thruster(entity: number | EntityHandle | EntitySummary): ThrusterHandle;
902
+ helms(): HelmHandle[];
903
+ helm(entity: number | EntityHandle | EntitySummary): HelmHandle;
904
+ doors(): DoorHandle[];
905
+ door(entity: number | EntityHandle | EntitySummary): DoorHandle;
906
+ spawnPoints(): SpawnPointHandle[];
907
+ spawnPoint(entity: number | EntityHandle | EntitySummary): SpawnPointHandle;
908
+ shieldProjectors(): ShieldProjectorHandle[];
909
+ shieldProjector(entity: number | EntityHandle | EntitySummary): ShieldProjectorHandle;
910
+ fluidTanks(): FluidTankHandle[];
911
+ fluidTank(entity: number | EntityHandle | EntitySummary): FluidTankHandle;
912
+ expandoBoxes(): ExpandoBoxHandle[];
913
+ expandoBox(entity: number | EntityHandle | EntitySummary): ExpandoBoxHandle;
914
+ }
915
+ ```
916
+
917
+ ### `MachineSummary`
918
+
919
+ Grouped machine/component state.
920
+
921
+ ```ts
922
+ interface MachineSummary {
923
+ itemHolders: ItemHolderSummary[];
924
+ health: HealthSummary[];
925
+ fabricators: FabricatorSummary[];
926
+ cargoEjectors: CargoEjectorSummary[];
927
+ cannons: CannonSummary[];
928
+ thrusters: ThrusterSummary[];
929
+ pushers: PusherSummary[];
930
+ pusherBeams: PusherBeamSummary[];
931
+ launchers: LauncherSummary[];
932
+ loaders: LoaderSummary[];
933
+ cargoHatches: CargoHatchSummary[];
934
+ navigationUnits: NavigationUnitSummary[];
935
+ commsStations: CommsStationSummary[];
936
+ fluidTanks: FluidTankSummary[];
937
+ shieldGenerators: ShieldGeneratorSummary[];
938
+ shieldProjectors: ShieldProjectorSummary[];
939
+ helms: HelmSummary[];
940
+ signs: SignSummary[];
941
+ spawnPoints: SpawnPointSummary[];
942
+ doors: DoorSummary[];
943
+ expandoBoxes: ExpandoBoxSummary[];
944
+ }
945
+ ```
946
+
947
+ ### Common machine handle
948
+
949
+ ```ts
950
+ interface MachineHandle extends EntityHandle {
951
+ open(options?: { invSlot?: number; hold?: boolean }, command?: Command): DredlessClient;
952
+ }
953
+ ```
954
+
955
+ `open()` focuses/uses the entity through the player command path.
956
+
957
+ ### `LoaderHandle`
958
+
959
+ ```ts
960
+ interface LoaderHandle extends MachineHandle {
961
+ state: LoaderSummary | null;
962
+ configure(config?: LoaderConfig): DredlessClient;
963
+ configureFull(config?: LoaderFullConfig): DredlessClient;
964
+ copy(config?: LoaderFullConfig): DredlessClient;
965
+ setPickPlace(pick: LoaderPosition, place: LoaderPosition, config?: LoaderConfig): DredlessClient;
966
+ setPriority(priority: LoaderPriority, config?: LoaderConfig): DredlessClient;
967
+ setStack(stack: number, config?: LoaderConfig): DredlessClient;
968
+ setCycle(cycle: number, config?: LoaderConfig): DredlessClient;
969
+ setRequireOutput(requireOutput: boolean, config?: LoaderConfig): DredlessClient;
970
+ setWaitForStack(waitForStack: boolean, config?: LoaderConfig): DredlessClient;
971
+ setFilterMode(filterMode: LoaderFilterMode): DredlessClient;
972
+ setFilterItems(filterSlots?: Array<number | null | undefined>): DredlessClient;
973
+ pick: number | undefined;
974
+ place: number | undefined;
975
+ priority: number | undefined;
976
+ stack: number | undefined;
977
+ cycle: number | undefined;
978
+ requireOutput: boolean | undefined;
979
+ waitForStack: boolean | undefined;
980
+ filterMode: number | undefined;
981
+ filterSlots: Array<number | null>;
982
+ }
983
+ ```
984
+
985
+ Config inputs:
986
+
987
+ ```ts
988
+ const LoaderPosition = { TopLeft: "top-left", TopMiddle: "top-middle", TopRight: "top-right", MiddleLeft: "middle-left", MiddleRight: "middle-right", BottomLeft: "bottom-left", BottomMiddle: "bottom-middle", BottomRight: "bottom-right" } as const;
989
+ type LoaderPosition = typeof LoaderPosition[keyof typeof LoaderPosition];
990
+
991
+ const LoaderPriority = { Low: "low", Normal: "normal", High: "high" } as const;
992
+ type LoaderPriority = typeof LoaderPriority[keyof typeof LoaderPriority];
993
+
994
+ const LoaderFilterMode = { AllowAll: "allow-all", BlockFilter: "block-filter", AllowFilter: "allow-filter", BlockAll: "block-all" } as const;
995
+ type LoaderFilterMode = typeof LoaderFilterMode[keyof typeof LoaderFilterMode];
996
+
997
+ interface LoaderConfig {
998
+ pick?: LoaderPosition;
999
+ place?: LoaderPosition;
1000
+ priority?: LoaderPriority;
1001
+ stack?: number;
1002
+ cycle?: number;
1003
+ requireOutput?: boolean;
1004
+ waitForStack?: boolean;
1005
+ }
1006
+
1007
+ interface LoaderFullConfig extends LoaderConfig {
1008
+ filterMode?: LoaderFilterMode;
1009
+ filterSlots?: Array<number | null | undefined>;
1010
+ }
1011
+ ```
1012
+
1013
+ State output:
1014
+
1015
+ ```ts
1016
+ interface LoaderSummary {
1017
+ entity: number;
1018
+ pick: number | null;
1019
+ pickName: string | null;
1020
+ place: number | null;
1021
+ placeName: string | null;
1022
+ priority: number | null;
1023
+ priorityName: string | null;
1024
+ requireOutput: boolean | null;
1025
+ waitForStack: boolean | null;
1026
+ stack: number | null;
1027
+ cycle: number | null;
1028
+ filterMode: number | null;
1029
+ filterModeName: string | null;
1030
+ filterSlots: (number | null)[] | null;
1031
+ heldItemId: number | null;
1032
+ heldItemName: string | null;
1033
+ heldCount: number | null;
1034
+ active: boolean;
1035
+ progress: number | null;
1036
+ state: ModelRecord;
1037
+ filterState: ModelRecord;
1038
+ filterSlotsState: ModelRecord;
1039
+ }
1040
+ ```
1041
+
1042
+ ### `PusherHandle`
1043
+
1044
+ ```ts
1045
+ interface PusherHandle extends MachineHandle {
1046
+ state: PusherSummary | null;
1047
+ beam: PusherBeamSummary | null;
1048
+ configure(config?: PusherConfig): DredlessClient;
1049
+ setAngle(angle: number, config?: PusherConfig): DredlessClient;
1050
+ setSpeed(speed: number, config?: PusherConfig): DredlessClient;
1051
+ setLength(length: number, config?: PusherConfig): DredlessClient;
1052
+ setMode(mode: PusherMode, config?: PusherConfig): DredlessClient;
1053
+ setFilteredMode(mode: PusherMode, config?: PusherConfig): DredlessClient;
1054
+ setFilterInventory(filterInventory: boolean, config?: PusherConfig): DredlessClient;
1055
+ setFilterItems(filterSlots?: Array<number | null | undefined>): DredlessClient;
1056
+ angle: number | undefined;
1057
+ speed: number | undefined;
1058
+ length: number | undefined;
1059
+ mode: number | undefined;
1060
+ filteredMode: number | undefined;
1061
+ }
1062
+ ```
1063
+
1064
+ Config input:
1065
+
1066
+ ```ts
1067
+ const PusherMode = { Push: "push", Pull: "pull", DoNothing: "do-nothing" } as const;
1068
+ type PusherMode = typeof PusherMode[keyof typeof PusherMode];
1069
+
1070
+ interface PusherConfig {
1071
+ mode?: PusherMode;
1072
+ filteredMode?: PusherMode;
1073
+ angle?: number;
1074
+ speed?: number;
1075
+ filterInventory?: boolean;
1076
+ length?: number;
1077
+ }
1078
+ ```
1079
+
1080
+ State output:
1081
+
1082
+ ```ts
1083
+ interface PusherSummary {
1084
+ entity: number;
1085
+ mode: number;
1086
+ modeName: string | null;
1087
+ filteredMode: number;
1088
+ filteredModeName: string | null;
1089
+ angle: number | null;
1090
+ speed: number;
1091
+ length: number;
1092
+ filterInventory: boolean;
1093
+ filterSlots: (number | null)[] | null;
1094
+ state: ModelRecord;
1095
+ filterSlotsState: ModelRecord;
1096
+ }
1097
+
1098
+ interface PusherBeamSummary {
1099
+ entity: number;
1100
+ active: boolean;
1101
+ mode: number;
1102
+ modeName: string | null;
1103
+ lengthRaw: number;
1104
+ length: number;
1105
+ state: ModelRecord;
1106
+ }
1107
+ ```
1108
+
1109
+ Pusher beams are associated with the same entity as their parent pusher, exposed
1110
+ as `pusher.beam`, `entity.feature("beam")`, and `machines.state().pusherBeams`.
1111
+
1112
+ ### `LauncherHandle`
1113
+
1114
+ ```ts
1115
+ interface LauncherHandle extends MachineHandle {
1116
+ state: LauncherSummary | null;
1117
+ setAngle(angle: number): DredlessClient;
1118
+ setPower(power: number): DredlessClient;
1119
+ angleDegrees: number | undefined;
1120
+ angleRadians: number | undefined;
1121
+ angleRaw: number | null | undefined;
1122
+ }
1123
+
1124
+ interface LauncherSummary {
1125
+ entity: number;
1126
+ angleRaw: number | null;
1127
+ angleRadians: number | null;
1128
+ angleDegrees: number | null;
1129
+ state: ModelRecord;
1130
+ }
1131
+ ```
1132
+
1133
+ Launcher power may not be present until the relevant UI has exposed it.
1134
+
1135
+ ### `NavigationUnitHandle`
1136
+
1137
+ ```ts
1138
+ interface NavigationUnitHandle extends MachineHandle {
1139
+ state: NavigationUnitSummary | null;
1140
+ configure(config?: NavigationUnitConfig): DredlessClient;
1141
+ copy(config?: NavigationUnitConfig): DredlessClient;
1142
+ paste(config?: NavigationUnitConfig): DredlessClient;
1143
+ setDestination(destination: number, config?: NavigationUnitConfig): DredlessClient;
1144
+ setAutoWarp(config?: NavigationUnitConfig): DredlessClient;
1145
+ startWarp(config?: NavigationUnitConfig): DredlessClient;
1146
+ cancelWarp(config?: NavigationUnitConfig): DredlessClient;
1147
+ destination: number | undefined;
1148
+ autoWarpOnShieldFailure: boolean | undefined;
1149
+ autoWarpOnNoCaptains: boolean | undefined;
1150
+ warp: string | undefined;
1151
+ }
1152
+ ```
1153
+
1154
+ Config and state:
1155
+
1156
+ ```ts
1157
+ interface NavigationUnitConfig {
1158
+ destination?: number;
1159
+ page?: number;
1160
+ warp?: boolean | "start" | "idle" | "cancel";
1161
+ autoWarpOnShieldFailure?: boolean;
1162
+ autoWarpOnNoCaptains?: boolean;
1163
+ }
1164
+
1165
+ interface NavigationUnitSummary {
1166
+ entity: number;
1167
+ destination: number;
1168
+ destinationName: string | null;
1169
+ autoWarpOnShieldFailure: boolean | null;
1170
+ autoWarpOnNoCaptains: boolean | null;
1171
+ state: ModelRecord;
1172
+ }
1173
+ ```
1174
+
1175
+ ### `FabricatorHandle`
1176
+
1177
+ ```ts
1178
+ interface FabricatorHandle extends MachineHandle {
1179
+ state: FabricatorSummary | null;
1180
+ panel(): PuiEvent | null;
1181
+ add(itemId: number, count?: number, index?: number): DredlessClient;
1182
+ sub(itemId: number, count?: number, index?: number): DredlessClient;
1183
+ clearQueue(): DredlessClient;
1184
+ toggleRepeat(): DredlessClient;
1185
+ lockResource(row: number): DredlessClient;
1186
+ unlockResource(row: number): DredlessClient;
1187
+ eject(row: number): DredlessClient;
1188
+ }
1189
+
1190
+ const FabricatorType = { Starter: "starter", Munitions: "munitions", Engineering: "engineering", Equipment: "equipment" } as const;
1191
+ type FabricatorType = typeof FabricatorType[keyof typeof FabricatorType];
1192
+
1193
+ interface FabricatorSummary {
1194
+ entity: number;
1195
+ type: FabricatorType | null;
1196
+ typeIndex: number | null;
1197
+ state: ModelRecord;
1198
+ rows: { itemId: number | null; itemName: string | null; count: number | null }[];
1199
+ progress: number | null;
1200
+ progressRaw: number | null;
1201
+ active: boolean;
1202
+ craftingItemId: number | null;
1203
+ craftingItemName: string | null;
1204
+ craftingCount: number | null;
1205
+ }
1206
+ ```
1207
+
1208
+ ### `CommsStationHandle`
1209
+
1210
+ ```ts
1211
+ interface CommsStationHandle extends MachineHandle {
1212
+ state: CommsStationSummary | null;
1213
+ panel(): CommsEvent | null;
1214
+ sendMessage(message?: string): DredlessClient;
1215
+ }
1216
+
1217
+ interface CommsStationSummary {
1218
+ entity: number;
1219
+ typeId: number;
1220
+ typeName: string | null;
1221
+ charges: number | null;
1222
+ maxCharges: number;
1223
+ chargeRatio: number | null;
1224
+ occupied: boolean;
1225
+ state: ModelRecord;
1226
+ }
1227
+ ```
1228
+
1229
+ ### `SignHandle`
1230
+
1231
+ ```ts
1232
+ interface SignHandle extends MachineHandle {
1233
+ state: SignSummary | null;
1234
+ setText(text?: string, mode?: SignDisplayMode): DredlessClient;
1235
+ text: string | undefined;
1236
+ mode: number | undefined;
1237
+ }
1238
+
1239
+ const SignDisplayMode = { Always: "always", WhenNear: "when-near", OnHover: "on-hover" } as const;
1240
+ type SignDisplayMode = typeof SignDisplayMode[keyof typeof SignDisplayMode];
1241
+
1242
+ interface SignSummary {
1243
+ entity: number;
1244
+ text: string;
1245
+ displayMode: number;
1246
+ displayModeName: string | null;
1247
+ state: ModelRecord;
1248
+ }
1249
+ ```
1250
+
1251
+ ### `GeneratorHandle`
1252
+
1253
+ ```ts
1254
+ interface GeneratorHandle extends MachineHandle {
1255
+ state: ShieldGeneratorSummary | null;
1256
+ solvePuzzle(solution: string | number): DredlessClient;
1257
+ }
1258
+
1259
+ interface ShieldGeneratorSummary {
1260
+ entity: number;
1261
+ charge: number;
1262
+ maxCharge: number;
1263
+ chargeRatio: number | null;
1264
+ efficiencyPercent: number | null;
1265
+ efficiency: number | null;
1266
+ storedItemId: number | null;
1267
+ storedItemName: string | null;
1268
+ storedItemCount: number | null;
1269
+ hasShieldCore: boolean;
1270
+ boostState: number;
1271
+ boostStateName: string | null;
1272
+ boostTimer: number;
1273
+ boostActive: boolean;
1274
+ puzzleSeed: number | null;
1275
+ puzzleSolution: string | null;
1276
+ state: ModelRecord;
1277
+ itemState: ModelRecord;
1278
+ boostStateRaw: ModelRecord;
1279
+ }
1280
+ ```
1281
+
1282
+ ### `CargoHatchHandle`
1283
+
1284
+ ```ts
1285
+ interface CargoHatchHandle extends MachineHandle {
1286
+ state: CargoHatchSummary | null;
1287
+ configure(config?: Pick<LoaderFullConfig, "filterMode" | "filterSlots">): DredlessClient;
1288
+ copy(config?: Pick<LoaderFullConfig, "filterMode" | "filterSlots">): DredlessClient;
1289
+ paste(config?: Pick<LoaderFullConfig, "filterMode" | "filterSlots">): DredlessClient;
1290
+ setFilterMode(filterMode: LoaderFilterMode): DredlessClient;
1291
+ setFilterItems(filterSlots?: Array<number | null | undefined>): DredlessClient;
1292
+ }
1293
+
1294
+ interface CargoHatchSummary {
1295
+ entity: number;
1296
+ typeId: number;
1297
+ typeName: string | null;
1298
+ filterMode: number;
1299
+ filterModeName: string | null;
1300
+ filterSlots: (number | null)[] | null;
1301
+ openFraction: number | null;
1302
+ filterState: ModelRecord;
1303
+ filterSlotsState: ModelRecord;
1304
+ }
1305
+ ```
1306
+
1307
+ ### Other machine handles
1308
+
1309
+ ```ts
1310
+ interface CannonHandle extends MachineHandle {
1311
+ state: CannonSummary | null;
1312
+ }
1313
+
1314
+ interface ThrusterHandle extends MachineHandle {
1315
+ state: ThrusterSummary | null;
1316
+ }
1317
+
1318
+ interface HelmHandle extends MachineHandle {
1319
+ state: HelmSummary | null;
1320
+ occupied: boolean | undefined;
1321
+ }
1322
+
1323
+ interface DoorHandle extends MachineHandle {
1324
+ state: DoorSummary | null;
1325
+ rank: number | undefined;
1326
+ open: boolean | undefined;
1327
+ }
1328
+
1329
+ interface SpawnPointHandle extends MachineHandle {
1330
+ state: SpawnPointSummary | null;
1331
+ rank: number | undefined;
1332
+ }
1333
+
1334
+ interface ShieldProjectorHandle extends MachineHandle {
1335
+ state: ShieldProjectorSummary | null;
1336
+ active: boolean | undefined;
1337
+ }
1338
+
1339
+ interface FluidTankHandle extends MachineHandle {
1340
+ state: FluidTankSummary | null;
1341
+ amount: number | null | undefined;
1342
+ }
1343
+
1344
+ interface ExpandoBoxHandle extends MachineHandle {
1345
+ state: ExpandoBoxSummary | null;
1346
+ item: number | null | undefined;
1347
+ count: number | null | undefined;
1348
+ }
1349
+
1350
+ interface CargoEjectorSummary {
1351
+ entity: number;
1352
+ typeId: number;
1353
+ typeName: string | null;
1354
+ progress: number | null;
1355
+ active: boolean | null;
1356
+ }
1357
+
1358
+ interface CargoEjectorHandle extends MachineHandle {
1359
+ state: CargoEjectorSummary | null;
1360
+ progress: number | null | undefined;
1361
+ active: boolean | null | undefined;
1362
+ setDirection(direction: FixedAngleDirection): DredlessClient;
1363
+ copy(direction?: FixedAngleDirection): DredlessClient;
1364
+ paste(direction?: FixedAngleDirection): DredlessClient;
1365
+ }
1366
+ ```
1367
+
1368
+ Associated summary shapes:
1369
+
1370
+ ```ts
1371
+ interface CannonSummary {
1372
+ entity: number;
1373
+ typeId: number;
1374
+ typeName: string | null;
1375
+ ammoItemId: number | null;
1376
+ ammoName: string | null;
1377
+ ammoCount: number;
1378
+ aim: number | null;
1379
+ recoil: number | null;
1380
+ recoil2: number | null;
1381
+ recoils: [number | null, number | null];
1382
+ charge: number | null;
1383
+ charged: boolean | null;
1384
+ spin: number | null;
1385
+ coolingCellCount: number;
1386
+ state: ModelRecord;
1387
+ }
1388
+
1389
+ interface ThrusterSummary {
1390
+ entity: number;
1391
+ typeId: number;
1392
+ typeName: string | null;
1393
+ facing: number;
1394
+ facingName:
1395
+ | "bottom"
1396
+ | "top"
1397
+ | "right"
1398
+ | "left"
1399
+ | "bottom-right"
1400
+ | "bottom-left"
1401
+ | "top-right"
1402
+ | "top-left"
1403
+ | null;
1404
+ fuel: number | null;
1405
+ state: ModelRecord;
1406
+ }
1407
+
1408
+ interface HelmSummary {
1409
+ entity: number;
1410
+ typeId: number;
1411
+ typeName: string | null;
1412
+ occupied: boolean;
1413
+ }
1414
+
1415
+ interface DoorSummary {
1416
+ entity: number;
1417
+ rank: number;
1418
+ rankName: string | null;
1419
+ open: boolean;
1420
+ rankState: ModelRecord;
1421
+ state: ModelRecord;
1422
+ }
1423
+
1424
+ interface SpawnPointSummary {
1425
+ entity: number;
1426
+ rank: number;
1427
+ rankName: string | null;
1428
+ state: ModelRecord;
1429
+ }
1430
+
1431
+ interface ShieldProjectorSummary {
1432
+ entity: number;
1433
+ active: boolean;
1434
+ state: ModelRecord;
1435
+ }
1436
+
1437
+ interface FluidTankSummary {
1438
+ entity: number;
1439
+ amount: number | null;
1440
+ state: ModelRecord;
1441
+ }
1442
+
1443
+ interface ExpandoBoxSummary {
1444
+ entity: number;
1445
+ itemId: number | null;
1446
+ itemName: string | null;
1447
+ count: number | null;
1448
+ width: number | null;
1449
+ height: number | null;
1450
+ rawWidth: number | null;
1451
+ rawHeight: number | null;
1452
+ itemState: ModelRecord;
1453
+ sizeState: ModelRecord;
1454
+ }
1455
+ ```
1456
+
1457
+ ## Ship Reads
1458
+
1459
+ ### `ShipHandle`
1460
+
1461
+ Returned by `client.overworld()?.ships()`.
1462
+
1463
+ ```ts
1464
+ interface ShipHandle {
1465
+ entity: number;
1466
+ name: string | null;
1467
+ hexCode: string | null;
1468
+ distance: number | null;
1469
+ worldId: number | null;
1470
+ hasWorldData: boolean;
1471
+ world(): WorldDomain | null;
1472
+ snapshot(): ShipReadSummary;
1473
+ }
1474
+ ```
1475
+
1476
+ ### `ShipReadSummary`
1477
+
1478
+ ```ts
1479
+ interface ShipReadSummary {
1480
+ entity: number;
1481
+ name: string | null;
1482
+ hexCode: string | null;
1483
+ color: number | null;
1484
+ colorCss: string | null;
1485
+ position: { x: number | null; y: number | null; rot: number | null } | null;
1486
+ distance: number | null;
1487
+ footprint: EntitySummary["footprint"];
1488
+ label: string;
1489
+ kind: string[];
1490
+ thrust: { x: number | null; y: number | null };
1491
+ shield: ShipShieldSummary | null;
1492
+ warp: ShipWarpSummary | null;
1493
+ worldId: number | null;
1494
+ hasWorldData: boolean;
1495
+ world: WorldSnapshot | null;
1496
+ control: ShipControlSummary;
1497
+ entitySummary: EntitySummary;
1498
+ }
1499
+ ```
1500
+
1501
+ ### `ShipControlSummary`
1502
+
1503
+ ```ts
1504
+ interface ShipControlSummary {
1505
+ entity: number;
1506
+ name: string | null;
1507
+ hexCode: string | null;
1508
+ shipWorldId: number | null;
1509
+ color: number | null;
1510
+ colorCss: string | null;
1511
+ thrustX: number | null;
1512
+ thrustY: number | null;
1513
+ value52: number | null;
1514
+ value84: number | null;
1515
+ value96: number | null;
1516
+ shield: ShipShieldSummary | null;
1517
+ warp: ShipWarpSummary | null;
1518
+ state: ModelRecord;
1519
+ }
1520
+ ```
1521
+
1522
+ ### Ship shield and warp summaries
1523
+
1524
+ ```ts
1525
+ interface ShipShieldSummary {
1526
+ maxHp: number | null;
1527
+ baseHp: number | null;
1528
+ activeTankHp: number | null;
1529
+ inactiveTankHp: number | null;
1530
+ tankValues: number[];
1531
+ }
1532
+
1533
+ interface ShipWarpSummary {
1534
+ active: boolean;
1535
+ ticks: number;
1536
+ elapsedSeconds: number;
1537
+ durationSeconds: number;
1538
+ remainingSeconds: number;
1539
+ }
1540
+ ```
1541
+
1542
+ ## Player, Blocks, Materials
1543
+
1544
+ ```ts
1545
+ interface PlayerCollection {
1546
+ all(): PlayerSummary[];
1547
+ current(): PlayerSummary | null;
1548
+ }
1549
+
1550
+ interface BlockCollection {
1551
+ all(): BlockSummary[];
1552
+ at(x: number, y: number): BlockSummary | null;
1553
+ }
1554
+
1555
+ interface MaterialCollection {
1556
+ all(): MaterialSummary[];
1557
+ }
1558
+ ```
1559
+
1560
+ ### `PlayerSummary`
1561
+
1562
+ ```ts
1563
+ interface PlayerSummary {
1564
+ entity: number;
1565
+ name: string | null;
1566
+ heldItemId: number | null;
1567
+ heldItemName: string | null;
1568
+ repairTargetDistance: number | null;
1569
+ repairTargetAngle: number | null;
1570
+ shipRank: PlayerShipRank | null;
1571
+ patronTier: "bronze" | "silver" | "gold" | "plat" | "flux" | null;
1572
+ isDeveloper: boolean;
1573
+ isPatron: boolean;
1574
+ piloting: boolean;
1575
+ muted: boolean;
1576
+ actionPreview: PlayerActionPreviewSummary | null;
1577
+ state: ModelRecord;
1578
+ }
1579
+ ```
1580
+
1581
+ ### `PlayerActionPreviewSummary`
1582
+
1583
+ ```ts
1584
+ interface PlayerActionPreviewSummary {
1585
+ entity: number;
1586
+ active: boolean;
1587
+ x: number | null;
1588
+ y: number | null;
1589
+ width: number | null;
1590
+ height: number | null;
1591
+ progress: number | null;
1592
+ color: number | null;
1593
+ colorCss: string | null;
1594
+ actionName: "place" | "break" | "blueprint" | null;
1595
+ blueprintId: number | null;
1596
+ blueprintItems: BlueprintPreviewSummary[];
1597
+ state: ModelRecord;
1598
+ }
1599
+ ```
1600
+
1601
+ ### `BlockSummary`
1602
+
1603
+ ```ts
1604
+ interface BlockSummary {
1605
+ x: number;
1606
+ y: number;
1607
+ entities: EntitySummary[];
1608
+ }
1609
+ ```
1610
+
1611
+ ### `MaterialSummary`
1612
+
1613
+ ```ts
1614
+ interface MaterialSummary {
1615
+ material: number;
1616
+ name: string | null;
1617
+ count: number;
1618
+ solid: boolean | null;
1619
+ hp: number | null;
1620
+ }
1621
+ ```
1622
+
1623
+ ## World State Classes
1624
+
1625
+ These classes are public mostly for inspection, replay, testing, and lower-level
1626
+ tooling.
1627
+
1628
+ ### `WorldStore`
1629
+
1630
+ ```ts
1631
+ class WorldStore {
1632
+ currentWorldId: number | null;
1633
+ worlds: Map<number, WorldState>;
1634
+
1635
+ get(id: number): WorldState;
1636
+ apply(packet: unknown): WorldUpdate | null;
1637
+ snapshot(options?: { includeTiles?: boolean; includeModel?: boolean }): WorldSnapshot[];
1638
+ ids(): number[];
1639
+ overworld(): WorldState | null;
1640
+ shipWorld(): WorldState | null;
1641
+ currentShipEntity(): EntitySummary | null;
1642
+ }
1643
+ ```
1644
+
1645
+ ### `WorldState`
1646
+
1647
+ ```ts
1648
+ class WorldState {
1649
+ constructor(id: number);
1650
+
1651
+ id: number;
1652
+ seed: number | null;
1653
+ isOverworld: boolean | null;
1654
+ tileset: Tileset | null;
1655
+ blockWidth: number | null;
1656
+ blockHeight: number | null;
1657
+ parentWorld: number | null;
1658
+ parentEntity: number | null;
1659
+ tiles: Map<string, Tile>;
1660
+ chunks: unknown[];
1661
+ events: unknown[];
1662
+ modelPackets: unknown[];
1663
+ commsBubbles: CommsBubbleSummary[];
1664
+ model: ModelState;
1665
+ lastChunkPatch: unknown;
1666
+ lastPacket: unknown;
1667
+ meta: unknown;
1668
+
1669
+ readMeta(packet: unknown): void;
1670
+ addCommsBubble(packet: unknown): CommsBubbleSummary;
1671
+ decodeEncrypted(data: Uint8Array | ArrayBuffer | number[]): unknown;
1672
+ applyTile(value: unknown): Tile | null;
1673
+ applyChunk(value: unknown): Tile[] | null;
1674
+ setTile(tile: Tile): Tile;
1675
+ normalizeTile(tile: Tile): Tile;
1676
+ materials(): MaterialSummary[];
1677
+ snapshot(options?: { includeTiles?: boolean; includeModel?: boolean }): WorldSnapshot;
1678
+ table(id: number): Map<number, ModelRecord>;
1679
+ record(tableId: number, entityId: number): ModelRecord | null;
1680
+ tileDefinition(material: number): TileDefinition | null;
1681
+ entity(entityId: number): EntitySummary | null;
1682
+ entities(): EntitySummary[];
1683
+ blocks(): BlockSummary[];
1684
+ }
1685
+ ```
1686
+
1687
+ ### `ModelState`
1688
+
1689
+ ```ts
1690
+ class ModelState {
1691
+ generation: number | null;
1692
+ tables: Map<number, Map<number, ModelRecord>>;
1693
+ removedEntities: number[];
1694
+ lastUpdate: unknown;
1695
+ errors: unknown[];
1696
+
1697
+ table(id: number): Map<number, ModelRecord>;
1698
+ record(tableId: number, entityId: number): ModelRecord | null;
1699
+ entity(entityId: number): EntitySummary | null;
1700
+ entities(): EntitySummary[];
1701
+ blocks(): BlockSummary[];
1702
+ apply(bytes: Uint8Array | ArrayBuffer | number[]): unknown;
1703
+ snapshot(options?: { includeTables?: boolean }): ModelSnapshot;
1704
+ tablesSnapshot(): unknown[];
1705
+ transforms(): TransformSummary[];
1706
+ itemHolders(): ItemHolderSummary[];
1707
+ fabricators(): FabricatorSummary[];
1708
+ players(): PlayerSummary[];
1709
+ shipControls(): ShipControlSummary[];
1710
+ shipMetadata(): ShipWorldMetadataSummary | null;
1711
+ machines(): MachineSummary;
1712
+ }
1713
+
1714
+ type ModelRecord = Record<string, unknown>;
1715
+ ```
1716
+
1717
+ ### `WorldSnapshot`
1718
+
1719
+ ```ts
1720
+ interface WorldSnapshot {
1721
+ id: number;
1722
+ is_overworld: boolean | null;
1723
+ overworldZone: OverworldZoneSummary | null;
1724
+ shipMetadata: ShipWorldMetadataSummary | null;
1725
+ tileset: Tileset | null;
1726
+ seed: number | null;
1727
+ block_w: number | null;
1728
+ block_h: number | null;
1729
+ parent_world: number | null;
1730
+ parent_ent: number | null;
1731
+ tileCount: number;
1732
+ chunkCount: number;
1733
+ lastChunkPatch: unknown;
1734
+ lastPacket: unknown;
1735
+ meta: unknown;
1736
+ materials: MaterialSummary[];
1737
+ model: ModelSnapshot;
1738
+ entities: EntitySummary[];
1739
+ blocks: BlockSummary[];
1740
+ transforms: TransformSummary[];
1741
+ machines: MachineSummary;
1742
+ players: PlayerSummary[];
1743
+ shipControls: ShipControlSummary[];
1744
+ commsBubbles: CommsBubbleSummary[];
1745
+ tiles?: Tile[];
1746
+ }
1747
+ ```
1748
+
1749
+ ### World metadata
1750
+
1751
+ ```ts
1752
+ interface OverworldZoneSummary {
1753
+ id: number;
1754
+ baseId: number;
1755
+ layer: number;
1756
+ key: string;
1757
+ name: string;
1758
+ tiered: boolean;
1759
+ displayName: string;
1760
+ }
1761
+
1762
+ interface ShipWorldMetadataSummary {
1763
+ name: string | null;
1764
+ color: number | null;
1765
+ colorCss: string | null;
1766
+ width: number | null;
1767
+ height: number | null;
1768
+ lockdownTimerSeconds: number | null;
1769
+ lockdownCountdownSeconds: number | null;
1770
+ onlineShipOwnerCount: number | null;
1771
+ requiredShipOwnerCount: number | null;
1772
+ allShipOwnersOnline: boolean | null;
1773
+ lockdownEngaged: boolean | null;
1774
+ lockdownState: ModelRecord;
1775
+ shipState: ModelRecord;
1776
+ }
1777
+
1778
+ interface WorldUpdate {
1779
+ type: string;
1780
+ world: WorldState | null;
1781
+ packet?: unknown;
1782
+ bubble?: CommsBubbleSummary;
1783
+ decoded?: unknown;
1784
+ updates?: unknown[];
1785
+ result?: unknown;
1786
+ }
1787
+ ```
1788
+
1789
+ ### Tiles
1790
+
1791
+ ```ts
1792
+ interface Tile {
1793
+ x: number;
1794
+ y: number;
1795
+ material: number;
1796
+ materialName?: string | null;
1797
+ shape: number;
1798
+ shapeName?: string | null;
1799
+ hp: number;
1800
+ /** @deprecated Use hp. Raw 0-255 HP fraction byte, not absolute integrity. */
1801
+ integrity: number;
1802
+ color: number | null;
1803
+ solid?: boolean | null;
1804
+ maxHp?: number | null;
1805
+ hpRatio?: number | null;
1806
+ hpValue?: number | null;
1807
+ }
1808
+
1809
+ interface TilePhysics {
1810
+ filter?: {
1811
+ categoryBits: number;
1812
+ maskBits: number;
1813
+ groupIndex: number;
1814
+ };
1815
+ transparent?: boolean;
1816
+ walkway?: boolean;
1817
+ restitution?: number;
1818
+ friction?: number;
1819
+ }
1820
+
1821
+ interface TileDefinition {
1822
+ name?: string;
1823
+ solid: boolean;
1824
+ destruct_item?: number;
1825
+ blocks_bullets?: boolean;
1826
+ hp?: number;
1827
+ no_build_surface?: boolean;
1828
+ physics?: TilePhysics;
1829
+ }
1830
+
1831
+ interface Tileset {
1832
+ scale: number;
1833
+ atlas: string;
1834
+ tile_width: number;
1835
+ tiles: TileDefinition[];
1836
+ }
1837
+ ```
1838
+
1839
+ ### `ModelSnapshot`
1840
+
1841
+ ```ts
1842
+ interface ModelSnapshot {
1843
+ generation: number | null;
1844
+ tableCount: number;
1845
+ entityCount: number;
1846
+ removedEntities: number[];
1847
+ lastUpdate: unknown;
1848
+ errors: unknown[];
1849
+ entities: EntitySummary[];
1850
+ blocks: BlockSummary[];
1851
+ transforms: TransformSummary[];
1852
+ players: PlayerSummary[];
1853
+ shipControls: ShipControlSummary[];
1854
+ machines: MachineSummary;
1855
+ tables: unknown[];
1856
+ }
1857
+ ```
1858
+
1859
+ ## Additional Entity Component Shapes
1860
+
1861
+ ```ts
1862
+ interface TransformSummary {
1863
+ entity: number;
1864
+ x: number | null;
1865
+ y: number | null;
1866
+ rot: number | null;
1867
+ flags: unknown[];
1868
+ }
1869
+
1870
+ interface ItemHolderSummary {
1871
+ entity: number;
1872
+ itemId: number | null;
1873
+ itemName: string | null;
1874
+ count: number | null;
1875
+ }
1876
+
1877
+ interface ItemCrateSummary {
1878
+ entity: number;
1879
+ itemId: number | null;
1880
+ itemName: string | null;
1881
+ count: number | null;
1882
+ width: number | null;
1883
+ height: number | null;
1884
+ itemState: ModelRecord;
1885
+ sizeState: ModelRecord;
1886
+ }
1887
+
1888
+ interface HoverOutlineSummary {
1889
+ entity: number;
1890
+ width: number | null;
1891
+ height: number | null;
1892
+ rawWidth: number | null;
1893
+ rawHeight: number | null;
1894
+ state: ModelRecord;
1895
+ }
1896
+
1897
+ interface MapMarkerSummary {
1898
+ entity: number;
1899
+ kind: string;
1900
+ title: string | null;
1901
+ key: string | null;
1902
+ description: string | null;
1903
+ color: number | null;
1904
+ colorCss: string | null;
1905
+ accentColor: number | null;
1906
+ accentColorCss: string | null;
1907
+ width: number | null;
1908
+ height: number | null;
1909
+ labelState: ModelRecord;
1910
+ zoneState: ModelRecord;
1911
+ }
1912
+
1913
+ interface DockingSpringSummary {
1914
+ entity: number;
1915
+ id: number | null;
1916
+ width: number;
1917
+ height: number;
1918
+ state: ModelRecord;
1919
+ }
1920
+
1921
+ interface HugeThrusterSummary {
1922
+ entity: number;
1923
+ width: number;
1924
+ height: number;
1925
+ state: ModelRecord;
1926
+ }
1927
+
1928
+ interface ShipSizeSummary {
1929
+ entity: number;
1930
+ width: number | null;
1931
+ height: number | null;
1932
+ rawWidth: number | null;
1933
+ rawHeight: number | null;
1934
+ state: ModelRecord;
1935
+ }
1936
+
1937
+ interface HealthSummary {
1938
+ entity: number;
1939
+ hp: number | null;
1940
+ maxHp: number | null;
1941
+ ratio: number | null;
1942
+ state: ModelRecord;
1943
+ }
1944
+
1945
+ interface BotSummary {
1946
+ entity: number;
1947
+ className: string;
1948
+ identifier: string;
1949
+ typeA: number | null;
1950
+ typeB: number | null;
1951
+ }
1952
+ ```
1953
+
1954
+ ## Blueprint Shapes
1955
+
1956
+ ### Placement request
1957
+
1958
+ ```ts
1959
+ interface BlueprintPlacement {
1960
+ x: number;
1961
+ y: number;
1962
+ width?: number;
1963
+ height?: number;
1964
+ w?: number;
1965
+ h?: number;
1966
+ source: string;
1967
+ }
1968
+
1969
+ interface BlueprintPlacementMessage {
1970
+ type: 9;
1971
+ x: number;
1972
+ y: number;
1973
+ w: number;
1974
+ h: number;
1975
+ source: string;
1976
+ }
1977
+ ```
1978
+
1979
+ ### Preview state
1980
+
1981
+ ```ts
1982
+ interface BlueprintPreviewSummary {
1983
+ entity: number;
1984
+ itemId: number;
1985
+ itemName: string | null;
1986
+ bits: number;
1987
+ rawBits: number | null;
1988
+ placementOffsets: number[];
1989
+ placementCount: number;
1990
+ placements: {
1991
+ offset: number;
1992
+ x: number | null;
1993
+ y: number | null;
1994
+ itemId: number;
1995
+ itemName: string | null;
1996
+ }[];
1997
+ x: number | null;
1998
+ y: number | null;
1999
+ rot: number | null;
2000
+ state: ModelRecord;
2001
+ }
2002
+ ```
2003
+
2004
+ ## PUI And Comms Shapes
2005
+
2006
+ ```ts
2007
+ interface PuiEvent {
2008
+ type: "pui";
2009
+ filter?: number;
2010
+ ent_id?: number;
2011
+ update?: boolean;
2012
+ data?: unknown;
2013
+ world?: number | null;
2014
+ }
2015
+
2016
+ interface CommsMessage {
2017
+ type: 3;
2018
+ msg: string;
2019
+ }
2020
+
2021
+ interface NormalizedCommsMessage {
2022
+ raw: unknown;
2023
+ text: string;
2024
+ }
2025
+
2026
+ interface CommsEvent {
2027
+ type: "comms";
2028
+ filter?: number;
2029
+ ent_id: number | null;
2030
+ entity: number | null;
2031
+ msgs_text: unknown[];
2032
+ rawMessages: unknown[];
2033
+ messages: NormalizedCommsMessage[];
2034
+ update?: boolean;
2035
+ world?: number | null;
2036
+ }
2037
+
2038
+ interface CommsBubbleSummary {
2039
+ sequence: number;
2040
+ worldId: number;
2041
+ entity: number | null;
2042
+ modelId: number | null;
2043
+ message: string;
2044
+ color: number | null;
2045
+ colorCss: string | null;
2046
+ durationSeconds: number | null;
2047
+ raw: unknown;
2048
+ }
2049
+ ```
2050
+
2051
+ ## Scanner And Ack Shapes
2052
+
2053
+ ```ts
2054
+ interface CommandAck {
2055
+ world: number;
2056
+ commandNumber: number;
2057
+ }
2058
+
2059
+ interface ScannerResult {
2060
+ kind: "manifest" | "bom" | "unknown";
2061
+ sid: number | null;
2062
+ shipHex: string | null;
2063
+ shipName: string | null;
2064
+ blocks: Record<string, number> | null;
2065
+ objects: Record<string, number> | null;
2066
+ inventories: Record<string, number> | null;
2067
+ materials: Record<string, number> | null;
2068
+ }
2069
+ ```
2070
+
2071
+ ## Helper Function Exports
2072
+
2073
+ These are public lower-level helpers. Prefer the object/domain methods unless
2074
+ you explicitly need protocol payloads or decoded utility functions.
2075
+
2076
+ ### Msgpack
2077
+
2078
+ Module: `dredless/protocol/msgpack` or root.
2079
+
2080
+ ```ts
2081
+ function decodeMsgpack(bytes: Uint8Array | ArrayBuffer | number[]): unknown;
2082
+ function encodeMsgpack(value: unknown): Uint8Array;
2083
+ ```
2084
+
2085
+ ### Commands
2086
+
2087
+ Module: `dredless/protocol/commands` or root.
2088
+
2089
+ ```ts
2090
+ function buildSignedCommandPacket(command: Command, sessionId: number): Uint8Array;
2091
+ ```
2092
+
2093
+ ### Inventory helpers
2094
+
2095
+ Module: `dredless/protocol/inventory` or root.
2096
+
2097
+ ```ts
2098
+ function normalizeEquipmentSlot(slot: EquipmentSlot): 16 | 17 | 18 | 19 | 20 | 21;
2099
+ function equipmentSlotName(slot: number): "head" | "face" | "body" | "back" | "hands" | "feet" | null;
2100
+ function buildInventoryDragCommand(source: number, target: number, split?: boolean): InventoryDragCommand;
2101
+ function buildEquipItemCommand(source: number, slot: EquipmentSlot, split?: boolean): InventoryDragCommand;
2102
+ function buildUnequipItemCommand(slot: EquipmentSlot, target?: number, split?: boolean): InventoryDragCommand;
2103
+ function normalizeInventoryEvent(event: unknown): InventoryState;
2104
+ ```
2105
+
2106
+ Inventory drag output remains protocol-shaped:
2107
+
2108
+ ```ts
2109
+ interface InventoryDragCommand {
2110
+ drag: {
2111
+ source: number;
2112
+ target: number;
2113
+ split: boolean;
2114
+ };
2115
+ }
2116
+ ```
2117
+
2118
+ `normalizeInventoryEvent()` returns the normalized `InventoryState` shape documented under `client.inventory`.
2119
+
2120
+ ### Comms helpers
2121
+
2122
+ Module: `dredless/protocol/comms` or root.
2123
+
2124
+ ```ts
2125
+ function buildCommsMessage(message?: string): CommsMessage;
2126
+ function normalizeCommsEvent(event: unknown): CommsEvent;
2127
+ function flattenRichText(value: unknown): string;
2128
+ ```
2129
+
2130
+ ### Sign helpers
2131
+
2132
+ Module: `dredless/protocol/sign` or root.
2133
+
2134
+ ```ts
2135
+ function buildSignTextMessage(text?: string, mode?: SignDisplayMode): SignTextMessage;
2136
+ function normalizeSignDisplayMode(mode?: SignDisplayMode): 0 | 1 | 2;
2137
+ function signDisplayModeName(mode: number): SignDisplayMode | null;
2138
+ ```
2139
+
2140
+ Output:
2141
+
2142
+ ```ts
2143
+ interface SignTextMessage {
2144
+ type: 5;
2145
+ cmd: "sign_text";
2146
+ args: [string, 0 | 1 | 2];
2147
+ }
2148
+ ```
2149
+
2150
+ ### Ship-management helpers
2151
+
2152
+ Module: `dredless/protocol/ship-management` or root.
2153
+
2154
+ ```ts
2155
+ function buildShipManagementMessage(act: string, arg?: unknown, extra?: Record<string, unknown> | null): ShipManagementMessage;
2156
+ function buildShipPrivacyMessage(privacy: ShipPrivacy): ShipManagementMessage;
2157
+ function buildStarterRecoveryMessage(itemId: number): ShipManagementMessage;
2158
+ function buildPlayerListMessage(): ShipManagementMessage;
2159
+ function buildInviteResetMessage(): ShipManagementMessage;
2160
+ function buildSetPlayerRankMessage(refId: number, rank: ShipPlayerRank): ShipManagementMessage;
2161
+ function buildKickPlayerMessage(refId: number): ShipManagementMessage;
2162
+ function buildBanPlayerMessage(refId: number): ShipManagementMessage;
2163
+ function buildDemoteSelfMessage(): ShipManagementMessage;
2164
+ function normalizePrivacy(privacy: ShipPrivacy): 0 | 1;
2165
+ function normalizePlayerRank(rank: ShipPlayerRank): 0 | 1 | 3;
2166
+ function normalizeShipConfig(event: unknown): ShipConfig;
2167
+ function normalizeCaptainSubrank(event: unknown): CaptainSubrank;
2168
+ function normalizeShipPlayerList(event: unknown, previous?: ShipPlayerList | null, currentCaptainSubrank?: CaptainSubrank | null): ShipPlayerList;
2169
+ ```
2170
+
2171
+ Message output:
2172
+
2173
+ ```ts
2174
+ interface ShipManagementMessage {
2175
+ type: 4;
2176
+ act: string;
2177
+ arg: unknown;
2178
+ rank?: unknown;
2179
+ }
2180
+ ```
2181
+
2182
+ ### Blueprint helpers
2183
+
2184
+ Module: `dredless/protocol/blueprint` or root.
2185
+
2186
+ ```ts
2187
+ function buildBlueprintPlacementMessage(placement: BlueprintPlacement): BlueprintPlacementMessage;
2188
+ ```
2189
+
2190
+ ### UI config helpers
2191
+
2192
+ Module: `dredless/protocol/ui-config` or root.
2193
+
2194
+ ```ts
2195
+ function buildNavigationUnitConfigData(entity: number, config: NavigationUnitConfig & { destination: number }): Uint8Array;
2196
+ function buildNavigationUnitClipboardConfigData(config: NavigationUnitConfig & { destination: number }): Uint8Array;
2197
+ function buildNavigationUnitPasteConfigData(entity: number, config: NavigationUnitConfig & { destination: number }): Uint8Array;
2198
+ function buildGeneratorMazePuzzleData(entity: number, solution: string | number): Uint8Array;
2199
+ function buildCargoHatchFilterConfigData(entity: number, filterMode?: LoaderFilterMode): Uint8Array;
2200
+ function buildCargoHatchFilterItemsData(entity: number, filterSlots?: Array<number | null | undefined>): Uint8Array;
2201
+ function buildCargoHatchFullConfigData(entity: number, config?: Pick<LoaderFullConfig, "filterMode" | "filterSlots">): Uint8Array;
2202
+ function buildCargoHatchCopyConfigData(config?: Pick<LoaderFullConfig, "filterMode" | "filterSlots">): Uint8Array;
2203
+ function buildClipboardConfigData(target: ClipboardTarget, commandName: string, values?: Iterable<number>): Uint8Array;
2204
+ function buildClipboardFixedAngleData(target: ClipboardTarget, direction: FixedAngleDirection): Uint8Array;
2205
+ function buildGeneratorClipboardDirectionData(direction: FixedAngleDirection): Uint8Array;
2206
+ function buildCargoEjectorDirectionData(entity: number, direction: FixedAngleDirection): Uint8Array;
2207
+ function buildCargoEjectorPasteConfigData(entity: number, direction: FixedAngleDirection): Uint8Array;
2208
+ function buildCargoEjectorCopyConfigData(direction: FixedAngleDirection): Uint8Array;
2209
+ function buildCargoEjectorClipboardDirectionData(direction: FixedAngleDirection): Uint8Array;
2210
+ function buildExpandoClipboardAngleData(angle: number): Uint8Array;
2211
+ function buildLoaderClipboardConfigData(config?: LoaderConfig): Uint8Array;
2212
+ function buildLoaderConfigData(entity: number, config?: LoaderConfig): Uint8Array;
2213
+ function buildLoaderCopyConfigData(config?: LoaderFullConfig): Uint8Array;
2214
+ function buildLoaderFilterConfigData(entity: number, filterMode?: LoaderFilterMode): Uint8Array;
2215
+ function buildLoaderFilterItemsData(entity: number, filterSlots?: Array<number | null | undefined>): Uint8Array;
2216
+ function buildLoaderFullConfigData(entity: number, config?: LoaderFullConfig): Uint8Array;
2217
+ function buildPusherConfigData(entity: number, config?: PusherConfig): Uint8Array;
2218
+ function buildPusherFilterItemsData(entity: number, filterSlots?: Array<number | null | undefined>): Uint8Array;
2219
+ ```
2220
+
2221
+ Clipboard/config input types:
2222
+
2223
+ ```ts
2224
+ type ClipboardTarget =
2225
+ | number
2226
+ | "loader" | "loader-config" | "loaderConfig"
2227
+ | "hatch" | "cargo-hatch" | "cargoHatch"
2228
+ | "ejector" | "cargo-ejector" | "cargoEjector"
2229
+ | "expando" | "expando-box" | "expandoBox"
2230
+ | "generator" | "shield-generator" | "shieldGenerator"
2231
+ | "navigation" | "navigation-unit" | "navigationUnit"
2232
+ | "nav" | "nav-unit" | "navUnit";
2233
+
2234
+ const FixedAngleDirection = { Right: "right", Up: "up", Left: "left", Down: "down" } as const;
2235
+ type FixedAngleDirection = typeof FixedAngleDirection[keyof typeof FixedAngleDirection];
2236
+ ```
2237
+
2238
+ ### Generator maze helpers
2239
+
2240
+ Module: `dredless/game/generator-maze` or root.
2241
+
2242
+ ```ts
2243
+ function generateGeneratorMaze(seed: number): GeneratorMaze;
2244
+ function solveGeneratorMazeSeed(seed: number): string;
2245
+ function maybeSolveGeneratorMazeSeed(seed: number | null | undefined): string | null;
2246
+ ```
2247
+
2248
+ Output:
2249
+
2250
+ ```ts
2251
+ interface GeneratorMazeCellWalls {
2252
+ up: boolean;
2253
+ down: boolean;
2254
+ left: boolean;
2255
+ right: boolean;
2256
+ }
2257
+
2258
+ interface GeneratorMazeCell {
2259
+ x: number;
2260
+ y: number;
2261
+ value: number;
2262
+ hex: string;
2263
+ digit: number;
2264
+ walls: GeneratorMazeCellWalls;
2265
+ backtrackDirection: number;
2266
+ marker: number;
2267
+ }
2268
+
2269
+ interface GeneratorMaze {
2270
+ seed: number;
2271
+ width: number;
2272
+ height: number;
2273
+ cells: GeneratorMazeCell[];
2274
+ rows: GeneratorMazeCell[][];
2275
+ solution: string;
2276
+ }
2277
+ ```
2278
+
2279
+ ### Crypto, compression, and model decoding
2280
+
2281
+ Modules: `dredless/crypto/chacha`, `dredless/compression/lz4`,
2282
+ `dredless/model`, and root.
2283
+
2284
+ ```ts
2285
+ function decryptPayload(
2286
+ wireBytes: Uint8Array | ArrayBuffer | number[],
2287
+ worldId: number,
2288
+ seed: number
2289
+ ): Uint8Array;
2290
+
2291
+ function decompressLz4Frame(bytes: Uint8Array | ArrayBuffer | number[]): Uint8Array;
2292
+
2293
+ function decodeModelData(bytes: Uint8Array | ArrayBuffer | number[]): unknown;
2294
+ ```
2295
+
2296
+ ### Ship spec helpers
2297
+
2298
+ Module: `dredless/ships`.
2299
+
2300
+ ```ts
2301
+ function createShipSpec(name?: string, color?: string): ShipSpec;
2302
+ function createInviteShipSpec(code: string): ShipSpec;
2303
+ ```
2304
+
2305
+ `createShipSpec()` returns a `{ type: "new", ... }` ship spec.
2306
+ `createInviteShipSpec()` returns a `{ type: "invite", code }` ship spec.
2307
+
2308
+ ## Public Constants From Subpath Modules
2309
+
2310
+ These constants are exported by helper subpaths for consumers that need protocol
2311
+ symbols. They are not required for normal object-domain use.
2312
+
2313
+ ### `dredless/protocol/blueprint`
2314
+
2315
+ ```ts
2316
+ const BLUEPRINT_PLACEMENT_TYPE: 9;
2317
+ ```
2318
+
2319
+ ### `dredless/protocol/comms`
2320
+
2321
+ ```ts
2322
+ const COMMS_MESSAGE_TYPE: 3;
2323
+ ```
2324
+
2325
+ ### `dredless/protocol/inventory`
2326
+
2327
+ ```ts
2328
+ const EQUIPMENT_SLOT_INDEXES: Readonly<{
2329
+ head: 16;
2330
+ face: 17;
2331
+ body: 18;
2332
+ back: 19;
2333
+ hands: 20;
2334
+ feet: 21;
2335
+ }>;
2336
+ ```
2337
+
2338
+ ### `dredless/protocol/ship-management`
2339
+
2340
+ ```ts
2341
+ const BAN_ACTION: "ban";
2342
+ const DEMOTE_SELF_ACTION: "demote_self";
2343
+ const KICK_ACTION: "kick";
2344
+ const PLAYER_LIST_ACTION: "player_list";
2345
+ const INVITE_RESET_ACTION: "invite_reset";
2346
+ const SET_PRIVACY_ACTION: "set_privacy";
2347
+ const SET_RANK_ACTION: "set_rank";
2348
+ const SHIP_MANAGEMENT_TYPE: 4;
2349
+ const STARTER_RECOVERY_ACTION: "starter_recovery";
2350
+ ```
2351
+
2352
+ ### `dredless/protocol/sign`
2353
+
2354
+ ```ts
2355
+ const SIGN_TEXT_COMMAND: "sign_text";
2356
+ const SIGN_DISPLAY_MODES: Map<0 | 1 | 2, "always" | "when-near" | "on-hover">;
2357
+ ```
2358
+
2359
+ ### `dredless/protocol/ui-config`
2360
+
2361
+ ```ts
2362
+ const CLIPBOARD_ACTION: 1;
2363
+ const CLIPBOARD_ANGLE_COMMAND: "angle";
2364
+ const CLIPBOARD_FIXED_ANGLE_COMMAND: "angle_fixed";
2365
+ const CLIPBOARD_TARGET_VALUES: Map<string, number>;
2366
+ const FIXED_ANGLE_VALUES: Map<string, 0 | 1 | 2 | 3>;
2367
+ const GENERATOR_MAZE_PUZZLE_COMMAND: "maze_puzzle";
2368
+ const LOADER_CONFIG_COMMAND: "config_loader";
2369
+ const LOADER_FALSE: 0x8e;
2370
+ const LOADER_FILTER_CONFIG_COMMAND: "filter_config";
2371
+ const LOADER_FILTER_ITEMS_COMMAND: "filter_items";
2372
+ const LOADER_TRUE: 0x8d;
2373
+ const NAV_UNIT_COMMAND: "config_nav_unit";
2374
+ const NAV_UNIT_FALSE: 0x8d;
2375
+ const NAV_UNIT_TRUE: 0x8e;
2376
+ const PUSHER_CONFIG_COMMAND: "config_pusher";
2377
+ const PUSHER_FILTER_ITEMS_COMMAND: "filter_items";
2378
+ ```
2379
+
2380
+ ## Usage Patterns
2381
+
2382
+ ### Read loaders from a live client
2383
+
2384
+ Use [NODE_API.md](./NODE_API.md) or [BROWSER_API.md](./BROWSER_API.md) to start a client for the current runtime.
2385
+
2386
+ ```js
2387
+ await client.whenReady();
2388
+
2389
+ for (const loader of client.currentShip().machines.loaders()) {
2390
+ console.log(loader.id, loader.pick, loader.place, loader.cycle);
2391
+ }
2392
+ ```
2393
+
2394
+ ### Read all nearby ships, including detailed loaded worlds when available
2395
+
2396
+ ```js
2397
+ const ships = client.overworld().ships({
2398
+ includeWorld: true,
2399
+ includeModel: true,
2400
+ sort: "distance"
2401
+ });
2402
+
2403
+ for (const ship of ships) {
2404
+ const snapshot = ship.snapshot();
2405
+ console.log(snapshot.name, snapshot.hexCode, snapshot.hasWorldData);
2406
+ }
2407
+ ```
2408
+
2409
+ ### Use generic features before narrowing to a machine type
2410
+
2411
+ ```js
2412
+ const entity = client.currentShip().entities.get(14);
2413
+
2414
+ if (entity.has("loader")) {
2415
+ const loader = entity.asLoader();
2416
+ loader.setCycle(10);
2417
+ }
2418
+
2419
+ if (entity.has("outline")) {
2420
+ console.log(entity.feature("outline"));
2421
+ }
2422
+ ```
2423
+
2424
+ ### Configure a pusher
2425
+
2426
+ ```js
2427
+ const pusher = client.currentShip().machines.pusher(27);
2428
+
2429
+ pusher.configure({
2430
+ mode: "push",
2431
+ filteredMode: "pull",
2432
+ angle: 90,
2433
+ speed: 20,
2434
+ length: 30,
2435
+ filterInventory: true
2436
+ });
2437
+ ```
2438
+
2439
+ ### Configure a navigation unit
2440
+
2441
+ ```js
2442
+ const nav = client.currentShip().machines.navigationUnit();
2443
+
2444
+ nav.setDestination(30, {
2445
+ autoWarpOnShieldFailure: true,
2446
+ autoWarpOnNoCaptains: false
2447
+ });
2448
+ ```
2449
+
2450
+ ## Cost Guidelines
2451
+
2452
+ Use handles for normal live code:
2453
+
2454
+ ```js
2455
+ client.currentShip().entities.get(id);
2456
+ client.currentShip().machines.loader(id);
2457
+ ```
2458
+
2459
+ Use raw grouped state for display, sorting, and cheap bulk reads:
2460
+
2461
+ ```js
2462
+ client.currentShip().entities.raw();
2463
+ client.currentShip().machines.state();
2464
+ ```
2465
+
2466
+ Use snapshots when you need immutable point-in-time data:
2467
+
2468
+ ```js
2469
+ entity.snapshot();
2470
+ client.currentShip().entities.snapshots();
2471
+ client.state({ includeModel: true });
2472
+ ```
2473
+
2474
+ Use debug and world/model classes when reverse engineering, replaying captures,
2475
+ or validating protocol assumptions:
2476
+
2477
+ ```js
2478
+ client.debug.modelRecord(worldId, tableId, entityId);
2479
+ client.debug.decodeErrors();
2480
+ client.debug.worldStore();
2481
+ ```