dredless 0.3.1 → 0.5.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/dist/browser/dredless.global.js +59 -2
- package/dist/browser/dredless.global.js.map +3 -3
- package/docs/API_REFERENCE.md +5 -8
- package/docs/BROWSER_API.md +2 -0
- package/docs/NODE_API.md +16 -1
- package/package.json +1 -1
- package/src/browser.d.ts +3 -1
- package/src/browser.js +4 -2
- package/src/client/core.js +1 -1
- package/src/index.d.ts +15 -8
- package/src/index.js +3 -1
- package/src/network/index.js +1 -1
- package/src/network/servers.d.ts +2 -0
- package/src/network/servers.js +59 -2
package/docs/API_REFERENCE.md
CHANGED
|
@@ -60,16 +60,13 @@ Both runtime entrypoints re-export world/model classes, protocol builders, confi
|
|
|
60
60
|
|
|
61
61
|
### `Server`
|
|
62
62
|
|
|
63
|
-
Returned by `fetchServers()`.
|
|
63
|
+
Returned by `fetchServers()`. Player counts and ping are returned separately by `fetchServerStatus()` or `fetchServerStatuses()`.
|
|
64
64
|
|
|
65
65
|
```ts
|
|
66
66
|
interface Server {
|
|
67
67
|
index: number;
|
|
68
68
|
domain: string;
|
|
69
69
|
description: string;
|
|
70
|
-
playerCount: number;
|
|
71
|
-
maxPlayerCount: number;
|
|
72
|
-
ping: number | null;
|
|
73
70
|
}
|
|
74
71
|
```
|
|
75
72
|
|
|
@@ -322,7 +319,7 @@ interface ClientSnapshot {
|
|
|
322
319
|
currentWorldId: number | null;
|
|
323
320
|
worlds: WorldSnapshot[];
|
|
324
321
|
cpuLoad: number | null;
|
|
325
|
-
inventory: InventoryState
|
|
322
|
+
inventory: InventoryState;
|
|
326
323
|
puiPanels: PuiEvent[];
|
|
327
324
|
commsPanels: CommsEvent[];
|
|
328
325
|
currentCommsPanel: CommsEvent | null;
|
|
@@ -493,7 +490,7 @@ const EquipmentSlot = { Head: "head", Face: "face", Body: "body", Back: "back",
|
|
|
493
490
|
type EquipmentSlot = typeof EquipmentSlot[keyof typeof EquipmentSlot];
|
|
494
491
|
|
|
495
492
|
interface InventoryDomain {
|
|
496
|
-
state(): InventoryState
|
|
493
|
+
state(): InventoryState;
|
|
497
494
|
hotbarSize(): number;
|
|
498
495
|
allSlots(): InventorySlotHandle[];
|
|
499
496
|
slot(ref: InventorySlotRef): InventorySlotHandle;
|
|
@@ -1320,7 +1317,7 @@ interface HelmHandle extends MachineHandle {
|
|
|
1320
1317
|
occupied: boolean | undefined;
|
|
1321
1318
|
}
|
|
1322
1319
|
|
|
1323
|
-
interface DoorHandle extends
|
|
1320
|
+
interface DoorHandle extends EntityHandle {
|
|
1324
1321
|
state: DoorSummary | null;
|
|
1325
1322
|
rank: number | undefined;
|
|
1326
1323
|
open: boolean | undefined;
|
|
@@ -2131,7 +2128,7 @@ chat-command path used by its chat commands, so client.sendChatMessage() can
|
|
|
2131
2128
|
send executable chat commands as well as ordinary chat text. For example:
|
|
2132
2129
|
|
|
2133
2130
|
```js
|
|
2134
|
-
client.sendChatMessage("/
|
|
2131
|
+
client.sendChatMessage("/save");
|
|
2135
2132
|
```
|
|
2136
2133
|
|
|
2137
2134
|
### Comms helpers
|
package/docs/BROWSER_API.md
CHANGED
|
@@ -41,6 +41,8 @@ interface DredlessBrowserNamespace {
|
|
|
41
41
|
fetchNoticeVersion: typeof fetchNoticeVersion;
|
|
42
42
|
fetchGameVersion: typeof fetchGameVersion;
|
|
43
43
|
fetchServers: typeof fetchServers;
|
|
44
|
+
fetchServerStatus: typeof fetchServerStatus;
|
|
45
|
+
fetchServerStatuses: typeof fetchServerStatuses;
|
|
44
46
|
fetchShips: typeof fetchShips;
|
|
45
47
|
fetchShipList: typeof fetchShipList;
|
|
46
48
|
joinShip: typeof joinShip;
|
package/docs/NODE_API.md
CHANGED
|
@@ -108,7 +108,22 @@ Scrapes the current game version string from the site.
|
|
|
108
108
|
function fetchServers(): Promise<Server[]>;
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
-
Scrapes and returns
|
|
111
|
+
Scrapes and returns game servers.
|
|
112
|
+
### `Dredless.fetchServerStatus(server)`
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
function fetchServerStatus(server: ServerRef): Promise<{ playerCount: number; maxPlayerCount: number; ping: number }>;
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Pings the server and returns the current player counts and measured response time in milliseconds.
|
|
119
|
+
|
|
120
|
+
### `Dredless.fetchServerStatuses()`
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
function fetchServerStatuses(): Promise<Server[]>;
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Fetches status for every server and returns server objects with updated `playerCount`, `maxPlayerCount`, and `ping` fields.
|
|
112
127
|
|
|
113
128
|
### `Dredless.fetchShips(session, server)`
|
|
114
129
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dredless",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.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",
|
package/src/browser.d.ts
CHANGED
|
@@ -76,6 +76,8 @@ export {
|
|
|
76
76
|
decompressLz4Frame,
|
|
77
77
|
fetchNoticeVersion,
|
|
78
78
|
fetchGameVersion,
|
|
79
|
+
fetchServerStatus,
|
|
80
|
+
fetchServerStatuses,
|
|
79
81
|
fetchServers
|
|
80
82
|
} from "./index.js";
|
|
81
83
|
|
|
@@ -199,7 +201,7 @@ export interface DredlessBrowserNamespace {
|
|
|
199
201
|
fetchAccountStatus: typeof fetchAccountStatus;
|
|
200
202
|
fetchNoticeVersion: typeof import("./index.js").fetchNoticeVersion;
|
|
201
203
|
fetchGameVersion: typeof import("./index.js").fetchGameVersion;
|
|
202
|
-
fetchServers: typeof import("./index.js").fetchServers;
|
|
204
|
+
fetchServers: typeof import("./index.js").fetchServers;`r`n fetchServerStatus: typeof import("./index.js").fetchServerStatus;`r`n fetchServerStatuses: typeof import("./index.js").fetchServerStatuses;
|
|
203
205
|
fetchShips: typeof fetchShips;
|
|
204
206
|
fetchShipList: typeof fetchShipList;
|
|
205
207
|
joinShip: typeof joinShip;
|
package/src/browser.js
CHANGED
|
@@ -66,7 +66,7 @@ export {
|
|
|
66
66
|
} from "./protocol/outbound/ui-config.js";
|
|
67
67
|
export {decryptPayload} from "./crypto/chacha.js";
|
|
68
68
|
export {decompressLz4Frame} from "./compression/lz4.js";
|
|
69
|
-
export {fetchNoticeVersion, fetchGameVersion, fetchServers} from "./network/servers.js";
|
|
69
|
+
export {fetchNoticeVersion, fetchGameVersion, fetchServerStatus, fetchServerStatuses, fetchServers} from "./network/servers.js";
|
|
70
70
|
export {fetchShips as fetchShipsWithSession, fetchShipList as fetchShipListWithSession} from "./network/ships.js";
|
|
71
71
|
export {
|
|
72
72
|
BrowserSession,
|
|
@@ -88,7 +88,7 @@ export {
|
|
|
88
88
|
|
|
89
89
|
import {Connection} from "./network/connection.js";
|
|
90
90
|
import {DredlessClient} from "./client/index.js";
|
|
91
|
-
import {fetchGameVersion, fetchNoticeVersion, fetchServers} from "./network/servers.js";
|
|
91
|
+
import {fetchGameVersion, fetchNoticeVersion, fetchServerStatus, fetchServerStatuses, fetchServers} from "./network/servers.js";
|
|
92
92
|
import {
|
|
93
93
|
BrowserSession,
|
|
94
94
|
browserSession,
|
|
@@ -121,6 +121,8 @@ export const DredlessBrowser = {
|
|
|
121
121
|
fetchAccountStatus,
|
|
122
122
|
fetchNoticeVersion,
|
|
123
123
|
fetchGameVersion,
|
|
124
|
+
fetchServerStatus,
|
|
125
|
+
fetchServerStatuses,
|
|
124
126
|
fetchServers,
|
|
125
127
|
fetchShips,
|
|
126
128
|
fetchShipList: fetchShipListForBrowser,
|
package/src/client/core.js
CHANGED
|
@@ -144,7 +144,7 @@ export class DredlessClient extends EventBus {
|
|
|
144
144
|
this.inventory = new InventoryDomain(this);
|
|
145
145
|
this.management = new ShipManagementDomain(this);
|
|
146
146
|
this.cpuLoad = null;
|
|
147
|
-
this.inventoryState =
|
|
147
|
+
this.inventoryState = normalizeInventoryEvent({type: "inventory", general_slots: 5});
|
|
148
148
|
this.puiPanels = new Map();
|
|
149
149
|
this.commsPanels = new Map();
|
|
150
150
|
this.currentCommsPanel = null;
|
package/src/index.d.ts
CHANGED
|
@@ -2,9 +2,6 @@ export interface Server {
|
|
|
2
2
|
index: number;
|
|
3
3
|
domain: string;
|
|
4
4
|
description: string;
|
|
5
|
-
playerCount: number;
|
|
6
|
-
maxPlayerCount: number;
|
|
7
|
-
ping: number | null;
|
|
8
5
|
}
|
|
9
6
|
|
|
10
7
|
export interface Ship {
|
|
@@ -31,6 +28,12 @@ export type ShipSpec =
|
|
|
31
28
|
| { type: "new"; name?: string | null; color?: string | null }
|
|
32
29
|
| { type: "invite"; code: string };
|
|
33
30
|
|
|
31
|
+
export interface ServerStatus {
|
|
32
|
+
playerCount: number;
|
|
33
|
+
maxPlayerCount: number;
|
|
34
|
+
ping: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
34
37
|
export type ServerRef = number | Server;
|
|
35
38
|
export type ShipRef = number | string | Ship | ShipSpec | null;
|
|
36
39
|
export type ShipPrivacy = 0 | 1 | boolean | "public" | "private";
|
|
@@ -612,7 +615,7 @@ export interface ShipManagementDomain {
|
|
|
612
615
|
}
|
|
613
616
|
|
|
614
617
|
export interface InventoryDomain {
|
|
615
|
-
state(): InventoryState
|
|
618
|
+
state(): InventoryState;
|
|
616
619
|
|
|
617
620
|
hotbarSize(): number;
|
|
618
621
|
|
|
@@ -1114,7 +1117,7 @@ export interface HelmHandle extends MachineHandle {
|
|
|
1114
1117
|
occupied: boolean | undefined;
|
|
1115
1118
|
}
|
|
1116
1119
|
|
|
1117
|
-
export interface DoorHandle extends
|
|
1120
|
+
export interface DoorHandle extends EntityHandle {
|
|
1118
1121
|
state: DoorSummary | null;
|
|
1119
1122
|
rank: number | undefined;
|
|
1120
1123
|
open: boolean | undefined;
|
|
@@ -1180,7 +1183,7 @@ export interface ClientSnapshot {
|
|
|
1180
1183
|
currentWorldId: number | null;
|
|
1181
1184
|
worlds: WorldSnapshot[];
|
|
1182
1185
|
cpuLoad: number | null;
|
|
1183
|
-
inventory: InventoryState
|
|
1186
|
+
inventory: InventoryState;
|
|
1184
1187
|
puiPanels: PuiEvent[];
|
|
1185
1188
|
commsPanels: CommsEvent[];
|
|
1186
1189
|
currentCommsPanel: CommsEvent | null;
|
|
@@ -1763,7 +1766,6 @@ export interface BotSummary {
|
|
|
1763
1766
|
export interface FabricatorSummary {
|
|
1764
1767
|
entity: number;
|
|
1765
1768
|
type: FabricatorType | null;
|
|
1766
|
-
typeIndex: number | null;
|
|
1767
1769
|
typeIndex: number | null;
|
|
1768
1770
|
state: ModelRecord;
|
|
1769
1771
|
rows: { itemId: number | null; itemName: string | null; count: number | null }[];
|
|
@@ -2249,6 +2251,10 @@ export function fetchGameVersion(): Promise<string>;
|
|
|
2249
2251
|
|
|
2250
2252
|
export function fetchServers(): Promise<Server[]>;
|
|
2251
2253
|
|
|
2254
|
+
export function fetchServerStatus(server: ServerRef): Promise<ServerStatus>;
|
|
2255
|
+
|
|
2256
|
+
export function fetchServerStatuses(): Promise<(Server & ServerStatus)[]>;
|
|
2257
|
+
|
|
2252
2258
|
export function fetchShips(session: Session, server: ServerRef): Promise<Ship[]>;
|
|
2253
2259
|
|
|
2254
2260
|
export function fetchShipList(session: Session, server: ServerRef): Promise<ShipList>;
|
|
@@ -2274,6 +2280,8 @@ export interface DredlessNamespace {
|
|
|
2274
2280
|
fetchNoticeVersion: typeof fetchNoticeVersion;
|
|
2275
2281
|
fetchGameVersion: typeof fetchGameVersion;
|
|
2276
2282
|
fetchServers: typeof fetchServers;
|
|
2283
|
+
fetchServerStatus: typeof fetchServerStatus;
|
|
2284
|
+
fetchServerStatuses: typeof fetchServerStatuses;
|
|
2277
2285
|
fetchShips: typeof fetchShips;
|
|
2278
2286
|
fetchShipList: typeof fetchShipList;
|
|
2279
2287
|
joinShip: typeof joinShip;
|
|
@@ -2281,6 +2289,5 @@ export interface DredlessNamespace {
|
|
|
2281
2289
|
startNewShip: typeof startNewShip;
|
|
2282
2290
|
joinInvite: typeof joinInvite;
|
|
2283
2291
|
}
|
|
2284
|
-
|
|
2285
2292
|
export const Dredless: DredlessNamespace;
|
|
2286
2293
|
export default Dredless;
|
package/src/index.js
CHANGED
|
@@ -81,7 +81,7 @@ export {decompressLz4Frame} from "./compression/lz4.js";
|
|
|
81
81
|
import {AnonSession, createAnonSession, createAnonToken, createSession, Session} from "./network/session.js";
|
|
82
82
|
import {Connection} from "./network/connection.js";
|
|
83
83
|
import {DredlessClient} from "./client/index.js";
|
|
84
|
-
import {fetchGameVersion, fetchNoticeVersion, fetchServers} from "./network/servers.js";
|
|
84
|
+
import {fetchGameVersion, fetchNoticeVersion, fetchServerStatus, fetchServerStatuses, fetchServers} from "./network/servers.js";
|
|
85
85
|
import {fetchShipList, fetchShips} from "./network/ships.js";
|
|
86
86
|
|
|
87
87
|
async function sessionOrAnon(session) {
|
|
@@ -114,6 +114,8 @@ export const Dredless = {
|
|
|
114
114
|
createAnonToken,
|
|
115
115
|
fetchNoticeVersion,
|
|
116
116
|
fetchGameVersion,
|
|
117
|
+
fetchServerStatus,
|
|
118
|
+
fetchServerStatuses,
|
|
117
119
|
fetchServers,
|
|
118
120
|
fetchShips,
|
|
119
121
|
fetchShipList,
|
package/src/network/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export {Connection} from "./connection.js";
|
|
2
|
-
export {fetchGameVersion, fetchNoticeVersion, fetchServers, resolveServer} from "./servers.js";
|
|
2
|
+
export {fetchGameVersion, fetchNoticeVersion, fetchServerStatus, fetchServerStatuses, fetchServers, resolveServer} from "./servers.js";
|
|
3
3
|
export {fetchShips, fetchShipList, createShipSpec, createInviteShipSpec, shipRef} from "./ships.js";
|
|
4
4
|
export {Session, AnonSession, createSession, createAnonSession, createAnonToken} from "./session.js";
|
package/src/network/servers.d.ts
CHANGED
package/src/network/servers.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {DEFAULT_BASE_URL} from "../constants.js";
|
|
2
|
-
import {hostName, normalizeBaseUrl} from "../runtime.js";
|
|
2
|
+
import {getWebSocket, hostName, normalizeBaseUrl} from "../runtime.js";
|
|
3
3
|
import {HttpClient} from "./http.js";
|
|
4
4
|
|
|
5
5
|
const cache = new Map();
|
|
@@ -56,6 +56,56 @@ class ServerDirectory {
|
|
|
56
56
|
|
|
57
57
|
export const fetchGameVersion = (baseUrl = DEFAULT_BASE_URL) => new ServerDirectory(baseUrl).version();
|
|
58
58
|
export const fetchServers = (baseUrl = DEFAULT_BASE_URL) => new ServerDirectory(baseUrl).servers();
|
|
59
|
+
export async function fetchServerStatus(server, baseUrl = DEFAULT_BASE_URL) {
|
|
60
|
+
const resolved = await resolveServer(server, baseUrl);
|
|
61
|
+
if (!resolved?.domain) throw new Error(`Unable to resolve server ${serverId(server)}`);
|
|
62
|
+
const WebSocket = await getWebSocket();
|
|
63
|
+
const startedAt = Date.now();
|
|
64
|
+
const socket = new WebSocket(`wss://${resolved.domain}:4000/`);
|
|
65
|
+
|
|
66
|
+
return new Promise((resolve, reject) => {
|
|
67
|
+
let settled = false;
|
|
68
|
+
const finish = (callback, value) => {
|
|
69
|
+
if (settled) return;
|
|
70
|
+
settled = true;
|
|
71
|
+
clearTimeout(timeout);
|
|
72
|
+
callback(value);
|
|
73
|
+
if (socket.readyState === 0 || socket.readyState === 1) socket.close();
|
|
74
|
+
};
|
|
75
|
+
const timeout = setTimeout(() => finish(reject, new Error(`Timed out fetching status for ${resolved.domain}`)), 10000);
|
|
76
|
+
const onOpen = () => socket.send("yo");
|
|
77
|
+
const onMessage = async (event) => {
|
|
78
|
+
try {
|
|
79
|
+
const data = JSON.parse(await websocketText(event?.data ?? event));
|
|
80
|
+
const playerCount = Number(data.player_count);
|
|
81
|
+
const maxPlayerCount = Number(data.player_max);
|
|
82
|
+
if (!Number.isFinite(playerCount) || !Number.isFinite(maxPlayerCount)) throw new Error("Invalid server status response");
|
|
83
|
+
finish(resolve, {playerCount, maxPlayerCount, ping: Date.now() - startedAt});
|
|
84
|
+
} catch (error) {
|
|
85
|
+
finish(reject, new Error(`Invalid status response from ${resolved.domain}: ${error.message}`));
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const onError = (event) => finish(reject, event?.error || new Error(`WebSocket error while fetching ${resolved.domain}`));
|
|
89
|
+
if (typeof socket.on === "function") {
|
|
90
|
+
socket.on("open", onOpen);
|
|
91
|
+
socket.on("message", onMessage);
|
|
92
|
+
socket.on("error", onError);
|
|
93
|
+
} else if (typeof socket.addEventListener === "function") {
|
|
94
|
+
socket.addEventListener("open", onOpen);
|
|
95
|
+
socket.addEventListener("message", onMessage);
|
|
96
|
+
socket.addEventListener("error", onError);
|
|
97
|
+
} else {
|
|
98
|
+
socket.onopen = onOpen;
|
|
99
|
+
socket.onmessage = onMessage;
|
|
100
|
+
socket.onerror = onError;
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export async function fetchServerStatuses(baseUrl = DEFAULT_BASE_URL) {
|
|
106
|
+
const servers = await fetchServers(baseUrl);
|
|
107
|
+
return Promise.all(servers.map(async (server) => ({...server, ...await fetchServerStatus(server, baseUrl)})));
|
|
108
|
+
}
|
|
59
109
|
|
|
60
110
|
export async function fetchNoticeVersion(baseUrl = DEFAULT_BASE_URL) {
|
|
61
111
|
const response = await new HttpClient({baseUrl}).request("index.html");
|
|
@@ -128,6 +178,13 @@ function parseServerInfo(text, baseUrl) {
|
|
|
128
178
|
};
|
|
129
179
|
}
|
|
130
180
|
|
|
181
|
+
async function websocketText(data) {
|
|
182
|
+
if (typeof data === "string") return data;
|
|
183
|
+
if (data instanceof ArrayBuffer) return new TextDecoder().decode(data);
|
|
184
|
+
if (ArrayBuffer.isView(data)) return new TextDecoder().decode(data);
|
|
185
|
+
if (typeof data?.text === "function") return data.text();
|
|
186
|
+
return String(data);
|
|
187
|
+
}
|
|
131
188
|
function server(index, domain, description) {
|
|
132
|
-
return {index, domain, description
|
|
189
|
+
return {index, domain, description};
|
|
133
190
|
}
|