dredless 0.6.3 → 1.0.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 (41) hide show
  1. package/README.md +22 -57
  2. package/dist/browser/dredless.global.js +827 -1058
  3. package/dist/browser/dredless.global.js.map +4 -4
  4. package/docs/ACCOUNT.md +146 -0
  5. package/docs/API_REFERENCE.md +63 -2550
  6. package/docs/BROWSER_API.md +151 -70
  7. package/docs/CLIENT.md +183 -0
  8. package/docs/EVENTS.md +136 -0
  9. package/docs/GETTING_STARTED.md +135 -0
  10. package/docs/MACHINES.md +351 -0
  11. package/docs/MANAGEMENT.md +285 -0
  12. package/docs/NODE_API.md +120 -318
  13. package/docs/PLAYER_INVENTORY.md +235 -0
  14. package/docs/PROTOCOL.md +227 -0
  15. package/docs/README.md +44 -0
  16. package/docs/TROUBLESHOOTING.md +91 -0
  17. package/docs/WORLD_STATE.md +183 -0
  18. package/package.json +1 -2
  19. package/src/browser.d.ts +31 -1
  20. package/src/browser.js +10 -0
  21. package/src/client/core.js +302 -15
  22. package/src/client/domains/index.js +57 -7
  23. package/src/client/index.d.ts +1 -1
  24. package/src/index.d.ts +303 -14
  25. package/src/index.js +10 -0
  26. package/src/network/account.js +182 -0
  27. package/src/network/disconnect.d.ts +2 -0
  28. package/src/network/disconnect.js +53 -0
  29. package/src/network/index.d.ts +1 -0
  30. package/src/network/index.js +1 -0
  31. package/src/network/invites.d.ts +0 -3
  32. package/src/network/invites.js +3 -40
  33. package/src/network/session.d.ts +2 -0
  34. package/src/network/session.js +21 -0
  35. package/src/protocol/outbound/ship-management.d.ts +66 -1
  36. package/src/protocol/outbound/ship-management.js +83 -0
  37. package/src/state/model/decoder.js +101 -56
  38. package/src/state/model/index.d.ts +4 -0
  39. package/src/state/model/loader-config.js +0 -997
  40. package/src/state/model/state.js +28 -80
  41. package/src/state/world/index.js +27 -1
@@ -0,0 +1,183 @@
1
+ # World and entity reads
2
+
3
+ [Documentation index](README.md) · [Machines](MACHINES.md) · [Events](EVENTS.md)
4
+
5
+ ## Contents
6
+
7
+ - [Choose a world](#choose-a-world)
8
+ - [Entities and features](#entities-and-features)
9
+ - [Machine and other collections](#machine-and-other-collections)
10
+ - [Nearby ships](#nearby-ships)
11
+ - [Live reads and snapshots](#live-reads-and-snapshots)
12
+ - [Coordinates and incomplete data](#coordinates-and-incomplete-data)
13
+
14
+ ## Choose a world
15
+
16
+ ```ts
17
+ client.currentShip(): ShipDomain | null;
18
+ client.ship(): ShipDomain | null; // Alias of currentShip().
19
+ client.overworld(): OverworldDomain | null;
20
+ client.world(id: number): WorldDomain | null;
21
+ client.currentPlayerEntity(): EntityHandle | null;
22
+ ```
23
+
24
+ The ship world describes its interior. The overworld contains ship entities and surrounding objects. Nearby ships may be
25
+ represented in the overworld without their interiors being decoded. An entity ID is meaningful only together with its
26
+ world.
27
+
28
+ A `WorldDomain` exposes `id`, `exists()`, `entities`, `machines`, `players`, `blocks`, and `materials`, plus
29
+ `snapshot(options?)`. A `ShipDomain` adds `metadata`, `entity()`, and `overworldEntity`. These refer to the ship's
30
+ associated overworld entity when available, not its local player.
31
+
32
+ **Fragment:** read what is available now:
33
+
34
+ ```js
35
+ const ship = client.currentShip();
36
+ if (ship) {
37
+ console.log(ship.id, ship.metadata);
38
+ console.log(ship.players.all());
39
+ }
40
+ ```
41
+
42
+ World domains capture a scope. Reacquire a current-ship domain when changing ships rather than assuming an old handle
43
+ follows every future world transition.
44
+
45
+ ## Entities and features
46
+
47
+ ```ts
48
+ world.entities.all(): EntityHandle[];
49
+ world.entities.get(entity: EntityRef): EntityHandle;
50
+ world.entities.snapshots(): EntitySnapshot[];
51
+ world.entities.states(): EntitySnapshot[]; // Alias of snapshots().
52
+
53
+ type EntityRef = number | EntityHandle | EntitySummary | EntityDebugSummary;
54
+
55
+ entity.exists(): boolean;
56
+ entity.snapshot(): EntitySnapshot | null;
57
+ entity.is(type: string): boolean;
58
+ entity.has(feature: string): boolean;
59
+ entity.feature(feature: string): unknown | null;
60
+ entity.as(type: string): MachineHandle | null;
61
+ entity.openTips(options?: TipOptions): Promise<TipList>;
62
+ entity.use(options?: {invSlot?: number; hold?: boolean}, command?: Command): DredlessClient;
63
+ ```
64
+
65
+ `get()` constructs a lightweight live handle; it does not validate existence. Reads such as `id`, `type`, `position`,
66
+ `health`, and `features` resolve against currently decoded state. `entity.entity` is a deprecated alias for `id`.
67
+
68
+ Use feature checks for generic behavior, or narrow to machine-specific handles with `asLoader()`, `asPusher()`,
69
+ `asLauncher()`, `asNavigationUnit()`, `as("fabricator")`, `asCommsStation()`, `asSign()`, `asGenerator()`,
70
+ `asCargoHatch()`, `asCargoEjector()`, `asCannon()`, `asThruster()`, `asHelm()`, `asDoor()`, `asSpawnPoint()`,
71
+ `asShieldProjector()`, `asFluidTank()`, or `asExpandoBox()`.
72
+
73
+ **Fragment:** inspect an actual decoded entity instead of assuming a particular ID exists:
74
+
75
+ ```js
76
+ const entity = client.currentShip()?.entities.all().find((item) => item.has("loader"));
77
+ const loader = entity?.asLoader();
78
+ if (loader) console.log(loader.id, loader.state);
79
+ ```
80
+
81
+ `EntitySnapshot` includes `id`, `entity`, `type`, `features`, `position`, `rotation`, and methods `is`, `has`, and
82
+ `feature`. Component data is available through `feature()`. Generic summaries contain `transform`, footprint/label/kind
83
+ metadata, and typed components. See `EntitySummary`, `EntityContentsSummary`, and component summary types in
84
+ the [declarations](../src/index.d.ts).
85
+
86
+ ## Machine and other collections
87
+
88
+ `world.machines` is the typed entrypoint for machines. [Machine reference](MACHINES.md#find-a-machine) lists every
89
+ collection and special lookup behavior.
90
+
91
+ ```ts
92
+ world.machines.state(): MachineSummary;
93
+ world.machines.raw(): MachineSummary; // Alias of state().
94
+ world.players.all(): PlayerSummary[];
95
+ world.players.current(): PlayerSummary | null;
96
+ world.blocks.all(): BlockSummary[];
97
+ world.blocks.at(x: number, y: number): BlockSummary | null;
98
+ world.materials.all(): MaterialSummary[];
99
+ ```
100
+
101
+ `MachineSummary` groups arrays such as `loaders`, `pushers`, `pusherBeams`, `launchers`, `cannons`, and `doors`. Use it
102
+ for bulk display; use handles for actions. Raw/summary objects should be treated as read-only even when JavaScript does
103
+ not freeze them.
104
+
105
+ Materials summarize decoded blocks; they are not an authoritative ship inventory. A missing collection or component can
106
+ reflect incomplete decoding, not an absent server object.
107
+
108
+ ## Nearby ships
109
+
110
+ ```ts
111
+ client.overworld()?.ships(options?: ShipReadOptions): ShipHandle[];
112
+ client.overworld()?.shipByHex(hexCode: string, options?: ShipReadOptions): ShipHandle | null;
113
+ client.overworld()?.shipByEntity(entity: EntityRef, options?: ShipReadOptions): ShipHandle | null;
114
+
115
+ interface ShipReadOptions {
116
+ includeWorld?: boolean; // true
117
+ includeTiles?: boolean; // false
118
+ includeModel?: boolean; // false
119
+ includeBlocks?: boolean; // false
120
+ sort?: "distance" | null;
121
+ }
122
+
123
+ shipHandle.snapshot(): ShipReadSummary;
124
+ shipHandle.world(): WorldDomain | null;
125
+ ```
126
+
127
+ A ship handle exposes `entity`, `name`, `hexCode`, `distance`, `worldId`, and `hasWorldData`. Its summary includes
128
+ position, thrust, shield, warp, control data, and optionally a decoded `world`. Distance is measured between available
129
+ overworld transforms; it is `null` when those positions are missing.
130
+
131
+ **Fragment:**
132
+
133
+ ```js
134
+ const ships = client.overworld()?.ships({includeWorld: false, sort: "distance"}) ?? [];
135
+ for (const ship of ships) console.log(ship.hexCode, ship.name, ship.distance);
136
+ ```
137
+
138
+ `includeWorld` includes data already in the client; it does not fetch another ship's interior. `hasWorldData` describes
139
+ the returned summary with the chosen options. Ship read handles hold a summary from the read that created them; re-query
140
+ for a fresh list/summary after updates.
141
+
142
+ ## Live reads and snapshots
143
+
144
+ | API | Semantics |
145
+ |--------------------------------------------------|-------------------------------------------------------------------------------|
146
+ | Entity/machine handle properties | Resolve against current decoded state |
147
+ | `entity.snapshot()`, `entities.snapshots()` | Cloned, frozen entity snapshots, cached by source-summary identity |
148
+ | Machine `.state`, collection `.state()`/`.raw()` | Summary reads; no universal immutability guarantee |
149
+ | `shipHandle.snapshot()` | Returns the summary held by that ship read handle |
150
+ | `world.snapshot()` / `client.state()` | Aggregate snapshots with some copied arrays and some shared nested references |
151
+
152
+ Do not mutate returned state to configure the server. Use action/configuration methods. For historical records, select
153
+ the serializable fields you need and clone those fields yourself. Client/world snapshots are not a promise of deep
154
+ immutability.
155
+
156
+ ```ts
157
+ world.snapshot(options?: {
158
+ includeTiles?: boolean;
159
+ includeModel?: boolean;
160
+ includeBlocks?: boolean;
161
+ }): WorldSnapshot | null;
162
+ ```
163
+
164
+ Tiles, raw model tables, and block materialization are opt-in because they can be large. `includeModel` includes raw
165
+ tables; it does not mean ordinary entity/machine summaries were otherwise missing. For direct model snapshots, the
166
+ corresponding raw-table option is `includeTables`.
167
+
168
+ The client also retains compatibility reads such as `client.entities(scope?)`, `client.entity(id, scope?)`, and
169
+ `client.shipWorld(options?)`. Prefer scoped domains for new code. Scopes are `"ship"`, `"current"`, `"overworld"`, or a
170
+ numeric world ID.
171
+
172
+ ## Coordinates and incomplete data
173
+
174
+ Positions and distances are game/world coordinates, not browser pixels. A ship interior and the overworld are different
175
+ coordinate spaces. Raw transform `q*` fields are decoder internals; read normalized transforms and the explicitly named
176
+ angle fields instead.
177
+
178
+ Angle inputs/outputs are not uniform across all APIs: cannon outputs are radians, launcher setters take degrees, and
179
+ discrete direction enums have operation-specific wire mappings. [Machines](MACHINES.md) documents each one.
180
+
181
+ Readiness does not guarantee all component tables, a local player, a panel, or another ship's interior. Watch `model`/
182
+ `world` events, tolerate missing fields, and inspect [decode errors](PROTOCOL.md#debug-domains-and-state-classes) when
183
+ apparently present objects cannot be read.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dredless",
3
- "version": "0.6.3",
3
+ "version": "1.0.0",
4
4
  "description": "A fully-featured and from-scratch headless drednot.io client implementation written in pure js.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/certainhuman/dredless#readme",
@@ -152,7 +152,6 @@
152
152
  }
153
153
  },
154
154
  "dependencies": {
155
- "sharp": "^0.35.4",
156
155
  "ws": "^8.18.0"
157
156
  },
158
157
  "files": [
package/src/browser.d.ts CHANGED
@@ -26,15 +26,23 @@ export {
26
26
  normalizeInventoryEvent,
27
27
  EquipmentSlot,
28
28
  buildBanPlayerMessage,
29
+ buildUnbanPlayerMessage,
29
30
  buildDemoteSelfMessage,
30
31
  buildInviteResetMessage,
31
32
  buildKickPlayerMessage,
32
33
  buildPlayerListMessage,
34
+ buildShipRenameRequestMessage,
35
+ buildShipRenameCommitMessage,
33
36
  buildShipManagementMessage,
34
37
  buildSetPlayerRankMessage,
35
38
  buildShipPrivacyMessage,
39
+ buildShipGravityMessage,
40
+ buildSetPatronPerksMessage,
41
+ GravityDirection,
42
+ normalizeGravityDirection,
36
43
  buildStarterRecoveryMessage,
37
44
  normalizeCaptainSubrank,
45
+ normalizeCrewLog,
38
46
  normalizeShipPlayerList,
39
47
  normalizePlayerRank,
40
48
  normalizePrivacy,
@@ -82,6 +90,15 @@ export {
82
90
  } from "./index.js";
83
91
 
84
92
  export type {
93
+ RenameShipOptions,
94
+ ShipManagementOptions,
95
+ StarterRecoveryOptions,
96
+ StarterRecoveryResult,
97
+ CrewLog,
98
+ CrewLogEntry,
99
+ ShipGravityDirection,
100
+ ShipPatronPerk,
101
+ PatronPerksResponse,
85
102
  TipDomain,
86
103
  TipList,
87
104
  TipOptions,
@@ -93,6 +110,9 @@ export type {
93
110
  ServerRef,
94
111
  SessionSnapshot,
95
112
  Account,
113
+ AccountDetails,
114
+ AccountPerkShip,
115
+ ClanTagDetails,
96
116
  ConnectionSnapshot,
97
117
  BlueprintPlacement,
98
118
  BlueprintPlacementMessage,
@@ -105,7 +125,7 @@ export type {
105
125
  ReadWorldScope
106
126
  } from "./index.js";
107
127
 
108
- import type {Connection, DredlessClient, Server, ServerRef, SessionSnapshot, Ship, ShipList, ShipRef} from "./index.js";
128
+ import type {AccountDetails, AccountPerkShip, ClanTagDetails, Connection, DredlessClient, Server, ServerRef, SessionSnapshot, Ship, ShipList, ShipRef} from "./index.js";
109
129
 
110
130
 
111
131
  export class BrowserSession {
@@ -139,6 +159,16 @@ export class BrowserSession {
139
159
 
140
160
  fetchAccountStatus(): Promise<unknown>;
141
161
 
162
+ /** Scrape the authenticated account page; does not update account/status or session serialization. */
163
+ fetchAccountDetails(): Promise<AccountDetails>;
164
+ fetchClanTag(): Promise<ClanTagDetails>;
165
+ /** Submit the form and confirm the stored tag on the account page. */
166
+ setClanTag(tag: string): Promise<ClanTagDetails>;
167
+ clearClanTag(): Promise<ClanTagDetails>;
168
+ /** Remove this account's perks and return the confirmed remaining applied ships. */
169
+ removeShipPerks(shipId: string | number): Promise<AccountPerkShip[]>;
170
+
171
+
142
172
  fetchShips(server: ServerRef): Promise<Ship[]>;
143
173
 
144
174
  fetchShipList(server: ServerRef): Promise<ShipList>;
package/src/browser.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export {Connection} from "./network/connection.js";
2
+ export {DropReason, DisconnectError, normalizeDisconnect} from "./network/disconnect.js";
2
3
  export {DredlessClient, WrenchMode, TurretMode} from "./client/index.js";
3
4
  export {WorldStore, WorldState} from "./state/world/index.js";
4
5
  export {FabricatorType, ModelState, decodeModelData} from "./state/model/index.js";
@@ -18,15 +19,24 @@ export {
18
19
  } from "./protocol/outbound/inventory.js";
19
20
  export {
20
21
  buildBanPlayerMessage,
22
+ buildUnbanPlayerMessage,
21
23
  buildDemoteSelfMessage,
22
24
  buildInviteResetMessage,
23
25
  buildKickPlayerMessage,
24
26
  buildPlayerListMessage,
27
+ buildSaveShipMessage,
28
+ buildShipRenameRequestMessage,
29
+ buildShipRenameCommitMessage,
25
30
  buildShipManagementMessage,
26
31
  buildSetPlayerRankMessage,
27
32
  buildShipPrivacyMessage,
33
+ buildShipGravityMessage,
34
+ buildSetPatronPerksMessage,
35
+ GravityDirection,
36
+ normalizeGravityDirection,
28
37
  buildStarterRecoveryMessage,
29
38
  normalizeCaptainSubrank,
39
+ normalizeCrewLog,
30
40
  normalizeShipPlayerList,
31
41
  normalizePlayerRank,
32
42
  normalizePrivacy,