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.
- package/README.md +22 -57
- package/dist/browser/dredless.global.js +827 -1058
- package/dist/browser/dredless.global.js.map +4 -4
- package/docs/ACCOUNT.md +146 -0
- package/docs/API_REFERENCE.md +63 -2550
- 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 +303 -14
- 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 +101 -56
- package/src/state/model/index.d.ts +4 -0
- package/src/state/model/loader-config.js +0 -997
- package/src/state/model/state.js +28 -80
- package/src/state/world/index.js +27 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Getting started
|
|
2
|
+
|
|
3
|
+
[Documentation index](README.md) · [API reference](API_REFERENCE.md)
|
|
4
|
+
|
|
5
|
+
## Contents
|
|
6
|
+
|
|
7
|
+
- [Choose a runtime](#choose-a-runtime)
|
|
8
|
+
- [Read servers and ships](#read-servers-and-ships)
|
|
9
|
+
- [Connect through an invite](#connect-through-an-invite)
|
|
10
|
+
- [Read live state](#read-live-state)
|
|
11
|
+
- [Send an action](#send-an-action)
|
|
12
|
+
- [Next steps](#next-steps)
|
|
13
|
+
|
|
14
|
+
## Choose a runtime
|
|
15
|
+
|
|
16
|
+
For Node, install `dredless` and save examples as `.mjs` files. The runtime must provide `fetch`. Import `dredless/node`
|
|
17
|
+
for explicit sessions.
|
|
18
|
+
|
|
19
|
+
For browser integrations, import `dredless/browser` through a bundler or use the global bundle. Run in a
|
|
20
|
+
page/content-script context where the Drednot origin and cookies are accessible. An arbitrary website cannot acquire
|
|
21
|
+
Drednot authentication by loading this package. Follow [browser setup](BROWSER_API.md).
|
|
22
|
+
|
|
23
|
+
## Read servers and ships
|
|
24
|
+
|
|
25
|
+
This standalone Node program makes HTTP requests without joining a ship:
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
import Dredless from "dredless/node";
|
|
29
|
+
|
|
30
|
+
const session = await Dredless.createAnonSession(process.env.DREDNOT_ANON_KEY);
|
|
31
|
+
const servers = await Dredless.fetchServers();
|
|
32
|
+
const server = servers[0];
|
|
33
|
+
if (!server) throw new Error("No servers found");
|
|
34
|
+
|
|
35
|
+
console.log(server.index, server.description);
|
|
36
|
+
const list = await session.fetchShipList(server);
|
|
37
|
+
for (const ship of list.ships) {
|
|
38
|
+
console.log(ship.name, ship.hexCode, ship.playerCount, ship.saved);
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Choose a server from this list for the next example. Array position and `server.index` are not interchangeable: numeric
|
|
43
|
+
`ServerRef` arguments mean the server index.
|
|
44
|
+
|
|
45
|
+
## Connect through an invite
|
|
46
|
+
|
|
47
|
+
Obtain an invite code and server index from the ship you intend to join. Supply the code segment from its invite URL,
|
|
48
|
+
rather than the entire URL:
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
DREDNOT_SERVER_ID=0 DREDNOT_INVITE_CODE=your-code node inspect.mjs
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Save the following as `inspect.mjs`. It joins once, reads the currently available state, and closes the connection even
|
|
55
|
+
if inspection fails:
|
|
56
|
+
|
|
57
|
+
```js
|
|
58
|
+
import Dredless from "dredless/node";
|
|
59
|
+
|
|
60
|
+
const code = process.env.DREDNOT_INVITE_CODE;
|
|
61
|
+
const serverId = Number(process.env.DREDNOT_SERVER_ID);
|
|
62
|
+
if (!code || !Number.isInteger(serverId) || serverId < 0) {
|
|
63
|
+
throw new Error("Set DREDNOT_INVITE_CODE and a non-negative DREDNOT_SERVER_ID");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const session = await Dredless.createAnonSession(process.env.DREDNOT_ANON_KEY);
|
|
67
|
+
const servers = await Dredless.fetchServers();
|
|
68
|
+
const server = servers.find((entry) => entry.index === serverId);
|
|
69
|
+
if (!server) throw new Error("Requested server was not found");
|
|
70
|
+
|
|
71
|
+
const client = await session.joinInvite(server, code);
|
|
72
|
+
try {
|
|
73
|
+
const ship = client.currentShip();
|
|
74
|
+
if (!ship) throw new Error("Current ship state is not available yet");
|
|
75
|
+
console.log(ship.metadata);
|
|
76
|
+
console.log(ship.machines.loaders().map((loader) => ({id: loader.id, state: loader.state})));
|
|
77
|
+
} finally {
|
|
78
|
+
client.close();
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The factory resolves after the ready packet. It does not promise that every optional component or panel is populated.
|
|
83
|
+
For ongoing work, react to [events](EVENTS.md), and tolerate missing values.
|
|
84
|
+
|
|
85
|
+
Use `session.joinShip(server, ship)` for an active ship, or `session.startShip(server, ship)` when it may need loading
|
|
86
|
+
from a save. [Connection choices](NODE_API.md#join-start-and-invites) explains the difference.
|
|
87
|
+
|
|
88
|
+
## Read live state
|
|
89
|
+
|
|
90
|
+
**Fragment:** attach listeners immediately after obtaining a client. Factory promises can resolve after some initial
|
|
91
|
+
packets have arrived, so also read the cached state once:
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
function reportLoaders() {
|
|
95
|
+
const ship = client.currentShip();
|
|
96
|
+
if (!ship) return;
|
|
97
|
+
console.log(ship.machines.loaders().map((loader) => ({id: loader.id, cycle: loader.cycle})));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
client.on("model", reportLoaders);
|
|
101
|
+
client.on("disconnect", (info) => console.log(info.name, info.code, info.reason));
|
|
102
|
+
reportLoaders();
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
For a long-running integration, call `client.close()` when your application finishes. There is no automatic
|
|
106
|
+
reconnect. [Lifecycle](CLIENT.md) describes cleanup and retry boundaries.
|
|
107
|
+
|
|
108
|
+
## Send an action
|
|
109
|
+
|
|
110
|
+
A client must be writable and ready. The server still enforces permissions, range, inventory, and game rules.
|
|
111
|
+
|
|
112
|
+
**Fragment:** configure an existing loader you have permission and range to configure:
|
|
113
|
+
|
|
114
|
+
```js
|
|
115
|
+
const loader = client.currentShip()?.machines.loaders()[0];
|
|
116
|
+
if (!loader) throw new Error("No loader is currently visible");
|
|
117
|
+
loader.configure({
|
|
118
|
+
pick: "middle-left", place: "middle-right", priority: "normal", cycle: 5
|
|
119
|
+
}); // cycle is seconds; sends configuration without awaiting confirmation.
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Configuration enums are explicit here because of the [current numeric-default limitation](MACHINES.md#loaders).
|
|
123
|
+
|
|
124
|
+
Returning a client means a command was sent or queued. Awaiting such a return value adds no server acknowledgment.
|
|
125
|
+
Methods that return promises document their particular confirmation condition; for example, a rename waits for
|
|
126
|
+
permission and sends a commit, while ship saving waits for a close code.
|
|
127
|
+
See [completion](CLIENT.md#completion-and-readiness).
|
|
128
|
+
|
|
129
|
+
## Next steps
|
|
130
|
+
|
|
131
|
+
- [Node sessions](NODE_API.md): reuse identities and select ships.
|
|
132
|
+
- [World state](WORLD_STATE.md): entity IDs, handles, and snapshot behavior.
|
|
133
|
+
- [Machines](MACHINES.md): configuration, menus, and active interactions.
|
|
134
|
+
- [Management](MANAGEMENT.md): confirmed operations and crew control.
|
|
135
|
+
- [Account](ACCOUNT.md): clan tags, account details, and perk removal.
|
package/docs/MACHINES.md
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
# Machines and context menus
|
|
2
|
+
|
|
3
|
+
[Documentation index](README.md) · [World state](WORLD_STATE.md) · [Player input](PLAYER_INVENTORY.md)
|
|
4
|
+
|
|
5
|
+
## Contents
|
|
6
|
+
|
|
7
|
+
- [Find a machine](#find-a-machine)
|
|
8
|
+
- [Targeting and completion](#targeting-and-completion)
|
|
9
|
+
- [Context menus and access](#context-menus-and-access)
|
|
10
|
+
- [Loaders](#loaders)
|
|
11
|
+
- [Pushers](#pushers)
|
|
12
|
+
- [Launchers](#launchers)
|
|
13
|
+
- [Navigation units](#navigation-units)
|
|
14
|
+
- [Fabricators](#fabricators)
|
|
15
|
+
- [Signs and comms](#signs-and-comms)
|
|
16
|
+
- [Hatches, ejectors, and clipboard settings](#hatches-ejectors-and-clipboard-settings)
|
|
17
|
+
- [Generators and read-only machine state](#generators-and-read-only-machine-state)
|
|
18
|
+
|
|
19
|
+
## Find a machine
|
|
20
|
+
|
|
21
|
+
Get `machines` from a world domain, usually `client.currentShip()?.machines`. Plural methods return arrays of typed handles; singular methods accept `EntityRef` (an ID, handle, or summary):
|
|
22
|
+
|
|
23
|
+
| Collection | Lookup | Handle |
|
|
24
|
+
|----------------------|---------------------------|-------------------------|
|
|
25
|
+
| `loaders()` | `loader(entity)` | `LoaderHandle` |
|
|
26
|
+
| `pushers()` | `pusher(entity)` | `PusherHandle` |
|
|
27
|
+
| `launchers()` | `launcher(entity)` | `LauncherHandle` |
|
|
28
|
+
| `navigationUnits()` | `navigationUnit(entity?)` | `NavigationUnitHandle` |
|
|
29
|
+
| `fabricators()` | `fabricator(entity)` | `FabricatorHandle` |
|
|
30
|
+
| `commsStations()` | `commsStation(entity?)` | `CommsStationHandle` |
|
|
31
|
+
| `signs()` | `sign(entity)` | `SignHandle` |
|
|
32
|
+
| `generators()` | `generator(entity)` | `GeneratorHandle` |
|
|
33
|
+
| `cargoHatches()` | `cargoHatch(entity)` | `CargoHatchHandle` |
|
|
34
|
+
| `cargoEjectors()` | `cargoEjector(entity)` | `CargoEjectorHandle` |
|
|
35
|
+
| `cannons()` | `cannon(entity)` | `CannonHandle` |
|
|
36
|
+
| `thrusters()` | `thruster(entity)` | `ThrusterHandle` |
|
|
37
|
+
| `helms()` | `helm(entity)` | `HelmHandle` |
|
|
38
|
+
| `doors()` | `door(entity)` | `DoorHandle` |
|
|
39
|
+
| `spawnPoints()` | `spawnPoint(entity)` | `SpawnPointHandle` |
|
|
40
|
+
| `shieldProjectors()` | `shieldProjector(entity)` | `ShieldProjectorHandle` |
|
|
41
|
+
| `fluidTanks()` | `fluidTank(entity)` | `FluidTankHandle` |
|
|
42
|
+
| `expandoBoxes()` | `expandoBox(entity)` | `ExpandoBoxHandle` |
|
|
43
|
+
|
|
44
|
+
Navigation and comms lookups can choose an available handle when the entity argument is omitted, or return `null`. Other lookups create a handle without guaranteeing existence. Check `exists()`/`state` before using it. `machines.state()` and `.raw()` return grouped summaries, including pusher beams and shield generators.
|
|
45
|
+
|
|
46
|
+
Every machine handle inherits entity reads and actions. `.state` is a nullable machine summary property, not a method. `open(options?, command?)` sends player-use input and returns the client; it does not wait for a panel. Full summary fields are in the [handle and summary declarations](../src/index.d.ts).
|
|
47
|
+
|
|
48
|
+
## Targeting and completion
|
|
49
|
+
|
|
50
|
+
The server enforces range, permissions, and game state. Helpers neither move the player nor grant access.
|
|
51
|
+
|
|
52
|
+
| Action family | Target | Completion |
|
|
53
|
+
|-------------------------------------------------------------|-----------------------------------|-------------------------------------------------------|
|
|
54
|
+
| Loader/pusher/nav/hatch/ejector config, generator puzzle | Entity embedded in config payload | Sent/queued |
|
|
55
|
+
| Launcher angle/power, fabricator controls, sign text, comms | Active server interaction | Sent/queued; the handle's ID is not in these messages |
|
|
56
|
+
| `open()` | Entity focus in player input | Sent/queued, not panel-ready |
|
|
57
|
+
| Tip menu operations | Requested current-world entity | See menu contracts below |
|
|
58
|
+
| Door/spawn `setRank()` | Menu target | Requested rank observed in model |
|
|
59
|
+
|
|
60
|
+
For active-interaction actions, first open/use the intended machine and wait for the relevant panel or interaction state. The library does not offer a general `waitForPanel()` helper. Calling `someLauncher.setAngle()` alone does not select `someLauncher`.
|
|
61
|
+
|
|
62
|
+
## Context menus and access
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
client.tips.current: TipList | null;
|
|
66
|
+
client.tips.open(entity: number | EntityHandle, options?: TipOptions): Promise<TipList>;
|
|
67
|
+
client.tips.select(option: number | string, command?: Command): DredlessClient;
|
|
68
|
+
client.tips.choose(entity: number | EntityHandle, option: number | string,
|
|
69
|
+
options?: TipOptions): Promise<DredlessClient>;
|
|
70
|
+
client.tips.close(options?: TipOptions): Promise<DredlessClient>;
|
|
71
|
+
entity.openTips(options?: TipOptions): Promise<TipList>;
|
|
72
|
+
door.setRank(rank: ShipPlayerRank, options?: TipOptions): Promise<DredlessClient>;
|
|
73
|
+
spawnPoint.setRank(rank: ShipPlayerRank, options?: TipOptions): Promise<DredlessClient>;
|
|
74
|
+
|
|
75
|
+
interface TipOptions { timeout?: number; command?: Command; }
|
|
76
|
+
interface TipList {
|
|
77
|
+
readonly entity: number | null;
|
|
78
|
+
readonly world: number | null;
|
|
79
|
+
readonly filter: number | null;
|
|
80
|
+
readonly x: number;
|
|
81
|
+
readonly y: number;
|
|
82
|
+
readonly options: readonly string[];
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Fragment:** inspect and dismiss a visible door's menu:
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
const door = client.currentShip()?.machines.doors()[0];
|
|
90
|
+
if (!door) throw new Error("No door is currently decoded");
|
|
91
|
+
const menu = await door.openTips();
|
|
92
|
+
console.log(menu.options);
|
|
93
|
+
await client.tips.close();
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
- `open()` waits for a nonempty menu. A target must exist on this client, be in the current world, and have a position.
|
|
97
|
+
- `select()` accepts an exact displayed string or zero-based index. It sends the selection and clears the local menu without waiting for its effect.
|
|
98
|
+
- `choose()` opens a fresh menu and sends a selection. Its promise does not confirm the selected action finished.
|
|
99
|
+
- `close()` uses the normal dismissal click and waits for an empty tip list. With no menu, it resolves without sending.
|
|
100
|
+
- Door/spawn `setRank()` accepts `"guest"`, `"crew"`, `"captain"`, or `0`, `1`, `3`. It opens the appropriate menu, selects the restriction, and waits for model confirmation. It sends nothing if the rank already matches. This controls entity access, not a player's crew rank.
|
|
101
|
+
|
|
102
|
+
Timeout defaults to **5000 ms per response**; a rank change can involve a menu wait and a model wait. Only one asynchronous tip operation can run per client; overlaps reject. Disconnect, timeout, invalid menu choices, and invalid targets reject. Raw context-menu commands or another actor using the same socket can interfere with these operations.
|
|
103
|
+
|
|
104
|
+
The server does not include the target ID in a tip list. Dredless infers it from the pending request; unsolicited menus have `entity: null`. Empty menus still emit `tip-list` and set `current` to `null`. Repeated menus are not repeated action acknowledgments.
|
|
105
|
+
|
|
106
|
+
## Loaders
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
loader.configure(config?: LoaderConfig): DredlessClient;
|
|
110
|
+
loader.configureFull(config?: LoaderFullConfig): DredlessClient;
|
|
111
|
+
loader.copy(config?: LoaderFullConfig): DredlessClient;
|
|
112
|
+
loader.setPickPlace(pick: LoaderPosition, place: LoaderPosition, config?: LoaderConfig): DredlessClient;
|
|
113
|
+
loader.setPriority(priority: LoaderPriority, config?: LoaderConfig): DredlessClient;
|
|
114
|
+
loader.setStack(stack: number, config?: LoaderConfig): DredlessClient;
|
|
115
|
+
loader.setCycle(seconds: number, config?: LoaderConfig): DredlessClient;
|
|
116
|
+
loader.setRequireOutput(value: boolean, config?: LoaderConfig): DredlessClient;
|
|
117
|
+
loader.setWaitForStack(value: boolean, config?: LoaderConfig): DredlessClient;
|
|
118
|
+
loader.setFilterMode(mode: LoaderFilterMode): DredlessClient;
|
|
119
|
+
loader.setFilterItems(slots?: Array<number | null | undefined>): DredlessClient;
|
|
120
|
+
|
|
121
|
+
interface LoaderConfig {
|
|
122
|
+
pick?: LoaderPosition;
|
|
123
|
+
place?: LoaderPosition;
|
|
124
|
+
priority?: LoaderPriority;
|
|
125
|
+
stack?: number;
|
|
126
|
+
cycle?: number;
|
|
127
|
+
requireOutput?: boolean;
|
|
128
|
+
waitForStack?: boolean;
|
|
129
|
+
}
|
|
130
|
+
interface LoaderFullConfig extends LoaderConfig {
|
|
131
|
+
filterMode?: LoaderFilterMode;
|
|
132
|
+
filterSlots?: Array<number | null | undefined>;
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
| Input | Values/units |
|
|
137
|
+
|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
138
|
+
| `LoaderPosition` | `TopLeft`, `TopMiddle`, `TopRight`, `MiddleLeft`, `MiddleRight`, `BottomLeft`, `BottomMiddle`, `BottomRight` constants; values such as `"middle-left"` |
|
|
139
|
+
| `LoaderPriority` | `Low`/`Normal`/`High`, values `"low"`/`"normal"`/`"high"` |
|
|
140
|
+
| `stack` | Non-negative integer item count |
|
|
141
|
+
| `cycle` | Seconds, at least 1; rounded to 20 ticks/second, at most 65535 ticks |
|
|
142
|
+
| `LoaderFilterMode` | `AllowAll`, `BlockFilter`, `AllowFilter`, `BlockAll`; values `"allow-all"`, `"block-filter"`, `"allow-filter"`, `"block-all"` |
|
|
143
|
+
| `filterSlots` | Three item IDs (`0–65535`); omitted/null entries encode as zero; entries after the first three are not encoded |
|
|
144
|
+
|
|
145
|
+
State uses numeric codes: positions follow the table order above (`0–7`), priority is `-1/0/1`, and filter mode is `0–3`. Use `pickName`, `placeName`, `priorityName`, and `filterModeName` on `.state` for names. Component defaults when omitted by the server are middle-left → middle-right, normal priority, stack 16, cycle 1 second, both flags false.
|
|
146
|
+
|
|
147
|
+
**Current limitation:** high-level configuration merges numeric decoded enum values into builders that accept named enum inputs. Supply `pick`, `place`, and `priority` explicitly for configuration/setter/copy calls; also supply `filterMode` for full config/copy. Numeric state fields cannot be passed straight back as configuration enums. This applies even to a scalar setter such as `setCycle(seconds, config)`.
|
|
148
|
+
|
|
149
|
+
**Fragment:** all enum fields are explicit:
|
|
150
|
+
|
|
151
|
+
```js
|
|
152
|
+
import {LoaderPosition, LoaderPriority} from "dredless/node";
|
|
153
|
+
|
|
154
|
+
const loader = client.currentShip()?.machines.loaders()[0];
|
|
155
|
+
if (!loader) throw new Error("No loader is currently decoded");
|
|
156
|
+
loader.configure({
|
|
157
|
+
pick: LoaderPosition.MiddleLeft,
|
|
158
|
+
place: LoaderPosition.MiddleRight,
|
|
159
|
+
priority: LoaderPriority.Normal,
|
|
160
|
+
cycle: 5,
|
|
161
|
+
stack: 12
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
`configureFull()` includes filter mode/items; `configure()` does not. `.state` also exposes held-item, active, and progress values. These calls return immediately; observe `model` for changes. Copy writes clipboard configuration, not a local object clone.
|
|
166
|
+
|
|
167
|
+
## Pushers
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
pusher.configure(config?: PusherConfig): DredlessClient;
|
|
171
|
+
pusher.setAngle(angle: number, config?: PusherConfig): DredlessClient;
|
|
172
|
+
pusher.setSpeed(speed: number, config?: PusherConfig): DredlessClient;
|
|
173
|
+
pusher.setLength(length: number, config?: PusherConfig): DredlessClient;
|
|
174
|
+
pusher.setMode(mode: PusherMode, config?: PusherConfig): DredlessClient;
|
|
175
|
+
pusher.setFilteredMode(mode: PusherMode, config?: PusherConfig): DredlessClient;
|
|
176
|
+
pusher.setFilterInventory(value: boolean, config?: PusherConfig): DredlessClient;
|
|
177
|
+
pusher.setFilterItems(slots?: Array<number | null | undefined>): DredlessClient;
|
|
178
|
+
|
|
179
|
+
interface PusherConfig {
|
|
180
|
+
mode?: PusherMode;
|
|
181
|
+
filteredMode?: PusherMode;
|
|
182
|
+
angle?: number;
|
|
183
|
+
speed?: number;
|
|
184
|
+
length?: number;
|
|
185
|
+
filterInventory?: boolean;
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
`PusherMode.Push`/`Pull`/`DoNothing` are `"push"`/`"pull"`/`"do-nothing"`; state codes are `0/1/2`. Supply **both mode fields explicitly** to configuration and scalar setter calls because numeric decoded/default modes otherwise fail the named-enum builder validation.
|
|
190
|
+
|
|
191
|
+
Angle is the UI's degree value. Length is maximum beam distance in game units; speed is the UI's target movement speed, not a guarantee of actual object speed. These values are not browser pixels or a requested number of blocks. The target-speed control does not compensate for gravity, friction, or other forces.
|
|
192
|
+
|
|
193
|
+
The compact encoder requires finite numbers; integer values must be in `0–65535`. Fractional values use float32 encoding and do not have the same integer range check; that is not evidence the server accepts arbitrary fractions/ranges. Server rules still apply. Defaults without decoded values are angle 0, speed 20, length 1000, filterInventory false.
|
|
194
|
+
|
|
195
|
+
**Fragment:**
|
|
196
|
+
|
|
197
|
+
```js
|
|
198
|
+
const pusher = client.currentShip()?.machines.pushers()[0];
|
|
199
|
+
if (!pusher) throw new Error("No pusher is currently decoded");
|
|
200
|
+
pusher.configure({mode: "push", filteredMode: "pull", angle: 90, speed: 20, length: 30});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
`pusher.beam` exposes observed beam state: `active`, mode/name, and current length. It is distinct from the configured maximum length. `filterInventory` tests inventories of objects such as players and expando-boxes. The three filter item slots use the same item-ID convention as loaders.
|
|
204
|
+
|
|
205
|
+
## Launchers
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
launcher.setAngle(degrees: number): DredlessClient;
|
|
209
|
+
launcher.setPower(power: number): DredlessClient;
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Both act on the **active launcher interaction**, not an entity ID embedded in the command. Open/use the intended launcher first and establish that interaction before setting it. There is no promise that `open()` has completed that step. A handle by itself cannot configure an arbitrary launcher remotely.
|
|
213
|
+
|
|
214
|
+
Angle inputs are finite numbers, rounded to an integer and normalized into `0–359` degrees. Power must be an integer in `0–30`. These are sent immediately, without success confirmation.
|
|
215
|
+
|
|
216
|
+
Read `.state.angleDegrees`, `.state.angleRadians`, or `.state.angleRaw`. The angle is the launcher's decoded angle; the API does not add an inferred mounting rotation. Power is not exposed in `LauncherSummary`.
|
|
217
|
+
|
|
218
|
+
## Navigation units
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
nav.configure(config?: NavigationUnitConfig): DredlessClient;
|
|
222
|
+
nav.copy(config?: NavigationUnitConfig): DredlessClient;
|
|
223
|
+
nav.paste(config?: NavigationUnitConfig): DredlessClient;
|
|
224
|
+
nav.setDestination(destination: number, config?: NavigationUnitConfig): DredlessClient;
|
|
225
|
+
nav.setAutoWarp(config?: NavigationUnitConfig): DredlessClient;
|
|
226
|
+
nav.startWarp(config?: NavigationUnitConfig): DredlessClient;
|
|
227
|
+
nav.cancelWarp(config?: NavigationUnitConfig): DredlessClient;
|
|
228
|
+
|
|
229
|
+
interface NavigationUnitConfig {
|
|
230
|
+
destination?: number;
|
|
231
|
+
page?: number;
|
|
232
|
+
warp?: boolean | "start" | "idle" | "cancel";
|
|
233
|
+
autoWarpOnShieldFailure?: boolean;
|
|
234
|
+
autoWarpOnNoCaptains?: boolean;
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Destination is the game destination ID, not a ship entity ID. The encoded destination and page are integers in `0–255`; that byte range does not imply every destination ID is a valid game zone. Supply it explicitly if no current configuration is decoded. High-level methods fill other omitted fields from available state. Builders require a destination and can have stricter types than these high-level methods.
|
|
239
|
+
|
|
240
|
+
`setAutoWarp()` updates the supplied automatic-warp flags. `startWarp()`/`cancelWarp()` send warp actions; they do not await warp completion. Read `.state.destinationName`, auto-warp flags, and the ship's warp summary for observed state. `copy()`/`paste()` use the server's clipboard/configuration protocol.
|
|
241
|
+
|
|
242
|
+
## Fabricators
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
fabricator.panel(): PuiEvent | null;
|
|
246
|
+
fabricator.add(itemId: number, count?: number, index?: number): DredlessClient;
|
|
247
|
+
fabricator.sub(itemId: number, count?: number, index?: number): DredlessClient;
|
|
248
|
+
fabricator.clearQueue(): DredlessClient;
|
|
249
|
+
fabricator.toggleRepeat(): DredlessClient;
|
|
250
|
+
fabricator.lockResource(row: number): DredlessClient;
|
|
251
|
+
fabricator.unlockResource(row: number): DredlessClient;
|
|
252
|
+
fabricator.eject(row: number): DredlessClient;
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
These control the active fabricator UI. `add()` defaults to count 1/index -1; `sub()` defaults to count 1/index 0. Queue indexes and resource rows refer to the current UI, not entity IDs. Read the relevant panel first. All methods send immediately; observe PUI/model updates for results.
|
|
256
|
+
|
|
257
|
+
`.state`, `.progress`, `.active`, and `.craftingItem` expose decoded status. `FabricatorType` exports the named values `Starter`, `Munitions`, `Engineering`, and `Equipment` (lowercase string values) for fabricator categories. `panel()` reads the entity-keyed cached PUI; a cached panel does not itself prove that machine remains the active interaction.
|
|
258
|
+
|
|
259
|
+
## Signs and comms
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
sign.setText(text?: string, mode?: SignDisplayMode): DredlessClient;
|
|
263
|
+
commsStation.panel(): CommsEvent | null;
|
|
264
|
+
commsStation.sendMessage(message?: string): DredlessClient;
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Sign text and comms messages apply to their active interactions. Establish the intended interaction before writing. Pass an explicit named sign mode: the high-level sign setter currently defaults to numeric `0`, which the named-mode builder rejects. `SignDisplayMode.Always`, `WhenNear`, and `OnHover` have values `"always"`, `"when-near"`, and `"on-hover"`; read `.text`/`.mode` for decoded sign state. Sending a message/text is not a confirmed update.
|
|
268
|
+
|
|
269
|
+
## Hatches, ejectors, and clipboard settings
|
|
270
|
+
|
|
271
|
+
```ts
|
|
272
|
+
hatch.configure(config?: {filterMode?: LoaderFilterMode; filterSlots?: Array<number | null | undefined>}): DredlessClient;
|
|
273
|
+
hatch.copy(config?: {filterMode?: LoaderFilterMode; filterSlots?: Array<number | null | undefined>}): DredlessClient;
|
|
274
|
+
hatch.paste(config?: {filterMode?: LoaderFilterMode; filterSlots?: Array<number | null | undefined>}): DredlessClient;
|
|
275
|
+
hatch.setFilterMode(mode: LoaderFilterMode): DredlessClient;
|
|
276
|
+
hatch.setFilterItems(slots?: Array<number | null | undefined>): DredlessClient;
|
|
277
|
+
|
|
278
|
+
ejector.setDirection(direction: FixedAngleDirection): DredlessClient;
|
|
279
|
+
ejector.copy(direction?: FixedAngleDirection): DredlessClient;
|
|
280
|
+
ejector.paste(direction?: FixedAngleDirection): DredlessClient;
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Hatch full configuration/copy/paste also needs an explicit named `filterMode` to avoid the numeric-default enum limitation. Filter slots are three item IDs. Read hatch `.openFraction`/state for observed position.
|
|
284
|
+
|
|
285
|
+
`FixedAngleDirection.Right`, `Up`, `Left`, and `Down` are `"right"`, `"up"`, `"left"`, and `"down"`. Their wire order is **right 0, up 1, left 2, down 3**, which differs from [gravity](MANAGEMENT.md#gravity). Ejector copy/paste defaults to right; these operations send config/clipboard commands, not local copies.
|
|
286
|
+
|
|
287
|
+
Additional direct client clipboard helpers are `setGeneratorClipboardDirection(direction)`, `setExpandoClipboardAngle(degrees)`, and `setClipboardFixedAngle(target, direction)`. Expando angles must be integer degrees in `0–359`. Use [protocol/config builders](PROTOCOL.md#configuration-builders) for more clipboard controls; setters return immediately.
|
|
288
|
+
|
|
289
|
+
## Generators and read-only machine state
|
|
290
|
+
|
|
291
|
+
```ts
|
|
292
|
+
generator.solvePuzzle(solution: string | number): DredlessClient;
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Supply the solution as a digit string (at most 255 encoded bytes). Numeric arguments are converted to solution text; they are **not** interpreted as maze seeds, and cannot preserve leading zeros. Prefer strings. This targets the generator entity and sends without confirmation. `.state.puzzleSeed` and `.state.puzzleSolution` expose available puzzle data; [maze helpers](PROTOCOL.md#generator-maze-helpers) can compute a solution from a seed without sending.
|
|
296
|
+
|
|
297
|
+
| Handle | Useful reads |
|
|
298
|
+
|------------------|--------------------------------------------------------------------------|
|
|
299
|
+
| Cannon | Ammo, resources, indicator, spin/recoil, barrel angles |
|
|
300
|
+
| Thruster | `.state` |
|
|
301
|
+
| Helm | `.state`, `.occupied` |
|
|
302
|
+
| Shield projector | `.state`, `.active` |
|
|
303
|
+
| Fluid tank | `.state`, `.amount` |
|
|
304
|
+
| Expando-box | `.state`, `.item`, `.count` |
|
|
305
|
+
| Generator | Shield-generator `.state` |
|
|
306
|
+
| Ejector | `.state`, `.active`, `.progress` |
|
|
307
|
+
|
|
308
|
+
Cannon relative angle is radians from the mount. Absolute angle is ship-coordinate radians normalized to `[0, 2π)`; it needs both aim and mounting rotation. Missing inputs produce `null`. These fields replace raw `aim`; they do not expose a cannon aim setter.
|
|
309
|
+
|
|
310
|
+
Cannon resources and indicators are separate:
|
|
311
|
+
|
|
312
|
+
```ts
|
|
313
|
+
// Fields on CannonSummary (cannon.state)
|
|
314
|
+
resourceCount: number;
|
|
315
|
+
indicatorValue: number;
|
|
316
|
+
indicatorVisible: boolean;
|
|
317
|
+
indicatorColor: number | null;
|
|
318
|
+
indicatorBlinking: boolean;
|
|
319
|
+
indicatorBlinkColor: number | null;
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
`resourceCount` is the shared server count: burst charges on burst cannons,
|
|
323
|
+
cooling cells on machine cannons. It defaults to zero and is not clamped to the
|
|
324
|
+
number of markers the official client draws (three charges or two cells).
|
|
325
|
+
|
|
326
|
+
`indicatorValue` is the server's indicator scalar divided by 50; it defaults to
|
|
327
|
+
zero. It is not a charge count or a ready-to-fire flag. The official color mapping
|
|
328
|
+
is:
|
|
329
|
+
|
|
330
|
+
| Normalized value | Raw value | Appearance |
|
|
331
|
+
| --- | --- | --- |
|
|
332
|
+
| Below 1 | Below 50 | Hidden |
|
|
333
|
+
| 1 | 50 | Green |
|
|
334
|
+
| 2 | 100 | Yellow |
|
|
335
|
+
| 3 | 150 | Red |
|
|
336
|
+
| 4 | 200 | Alternating red/yellow |
|
|
337
|
+
|
|
338
|
+
Intermediate values interpolate green → yellow → red using the official
|
|
339
|
+
renderer's float32 calculations and integer channel truncation. Colors are packed
|
|
340
|
+
RGB numbers, without alpha. A hidden indicator has `indicatorColor: null`.
|
|
341
|
+
For value 4, `indicatorBlinking` is true, `indicatorColor` is red (`0xff0000`),
|
|
342
|
+
and `indicatorBlinkColor` is yellow (`0xffff00`). Consumers choose the display
|
|
343
|
+
phase; summaries do not change with local clock time. The official renderer uses
|
|
344
|
+
the fractional part of its time value: red below 0.5, yellow otherwise.
|
|
345
|
+
For nonblinking indicators, `indicatorBlinkColor` is null.
|
|
346
|
+
|
|
347
|
+
The misleading `charge`/`charged` fields and the type-specific `coolingCellCount`
|
|
348
|
+
name have been removed. Raw encoded values remain in `.state.state` (`q40` for
|
|
349
|
+
the indicator, `q56` for resources).
|
|
350
|
+
|
|
351
|
+
Summary progress, counts, health, occupancy, and raw model records vary by component; use the component's [declared summary](../src/index.d.ts) rather than assuming all machines share a progress scale or health convention.
|