dredless 0.7.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -58
- package/dist/browser/dredless.global.js +794 -98
- package/dist/browser/dredless.global.js.map +4 -4
- package/docs/ACCOUNT.md +146 -0
- package/docs/API_REFERENCE.md +63 -2563
- package/docs/BROWSER_API.md +151 -70
- package/docs/CLIENT.md +183 -0
- package/docs/EVENTS.md +136 -0
- package/docs/GETTING_STARTED.md +135 -0
- package/docs/MACHINES.md +351 -0
- package/docs/MANAGEMENT.md +285 -0
- package/docs/NODE_API.md +120 -318
- package/docs/PLAYER_INVENTORY.md +235 -0
- package/docs/PROTOCOL.md +227 -0
- package/docs/README.md +44 -0
- package/docs/TROUBLESHOOTING.md +91 -0
- package/docs/WORLD_STATE.md +183 -0
- package/package.json +1 -2
- package/src/browser.d.ts +31 -1
- package/src/browser.js +10 -0
- package/src/client/core.js +302 -15
- package/src/client/domains/index.js +57 -7
- package/src/client/index.d.ts +1 -1
- package/src/index.d.ts +299 -13
- package/src/index.js +10 -0
- package/src/network/account.js +182 -0
- package/src/network/disconnect.d.ts +2 -0
- package/src/network/disconnect.js +53 -0
- package/src/network/index.d.ts +1 -0
- package/src/network/index.js +1 -0
- package/src/network/invites.d.ts +0 -3
- package/src/network/invites.js +3 -40
- package/src/network/session.d.ts +2 -0
- package/src/network/session.js +21 -0
- package/src/protocol/outbound/ship-management.d.ts +66 -1
- package/src/protocol/outbound/ship-management.js +83 -0
- package/src/state/model/decoder.js +70 -10
- package/src/state/model/index.d.ts +4 -0
- package/src/state/model/state.js +22 -7
- package/src/state/world/index.js +27 -1
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# Ship management
|
|
2
|
+
|
|
3
|
+
[Documentation index](README.md) · [Events](EVENTS.md#management-updates) · [Account perks](ACCOUNT.md#ships-with-patron-perks)
|
|
4
|
+
|
|
5
|
+
## Contents
|
|
6
|
+
|
|
7
|
+
- [Completion and shared rules](#completion-and-shared-rules)
|
|
8
|
+
- [Read management state](#read-management-state)
|
|
9
|
+
- [Save a ship](#save-a-ship)
|
|
10
|
+
- [Rename a ship](#rename-a-ship)
|
|
11
|
+
- [Privacy and invite reset](#privacy-and-invite-reset)
|
|
12
|
+
- [Crew control](#crew-control)
|
|
13
|
+
- [Demote yourself](#demote-yourself)
|
|
14
|
+
- [Starter recovery](#starter-recovery)
|
|
15
|
+
- [Crew logs](#crew-logs)
|
|
16
|
+
- [Patron perks](#patron-perks)
|
|
17
|
+
- [Gravity](#gravity)
|
|
18
|
+
|
|
19
|
+
## Completion and shared rules
|
|
20
|
+
|
|
21
|
+
Methods below live on `client.management`. Server permissions still apply; having a method does not grant captain/owner
|
|
22
|
+
access.
|
|
23
|
+
|
|
24
|
+
| Operation | Return | What has completed? |
|
|
25
|
+
|----------------------------------------|---------------------------|----------------------------------------------|
|
|
26
|
+
| `canSave()` | `boolean` | Local eligibility check only |
|
|
27
|
+
| `save(options?)` | `Promise<DisconnectInfo>` | Close with `Saved` code 4015 received |
|
|
28
|
+
| `rename(name, options?)` | `Promise<void>` | Permission allowed and commit sent |
|
|
29
|
+
| `resetInvite(options?)` | `Promise<ShipConfig>` | Changed nonempty invite key observed |
|
|
30
|
+
| `demoteSelf(options?)` | `Promise<void>` | Demotion received and caches cleared |
|
|
31
|
+
| `recoverStarterItem(itemId, options?)` | `Promise<void>` | Successful recovery response received |
|
|
32
|
+
| Other action methods | `DredlessClient` | Command sent/queued; no confirmation awaited |
|
|
33
|
+
|
|
34
|
+
The promise-based operations require a connected, ready, writable client. Options use `timeout` in milliseconds, default
|
|
35
|
+
**10000**, positive and at most **2147483647**. A second pending call of the same operation rejects; this is not a
|
|
36
|
+
general lock across all management actions.
|
|
37
|
+
|
|
38
|
+
Sending errors, disconnects, and timeouts reject. Disconnect failures use `DisconnectError` with `.disconnect`. Rename,
|
|
39
|
+
recovery, and invite-reset waits also reject when demotion interrupts them or their confirmation arrives for a changed
|
|
40
|
+
current world. Save relies on its close result; self-demotion waits for the demotion event.
|
|
41
|
+
|
|
42
|
+
Timeout does not undo a server action. Replies do not carry request identifiers, so a matching later event confirms
|
|
43
|
+
observed state, not necessarily a uniquely correlated request. Avoid competing raw requests and blind retries while
|
|
44
|
+
waiting.
|
|
45
|
+
|
|
46
|
+
Direct client aliases include `canSaveShip`, `saveShip`, `renameShip`, `resetInvite`, `demoteSelf`, and
|
|
47
|
+
`recoverStarterItem` with the same corresponding options/returns. Prefer the domain in application code.
|
|
48
|
+
|
|
49
|
+
## Read management state
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
client.management.config(): ShipConfig | null;
|
|
53
|
+
client.management.playerList(): ShipPlayerList | null;
|
|
54
|
+
client.management.crewLog(): CrewLog | null;
|
|
55
|
+
client.management.hasCheats(): boolean;
|
|
56
|
+
client.management.requestPlayerList(): DredlessClient;
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Config includes `privacy`, `privacyName`, `inviteKey`, `teamId`, and `patronPerks`. `hasCheats()` reads the cached
|
|
60
|
+
captain-subrank message's cheat flag; it is not a capability test for arbitrary commands.
|
|
61
|
+
|
|
62
|
+
Player-list messages update/remove individual entries and merge them into the cache. `ShipPlayerList` includes
|
|
63
|
+
`players`, latest nonremoved `changes`, `removedPlayers`, `ownerCaptainRank`, and derived `shipOwners`. Each player
|
|
64
|
+
entry has `refId`, identity/color, rank, captain rank, item/alias data, playtime, online count, and management flags.
|
|
65
|
+
Use `refId` for management commands, not an entity ID or `sid`.
|
|
66
|
+
|
|
67
|
+
`canBeManaged` and owner-related fields are derived hints; the server remains authoritative. The current normalization
|
|
68
|
+
marks players at the lowest positive captain rank as `shipOwners`; this can include tied ranks. It is not a guarantee
|
|
69
|
+
that the server recognizes a unique owner for an owner-only action.
|
|
70
|
+
|
|
71
|
+
Read cached data once and subscribe to `ship-config`, `captain-subrank`, `player-list`, and `crew-log`. They can contain
|
|
72
|
+
`null` after demotion. `requestPlayerList()` sends a refresh request; it does not return the response or wait for it.
|
|
73
|
+
Config/logs arrive through server session messages.
|
|
74
|
+
|
|
75
|
+
## Save a ship
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
client.management.canSave(): boolean;
|
|
79
|
+
client.management.save(options?: {timeout?: number}): Promise<DisconnectInfo>;
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`canSave()` requires a connected/ready client, a current ship with a known parent world, and parent `danger_level === 0`
|
|
83
|
+
(Safe Zone). Missing or unsafe metadata returns `false`. It does not check all server-side permission rules.
|
|
84
|
+
|
|
85
|
+
**Fragment:** this saves the ship and ejects its players:
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
if (!client.management.canSave()) throw new Error("Ship is not in a known Safe Zone");
|
|
89
|
+
const result = await client.management.save();
|
|
90
|
+
console.log(result.name); // Saved
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The promise resolves only when the socket closes with `DropReason.Saved` (4015). Any other close code rejects. If the
|
|
94
|
+
server keeps the connection open without confirming, the operation times out. After success the client is disconnected;
|
|
95
|
+
join/start a new client to continue using the ship.
|
|
96
|
+
|
|
97
|
+
## Rename a ship
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
client.management.rename(name: string, options?: {color?: string; timeout?: number}): Promise<void>;
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Name must be a string of at most **32 UTF-16 code units**, matching the official input limit. It is not automatically
|
|
104
|
+
trimmed; the client permits an empty string, with final validation left to the server. Optional color is a six-digit
|
|
105
|
+
`#RRGGBB` string; omit it to preserve the color from the permission response.
|
|
106
|
+
|
|
107
|
+
**Fragment:**
|
|
108
|
+
|
|
109
|
+
```js
|
|
110
|
+
await client.management.rename("New Name", {color: "#3a8bce"});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The helper requests permission, waits for `rename_response`, then sends the commit. A denial rejects with the server's
|
|
114
|
+
message. There is no dedicated commit-success acknowledgment handled by the official client; this promise resolves when
|
|
115
|
+
the commit is sent. Observe ship metadata for the eventual name/color.
|
|
116
|
+
|
|
117
|
+
## Privacy and invite reset
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
client.management.setPrivacy(privacy: ShipPrivacy): DredlessClient;
|
|
121
|
+
client.management.resetInvite(options?: {timeout?: number}): Promise<ShipConfig>;
|
|
122
|
+
|
|
123
|
+
type ShipPrivacy = 0 | 1 | boolean | "public" | "private";
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`0`, `false`, and `"public"` select public; `1`, `true`, and `"private"` select private. The privacy setter does not
|
|
127
|
+
await confirmation; read `config()` or `ship-config`.
|
|
128
|
+
|
|
129
|
+
**Fragment:** resetting the invite invalidates its previous link:
|
|
130
|
+
|
|
131
|
+
```js
|
|
132
|
+
const config = await client.management.resetInvite();
|
|
133
|
+
console.log(config.inviteKey);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Reset waits for a config whose nonempty invite key differs from the key cached when the request began. Unchanged-key
|
|
137
|
+
config updates are ignored. If no previous key was known, the first subsequent nonempty key satisfies the wait. It
|
|
138
|
+
returns the updated config; it does not prove that a particular request caused that update.
|
|
139
|
+
|
|
140
|
+
## Crew control
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
client.management.setPlayerRank(refId: number, rank: ShipPlayerRank): DredlessClient;
|
|
144
|
+
client.management.kickPlayer(refId: number): DredlessClient;
|
|
145
|
+
client.management.banPlayer(refId: number): DredlessClient;
|
|
146
|
+
client.management.unbanPlayer(refId: number): DredlessClient;
|
|
147
|
+
|
|
148
|
+
type ShipPlayerRank = 0 | 1 | 3 | "guest" | "crew" | "captain";
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Rank values are guest 0, crew 1, captain 3. IDs must be nonnegative integers. These calls send immediately and do not
|
|
152
|
+
await a player-list change. Observe the merged list and server messages. A locally plausible `canBeManaged` value does
|
|
153
|
+
not override server restrictions.
|
|
154
|
+
|
|
155
|
+
**Fragment:** `selectedRefId` must come from a player-list entry selected by your application:
|
|
156
|
+
|
|
157
|
+
```js
|
|
158
|
+
const player = client.management.playerList()?.players.find((entry) => entry.refId === selectedRefId);
|
|
159
|
+
if (!player || player.refId === null) throw new Error("No matching management entry");
|
|
160
|
+
client.management.unbanPlayer(player.refId);
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Player-rank changes are different from [door/spawn access restrictions](MACHINES.md#context-menus-and-access).
|
|
164
|
+
|
|
165
|
+
## Demote yourself
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
client.management.demoteSelf(options?: {timeout?: number}): Promise<void>;
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
This requests demotion to Guest. It can remove the account's ability to load/manage the ship and can revoke its patron
|
|
172
|
+
contribution. The server's demotion response is the confirmation, not merely sending the command.
|
|
173
|
+
|
|
174
|
+
Before emitting `demote`, Dredless clears ship config, captain subrank/cheat flags, player list, and crew log. It then
|
|
175
|
+
emits their cache events with `null`. Pending rename/recovery/invite-reset waits reject. Player entity rank is still
|
|
176
|
+
driven by subsequent model updates; cache clearing does not fabricate a model update.
|
|
177
|
+
|
|
178
|
+
If the server does not send a demotion response, the promise times out. The helper does not manufacture a success result
|
|
179
|
+
from an unrelated captain-subrank value.
|
|
180
|
+
|
|
181
|
+
## Starter recovery
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
client.management.recoverStarterItem(itemId: number,
|
|
185
|
+
options?: {timeout?: number}): Promise<void>;
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Use an actual starter-recovery item ID supported by the server. IDs must be nonnegative integers. Recovery is an
|
|
189
|
+
owner-controlled server action: it deletes existing instances of the relevant items from the ship and returns them to
|
|
190
|
+
the caller's inventory. The official UI describes a once-per-minute limit; the server enforces eligibility and cooldown.
|
|
191
|
+
|
|
192
|
+
The promise waits for `starter_recovery_response`. Missing/null `fail_reason` resolves; otherwise it rejects with the
|
|
193
|
+
server's failure message. Inventory/model effects arrive through their normal updates. Every response also emits
|
|
194
|
+
`starter-recovery` with `{success, failReason}` and the original session packet, including responses to lower-level
|
|
195
|
+
requests.
|
|
196
|
+
|
|
197
|
+
## Crew logs
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
client.management.crewLog(): CrewLog | null;
|
|
201
|
+
|
|
202
|
+
interface CrewLogEntry {
|
|
203
|
+
icon: string | null;
|
|
204
|
+
text: string;
|
|
205
|
+
rawText: unknown;
|
|
206
|
+
count: number;
|
|
207
|
+
refId: number | null;
|
|
208
|
+
secondaryRefId: number | null;
|
|
209
|
+
}
|
|
210
|
+
interface CrewLog {
|
|
211
|
+
entries: CrewLogEntry[];
|
|
212
|
+
changes: CrewLogEntry[];
|
|
213
|
+
reset: boolean;
|
|
214
|
+
amend: boolean;
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Logs are pushed as captain/session `log` messages. There is no separate log-fetch request in the official client. Before
|
|
219
|
+
the first message, the cache is `null`; a received empty log is a non-null object with `entries: []`.
|
|
220
|
+
|
|
221
|
+
Apply each message in order: clear for `reset`, remove the last remaining entry for `amend`, append the new entries,
|
|
222
|
+
then retain the newest **500**. `entries` is the resulting log, oldest first; `changes` is just the entries supplied by
|
|
223
|
+
the latest message. An empty reset/amend can still change state. Counts aggregate repeated actions and do not expand the
|
|
224
|
+
array.
|
|
225
|
+
|
|
226
|
+
`text` flattens supported rich-text content. Styled content, date/image/badge tokens remain available in `rawText` for
|
|
227
|
+
custom rendering. `icon` remains an asset path. `refId`/`secondaryRefId` preserve server player references used to
|
|
228
|
+
filter the official player list.
|
|
229
|
+
|
|
230
|
+
**Fragment:**
|
|
231
|
+
|
|
232
|
+
```js
|
|
233
|
+
const report = (log) => console.log(log?.entries ?? []);
|
|
234
|
+
client.on("crew-log", report);
|
|
235
|
+
report(client.management.crewLog());
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
The event's second argument is the original session packet. The cache is also available at `client.crewLog` and
|
|
239
|
+
`client.state().crewLog`. Demotion emits `crew-log` with `null`; disconnect clears the cache before the disconnect
|
|
240
|
+
event.
|
|
241
|
+
|
|
242
|
+
## Patron perks
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
client.management.setPatronPerks(enabled: boolean): DredlessClient;
|
|
246
|
+
client.management.enablePatronPerks(): DredlessClient;
|
|
247
|
+
client.management.disablePatronPerks(): DredlessClient;
|
|
248
|
+
client.management.patronPerks(): ShipPatronPerk[] | null;
|
|
249
|
+
client.management.hasPatronPerks(name?: string): boolean;
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Setters apply/remove the caller's contribution on the current ship and return immediately. The direct client alias is `setShipPatronPerks(enabled)`. `enabled` must be a boolean;
|
|
253
|
+
the aliases pass true/false. The server checks account eligibility, permissions, and available perk allocations.
|
|
254
|
+
Disabling does not remove other patrons' contributions. Patron items can despawn after perks are removed.
|
|
255
|
+
|
|
256
|
+
`patronPerks()` reads config's `{name, color, tier}[]`: `null` if config is unavailable, `[]` if known empty. Color is
|
|
257
|
+
packed RGB; known tiers are `bronze`, `silver`, `gold`, `plat`, and `flux`. `hasPatronPerks()` checks any contributor; a
|
|
258
|
+
supplied string checks an exact, case-sensitive name. Unknown config returns `false`.
|
|
259
|
+
|
|
260
|
+
`patron-perks-response` emits `{failure}` plus the packet for every `perk_response`. A true flag reports failure; a
|
|
261
|
+
false flag alone is not a current applied-patrons list. Observe `ship-config` for that state. Setters do not
|
|
262
|
+
optimistically change the list.
|
|
263
|
+
|
|
264
|
+
To remove your perks from a listed ship without joining it, use the
|
|
265
|
+
separate [account method](ACCOUNT.md#ships-with-patron-perks).
|
|
266
|
+
|
|
267
|
+
## Gravity
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
client.management.setGravity(direction: ShipGravityDirection): DredlessClient;
|
|
271
|
+
type ShipGravityDirection = "down" | "up" | "left" | "right" | 0 | 1 | 2 | 3;
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
This sends the official `coolsnake303` gravity control immediately, without awaiting confirmation. The search string
|
|
275
|
+
reveals controls in the official UI; it is not an unlock request required by the protocol.
|
|
276
|
+
|
|
277
|
+
| Constant | String | Wire value |
|
|
278
|
+
|--------------------------|-----------|------------|
|
|
279
|
+
| `GravityDirection.Down` | `"down"` | 0 |
|
|
280
|
+
| `GravityDirection.Up` | `"up"` | 1 |
|
|
281
|
+
| `GravityDirection.Left` | `"left"` | 2 |
|
|
282
|
+
| `GravityDirection.Right` | `"right"` | 3 |
|
|
283
|
+
|
|
284
|
+
Values must be exactly one of these lowercase names or numeric values. This mapping differs from `FixedAngleDirection`
|
|
285
|
+
used by machine configuration. Direct client alias: `setShipGravity(direction)`.
|