pw-js-api 0.2.1 → 0.2.2-dev.8bac497

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 (49) hide show
  1. package/browser/pw.dev.js +162 -472
  2. package/browser/pw.prod.js +1 -1
  3. package/esm/api/PWApiClient.d.ts +182 -0
  4. package/esm/api/PWApiClient.js +247 -0
  5. package/esm/game/PWGameClient.d.ts +115 -0
  6. package/esm/game/PWGameClient.js +345 -0
  7. package/esm/gen/world_pb.d.ts +1301 -0
  8. package/esm/gen/world_pb.js +286 -0
  9. package/esm/index.d.ts +7 -0
  10. package/esm/index.js +10 -0
  11. package/esm/util/Bucket.d.ts +32 -0
  12. package/esm/util/Bucket.js +68 -0
  13. package/esm/util/Constants.d.ts +5 -0
  14. package/esm/util/Constants.js +6 -0
  15. package/esm/util/Errors.d.ts +4 -0
  16. package/esm/util/Errors.js +7 -0
  17. package/esm/util/Misc.d.ts +2 -0
  18. package/esm/util/Misc.js +51 -0
  19. package/esm/util/block.d.ts +1333 -0
  20. package/esm/util/block.js +1335 -0
  21. package/package.json +5 -6
  22. package/tsconfig-cm.json +8 -0
  23. package/tsconfig-esm.json +8 -0
  24. package/.npm-deprecaterc.json +0 -10
  25. package/buf.gen.yaml +0 -12
  26. package/esm.mjs +0 -18
  27. /package/{dist → cm}/api/PWApiClient.d.ts +0 -0
  28. /package/{dist → cm}/api/PWApiClient.js +0 -0
  29. /package/{dist → cm}/game/PWGameClient.d.ts +0 -0
  30. /package/{dist → cm}/game/PWGameClient.js +0 -0
  31. /package/{dist → cm}/gen/world_pb.d.ts +0 -0
  32. /package/{dist → cm}/gen/world_pb.js +0 -0
  33. /package/{dist → cm}/index.d.ts +0 -0
  34. /package/{dist → cm}/index.js +0 -0
  35. /package/{dist → cm}/util/Bucket.d.ts +0 -0
  36. /package/{dist → cm}/util/Bucket.js +0 -0
  37. /package/{dist → cm}/util/Constants.d.ts +0 -0
  38. /package/{dist → cm}/util/Constants.js +0 -0
  39. /package/{dist → cm}/util/Errors.d.ts +0 -0
  40. /package/{dist → cm}/util/Errors.js +0 -0
  41. /package/{dist → cm}/util/Misc.d.ts +0 -0
  42. /package/{dist → cm}/util/Misc.js +0 -0
  43. /package/{dist → cm}/util/block.d.ts +0 -0
  44. /package/{dist → cm}/util/block.js +0 -0
  45. /package/{dist → esm}/types/api.d.ts +0 -0
  46. /package/{dist → esm}/types/events.d.ts +0 -0
  47. /package/{dist → esm}/types/game.d.ts +0 -0
  48. /package/{dist → esm}/types/index.d.ts +0 -0
  49. /package/{dist → esm}/types/misc.d.ts +0 -0
@@ -0,0 +1,182 @@
1
+ import PWGameClient from "../game/PWGameClient.js";
2
+ import type { APIFailure, AuthResultSuccess, CollectionResult, ColPlayer, ColQuery, ColWorld, JoinKeyResult, LobbyResult } from "../types/api.js";
3
+ import type { GameClientSettings, WorldJoinData } from "../types/game.js";
4
+ /**
5
+ * Note if you want to join a world, use new PWGameClient() then run .init()
6
+ */
7
+ export default class PWApiClient {
8
+ /**
9
+ * The account token, this is private to prevent tampering.
10
+ */
11
+ private token?;
12
+ /**
13
+ * Account details with email and password, if applicable.
14
+ */
15
+ private account;
16
+ loggedIn: boolean;
17
+ /**
18
+ * This will create an instance of the class, as you're using the token, it will automatically be marked as loggedIn.
19
+ * @param token Must be a valid account token.
20
+ */
21
+ constructor(token: string);
22
+ /**
23
+ * This will create an instance of the class, as you're putting the account details, you must manually authenticate before invoking restricted calls including joinRoom.
24
+ * If populating email and password, you must manually authenticate yourself.
25
+ */
26
+ constructor(email: string, password: string);
27
+ /**
28
+ * Connects the API instance to the server.
29
+ * This will enable the client to join the room, or access to restricted collections.
30
+ */
31
+ authenticate(): Promise<AuthResultSuccess | APIFailure>;
32
+ /**
33
+ * Overrides local account details, the parameters are not needed if PW Api was already created with email/password in the first place.
34
+ * This is for those that used a token in the first place, the accounts won't be saved in the instance.
35
+ */
36
+ authenticate(email: string, password: string): Promise<AuthResultSuccess | APIFailure>;
37
+ /**
38
+ * Internal.
39
+ */
40
+ getJoinKey(roomType: string, roomId: string): Promise<JoinKeyResult>;
41
+ /**
42
+ * This route is available to take if you chose to create an API client to then join a world, in which case this returns the Game Client instance.
43
+ *
44
+ * Make sure the API client is already authenticated before calling this.
45
+ *
46
+ * The 3rd parameter is for if you wish to customise the reconnectability of the game client.
47
+ */
48
+ joinWorld(roomId: string, obj?: {
49
+ joinData?: WorldJoinData;
50
+ gameSettings?: Partial<GameClientSettings>;
51
+ }): Promise<PWGameClient<{}>>;
52
+ /**
53
+ * This will be an empty array if getRoomTypes has never been used successfully at least once.
54
+ */
55
+ static roomTypes: string[];
56
+ /**
57
+ * This will be an empty array if getRoomTypes has never been used successfully at least once.
58
+ */
59
+ get roomTypes(): string[];
60
+ /**
61
+ * Non-authenticated. This will refresh the room types each time, so make sure to check if roomTypes is available.
62
+ */
63
+ getRoomTypes(): Promise<string[]>;
64
+ /**
65
+ * Non-authenticated. This will refresh the room types each time, so make sure to check if roomTypes is available.
66
+ */
67
+ static getRoomTypes(): Promise<string[]>;
68
+ /**
69
+ * Non-authenticated. Returns the mappings from the game API.
70
+ *
71
+ * Note: This library also exports "BlockNames" which is an enum containing the block names along with their respective id.
72
+ */
73
+ getMappings(): Promise<Record<string, number>>;
74
+ /**
75
+ * Non-authenticated. Returns the mappings from the game API.
76
+ *
77
+ * Note: This library also exports "BlockNames" which is an enum containing the block names along with their respective id.
78
+ */
79
+ static getMappings(): Promise<Record<string, number>>;
80
+ /**
81
+ * Returns the collection result of the query - your own worlds.
82
+ * Default: page - 1, perPage - 10
83
+ */
84
+ getOwnedWorlds(page: number, perPage: number, query?: ColQuery<ColWorld>): Promise<CollectionResult<ColWorld>>;
85
+ getOwnedWorlds(query: ColQuery<ColWorld>): Promise<CollectionResult<ColWorld>>;
86
+ /**
87
+ * Returns the collection result of the query - players.
88
+ * Default: page - 1, perPage - 10
89
+ */
90
+ getPlayers(page: number, perPage: number, query?: ColQuery<ColPlayer>): Promise<CollectionResult<ColPlayer>>;
91
+ getPlayers(query: ColQuery<ColPlayer>): Promise<CollectionResult<ColPlayer>>;
92
+ /**
93
+ * Returns the collection result of the query - players.
94
+ * Default: page - 1, perPage - 10
95
+ */
96
+ static getPlayers(page: number, perPage: number, query?: ColQuery<ColPlayer>): Promise<CollectionResult<ColPlayer>>;
97
+ static getPlayers(query: ColQuery<ColPlayer>): Promise<CollectionResult<ColPlayer>>;
98
+ /**
99
+ * Returns the collection result of the query - public worlds.
100
+ * Default: page - 1, perPage - 10
101
+ */
102
+ getPublicWorlds(page: number, perPage: number, query?: ColQuery<ColWorld>): Promise<CollectionResult<ColWorld>>;
103
+ getPublicWorlds(query: ColQuery<ColWorld>): Promise<CollectionResult<ColWorld>>;
104
+ /**
105
+ * Returns the collection result of the query - public worlds.
106
+ * Default: page - 1, perPage - 10
107
+ */
108
+ static getPublicWorlds(page: number, perPage: number, query?: ColQuery<ColWorld>): Promise<CollectionResult<ColWorld>>;
109
+ static getPublicWorlds(query: ColQuery<ColWorld>): Promise<CollectionResult<ColWorld>>;
110
+ /**
111
+ * Returns the lobby result.
112
+ */
113
+ getVisibleWorlds(): Promise<LobbyResult>;
114
+ /**
115
+ * Returns the lobby result.
116
+ */
117
+ static getVisibleWorlds(): Promise<LobbyResult>;
118
+ /**
119
+ * Returns the world, if it exists and is public.
120
+ */
121
+ getPublicWorld(id: string): Promise<ColWorld | undefined>;
122
+ /**
123
+ * Returns the world, if it exists and is public.
124
+ */
125
+ static getPublicWorld(id: string): Promise<ColWorld | undefined>;
126
+ /**
127
+ * Gets the raw minimap bytes, the format may differ depending on the environment (Bun, NodeJS, Browser etc).
128
+ */
129
+ getMinimap(world: ColWorld | {
130
+ id: string;
131
+ minimap: string;
132
+ }, toURL?: false): Promise<Buffer>;
133
+ /**
134
+ * Gives the URL pointing to the minimap image.
135
+ */
136
+ getMinimap(world: ColWorld | {
137
+ id: string;
138
+ minimap: string;
139
+ }, toURL: true): string;
140
+ /**
141
+ * Gets the raw minimap bytes, the format may differ depending on the environment (Bun, NodeJS, Browser etc).
142
+ */
143
+ static getMinimap(world: ColWorld | {
144
+ id: string;
145
+ minimap: string;
146
+ }, toURL?: false): Promise<Buffer>;
147
+ /**
148
+ * Gives the URL pointing to the minimap image.
149
+ */
150
+ static getMinimap(world: ColWorld | {
151
+ id: string;
152
+ minimap: string;
153
+ }, toURL: true): string;
154
+ /**
155
+ * Note that username is cap sensitive, and may require you to use toUppercase
156
+ */
157
+ getPlayerByName(username: string): Promise<CollectionResult<ColPlayer>>;
158
+ /**
159
+ * Note that username is cap sensitive, and may require you to use toUppercase
160
+ */
161
+ static getPlayerByName(username: string): Promise<CollectionResult<ColPlayer>>;
162
+ /**
163
+ * IMPORTANT: This will return JSON for any responses that have the content-type of json, anything else will be sent back as Uint8array.
164
+ * If you're expecting raw bytes, make sure the endpoint is guaranteed to give you that otherwise there isn't a reason.
165
+ *
166
+ * This requires the manager to be authenticated, it will error if otherwise.
167
+ * @param url Requires to be a full URL with endpoint unfortunately. It will throw error if it doesn't match any of the 2 HTTP endpoint URLs.
168
+ * @param body If this is passed, the request will become a POST. (If you need to send a POST but has no data, just send an empty object).
169
+ * @param token The API token (not join key), this is if you wish to use authenticated API calls without having to instantise an api client yourself.
170
+ */
171
+ static request<T>(url: string, body?: Record<string, any> | string, token?: string): Promise<T>;
172
+ /**
173
+ * IMPORTANT: This will return JSON for any responses that have the content-type of json, anything else will be sent back as Uint8array.
174
+ * If you're expecting raw bytes, make sure the endpoint is guaranteed to give you that otherwise there isn't a reason.
175
+ *
176
+ * This requires the manager to be authenticated, it will error if otherwise.
177
+ * @param url Requires to be a full URL with endpoint unfortunately. It will throw error if it doesn't match any of the 2 HTTP endpoint URLs.
178
+ * @param body If this is passed, the request will become a POST. (If you need to send a POST but has no data, just send an empty object).
179
+ * @param isAuthenticated If true, this will send the token as the header.
180
+ */
181
+ protected request<T>(url: string, body?: Record<string, any> | string, isAuthenticated?: boolean): Promise<T>;
182
+ }
@@ -0,0 +1,247 @@
1
+ import PWGameClient from "../game/PWGameClient.js";
2
+ import { Endpoint } from "../util/Constants.js";
3
+ import { queryToString } from "../util/Misc.js";
4
+ /**
5
+ * Note if you want to join a world, use new PWGameClient() then run .init()
6
+ */
7
+ class PWApiClient {
8
+ constructor(email, password) {
9
+ /**
10
+ * Account details with email and password, if applicable.
11
+ */
12
+ this.account = {
13
+ email: "",
14
+ password: ""
15
+ };
16
+ this.loggedIn = false;
17
+ if (password === undefined) {
18
+ this.token = email;
19
+ this.loggedIn = true;
20
+ return;
21
+ }
22
+ this.account.email = email;
23
+ this.account.password = password;
24
+ // this.token = token;
25
+ }
26
+ authenticate(email, password) {
27
+ if (email === undefined) {
28
+ if (this.account.email.length === 0 || this.account.password.length === 0)
29
+ throw Error("No email/password given.");
30
+ email = this.account.email;
31
+ password = this.account.password;
32
+ }
33
+ return this.request(`${Endpoint.Api}/api/collections/users/auth-with-password`, { identity: email, password }).then(res => {
34
+ if ("token" in res) {
35
+ this.token = res.token;
36
+ this.loggedIn = true;
37
+ }
38
+ return res;
39
+ }); //.then(console.log);
40
+ }
41
+ /**
42
+ * Internal.
43
+ */
44
+ getJoinKey(roomType, roomId) {
45
+ return this.request(`${Endpoint.Api}/api/joinkey/${roomType}/${roomId}`, undefined, true);
46
+ }
47
+ /**
48
+ * This route is available to take if you chose to create an API client to then join a world, in which case this returns the Game Client instance.
49
+ *
50
+ * Make sure the API client is already authenticated before calling this.
51
+ *
52
+ * The 3rd parameter is for if you wish to customise the reconnectability of the game client.
53
+ */
54
+ joinWorld(roomId, obj) {
55
+ const game = new PWGameClient(this, obj === null || obj === void 0 ? void 0 : obj.gameSettings);
56
+ return game.joinWorld(roomId, obj === null || obj === void 0 ? void 0 : obj.joinData);
57
+ }
58
+ // I feel like this is cursed.
59
+ /**
60
+ * This will be an empty array if getRoomTypes has never been used successfully at least once.
61
+ */
62
+ get roomTypes() {
63
+ return PWApiClient.roomTypes;
64
+ }
65
+ /**
66
+ * Non-authenticated. This will refresh the room types each time, so make sure to check if roomTypes is available.
67
+ */
68
+ getRoomTypes() {
69
+ return PWApiClient.getRoomTypes();
70
+ }
71
+ /**
72
+ * Non-authenticated. This will refresh the room types each time, so make sure to check if roomTypes is available.
73
+ */
74
+ static getRoomTypes() {
75
+ return this.request(`${Endpoint.GameHTTP}/listroomtypes`)
76
+ .then(res => {
77
+ PWApiClient.roomTypes = res;
78
+ return res;
79
+ });
80
+ }
81
+ /**
82
+ * Non-authenticated. Returns the mappings from the game API.
83
+ *
84
+ * Note: This library also exports "BlockNames" which is an enum containing the block names along with their respective id.
85
+ */
86
+ getMappings() {
87
+ return PWApiClient.getMappings();
88
+ }
89
+ /**
90
+ * Non-authenticated. Returns the mappings from the game API.
91
+ *
92
+ * Note: This library also exports "BlockNames" which is an enum containing the block names along with their respective id.
93
+ */
94
+ static getMappings() {
95
+ return this.request(`${Endpoint.GameHTTP}/mappings`);
96
+ }
97
+ getOwnedWorlds(page = 1, perPage = 10, query) {
98
+ if (typeof page === "object") {
99
+ query = page;
100
+ page = 1;
101
+ }
102
+ return this.request(`${Endpoint.Api}/api/collections/worlds/records?page=${page}&perPage=${perPage}${queryToString(query)}`, undefined, true);
103
+ }
104
+ getPlayers(page = 1, perPage = 10, query) {
105
+ if (typeof page === "object") {
106
+ query = page;
107
+ page = 1;
108
+ }
109
+ return PWApiClient.getPlayers(page, perPage, query);
110
+ }
111
+ static getPlayers(page = 1, perPage = 10, query) {
112
+ if (typeof page === "object") {
113
+ query = page;
114
+ page = 1;
115
+ }
116
+ return this.request(`${Endpoint.Api}/api/collections/public_profiles/records?page=${page}&perPage=${perPage}${queryToString(query)}`);
117
+ }
118
+ getPublicWorlds(page = 1, perPage = 10, query) {
119
+ if (typeof page === "object") {
120
+ query = page;
121
+ page = 1;
122
+ }
123
+ return PWApiClient.getPublicWorlds(page, perPage, query);
124
+ }
125
+ static getPublicWorlds(page = 1, perPage = 10, query) {
126
+ if (typeof page === "object") {
127
+ query = page;
128
+ page = 1;
129
+ }
130
+ return this.request(`${Endpoint.Api}/api/collections/public_worlds/records?page=${page}&perPage=${perPage}${queryToString(query)}`);
131
+ }
132
+ /**
133
+ * Returns the lobby result.
134
+ */
135
+ getVisibleWorlds() {
136
+ return PWApiClient.getVisibleWorlds();
137
+ }
138
+ /**
139
+ * Returns the lobby result.
140
+ */
141
+ static getVisibleWorlds() {
142
+ if (this.roomTypes.length === 0)
143
+ throw Error("roomTypes is empty - use getRoomTypes first!");
144
+ return this.request(`${Endpoint.GameHTTP}/room/list/${this.roomTypes[0]}`);
145
+ }
146
+ /**
147
+ * Returns the world, if it exists and is public.
148
+ */
149
+ getPublicWorld(id) {
150
+ return PWApiClient.getPublicWorld(id);
151
+ }
152
+ /**
153
+ * Returns the world, if it exists and is public.
154
+ */
155
+ static getPublicWorld(id) {
156
+ return this.getPublicWorlds(1, 1, { filter: { id } })
157
+ .then(res => res.items[0]);
158
+ }
159
+ getMinimap(world, toURL = false) {
160
+ if (toURL)
161
+ return `${Endpoint.Api}/api/files/rhrbt6wqhc4s0cp/${world.id}/${world.minimap}`;
162
+ return PWApiClient.getMinimap(world, toURL);
163
+ }
164
+ static getMinimap(world, toURL = false) {
165
+ if (toURL)
166
+ return `${Endpoint.Api}/api/files/rhrbt6wqhc4s0cp/${world.id}/${world.minimap}`;
167
+ return this.request(this.getMinimap(world, true))
168
+ .then(res => {
169
+ if ("message" in res)
170
+ throw Error("Minimap doesn't exist, the world may be unlisted.");
171
+ return res;
172
+ });
173
+ }
174
+ /**
175
+ * Note that username is cap sensitive, and may require you to use toUppercase
176
+ */
177
+ getPlayerByName(username) {
178
+ return PWApiClient.getPlayerByName(username);
179
+ }
180
+ /**
181
+ * Note that username is cap sensitive, and may require you to use toUppercase
182
+ */
183
+ static getPlayerByName(username) {
184
+ return this.getPlayers(1, 1, { filter: { username } });
185
+ }
186
+ // This doesn't seem to work so I commented it out, not removing it as there might be an oversight idk
187
+ // getMessageTypes() {
188
+ // return this.request<string[]>(`${Endpoint.GameHTTP}/message_types`)
189
+ // .then(res => res instanceof Uint8Array ? [] : res ?? []);
190
+ // }
191
+ /**
192
+ * IMPORTANT: This will return JSON for any responses that have the content-type of json, anything else will be sent back as Uint8array.
193
+ * If you're expecting raw bytes, make sure the endpoint is guaranteed to give you that otherwise there isn't a reason.
194
+ *
195
+ * This requires the manager to be authenticated, it will error if otherwise.
196
+ * @param url Requires to be a full URL with endpoint unfortunately. It will throw error if it doesn't match any of the 2 HTTP endpoint URLs.
197
+ * @param body If this is passed, the request will become a POST. (If you need to send a POST but has no data, just send an empty object).
198
+ * @param token The API token (not join key), this is if you wish to use authenticated API calls without having to instantise an api client yourself.
199
+ */
200
+ static request(url, body, token) {
201
+ if (!(url.startsWith(Endpoint.Api) || url.startsWith(Endpoint.GameHTTP)))
202
+ throw Error("URL given does not have the correct endpoint URL, this is for safety.");
203
+ const headers = {
204
+ // "user-agent": "PW-TS-API/0.0.1"
205
+ };
206
+ if (typeof token === "string")
207
+ headers["authorization"] = token;
208
+ if (typeof body === "object")
209
+ body = JSON.stringify(body);
210
+ let method = "GET";
211
+ if (typeof body !== "undefined") {
212
+ headers["content-type"] = "application/json";
213
+ method = "POST";
214
+ }
215
+ return fetch(url, {
216
+ headers, method,
217
+ body: body
218
+ }).then(res => {
219
+ var _a;
220
+ if (res.status === 403)
221
+ throw Error("Forbidden access - token invalid or unauthorised.");
222
+ // else if (res.status !== 200) throw Error("")
223
+ if ((_a = res.headers.get("content-type")) === null || _a === void 0 ? void 0 : _a.startsWith("application/json"))
224
+ return res.json();
225
+ else
226
+ return res.arrayBuffer();
227
+ });
228
+ }
229
+ /**
230
+ * IMPORTANT: This will return JSON for any responses that have the content-type of json, anything else will be sent back as Uint8array.
231
+ * If you're expecting raw bytes, make sure the endpoint is guaranteed to give you that otherwise there isn't a reason.
232
+ *
233
+ * This requires the manager to be authenticated, it will error if otherwise.
234
+ * @param url Requires to be a full URL with endpoint unfortunately. It will throw error if it doesn't match any of the 2 HTTP endpoint URLs.
235
+ * @param body If this is passed, the request will become a POST. (If you need to send a POST but has no data, just send an empty object).
236
+ * @param isAuthenticated If true, this will send the token as the header.
237
+ */
238
+ request(url, body, isAuthenticated = false) {
239
+ return PWApiClient.request(url, body, isAuthenticated ? this.token : undefined);
240
+ }
241
+ }
242
+ /**
243
+ * This will be an empty array if getRoomTypes has never been used successfully at least once.
244
+ */
245
+ PWApiClient.roomTypes = [];
246
+ export default PWApiClient;
247
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUFdBcGlDbGllbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9saWIvYXBpL1BXQXBpQ2xpZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sWUFBWSxNQUFNLHlCQUF5QixDQUFDO0FBR25ELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNoRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFaEQ7O0dBRUc7QUFDSCxNQUFxQixXQUFXO0lBMEI1QixZQUFZLEtBQWEsRUFBRSxRQUFpQjtRQXBCNUM7O1dBRUc7UUFDSyxZQUFPLEdBQUc7WUFDZCxLQUFLLEVBQUUsRUFBRTtZQUNULFFBQVEsRUFBRSxFQUFFO1NBQ2YsQ0FBQTtRQUVELGFBQVEsR0FBRyxLQUFLLENBQUM7UUFhYixJQUFJLFFBQVEsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUN6QixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztZQUNuQixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztZQUNyQixPQUFPO1FBQ1gsQ0FBQztRQUVELElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztRQUMzQixJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7UUFFakMsc0JBQXNCO0lBQzFCLENBQUM7SUFZRCxZQUFZLENBQUMsS0FBYyxFQUFFLFFBQWlCO1FBQzFDLElBQUksS0FBSyxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3RCLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUMsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNLEtBQUssQ0FBQztnQkFBRSxNQUFNLEtBQUssQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO1lBRW5ILEtBQUssR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQztZQUMz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
@@ -0,0 +1,115 @@
1
+ import type PWApiClient from "../api/PWApiClient.js";
2
+ import { type PlayerChatPacket, type WorldBlockFilledPacket, type WorldBlockPlacedPacket } from "../gen/world_pb.js";
3
+ import type { GameClientSettings, WorldJoinData, Hook } from "../types/game.js";
4
+ import type { CustomBotEvents, MergedEvents, WorldEvents } from "../types/events.js";
5
+ import Bucket from "../util/Bucket.js";
6
+ import type { OmitRecursively, Optional, Promisable } from "../types/misc.js";
7
+ type SafeCheck<K extends keyof MergedEvents, State extends Partial<{
8
+ [K in keyof MergedEvents]: any;
9
+ }>> = State extends CustomBotEvents ? never : State[K];
10
+ export default class PWGameClient<StateT extends Partial<{
11
+ [K in keyof WorldEvents]: never;
12
+ }> = {}> {
13
+ settings: GameClientSettings;
14
+ api?: PWApiClient;
15
+ socket?: WebSocket;
16
+ private prevWorldId?;
17
+ protected totalBucket: Bucket;
18
+ protected chatBucket: Bucket;
19
+ protected connectAttempts: {
20
+ time: number;
21
+ count: number;
22
+ };
23
+ /**
24
+ * NOTE: After constructing, you must then run .init() to connect the API IF you're using email/password.
25
+ */
26
+ constructor(api: PWApiClient, settings?: Partial<GameClientSettings>);
27
+ constructor(settings?: Partial<GameClientSettings>);
28
+ get connected(): boolean;
29
+ /**
30
+ * This will connect to the world.
31
+ *
32
+ * (This returns itself for chaining)
33
+ */
34
+ joinWorld(roomId: string, joinData?: WorldJoinData): Promise<this>;
35
+ /**
36
+ * INTERNAL
37
+ */
38
+ private createSocket;
39
+ /**
40
+ * This is a more direct route if you already have a join key acquired via Pixelwalker's API.
41
+ *
42
+ * Useful for those wary of security.
43
+ */
44
+ static joinWorld(joinKey: string, obj?: {
45
+ joinData?: WorldJoinData;
46
+ gameSettings?: Partial<GameClientSettings>;
47
+ }): Promise<PWGameClient>;
48
+ /**
49
+ * For faster performance (even if it seems insignificant),
50
+ * direct functions are used instead of events which are also inconsistent with browsers/nodejs etc.
51
+ *
52
+ * NOTE: the "this" won't be the client itself. You will need to bind yourself if you want to keep this.
53
+ */
54
+ protected callbacks: Partial<{ [K in keyof MergedEvents]: Array<(data: MergedEvents[K], states?: SafeCheck<K, StateT>) => Promisable<void | "STOP">>; }>;
55
+ /**
56
+ * Poorly documented because I cba
57
+ */
58
+ private hooks;
59
+ /**
60
+ * This is different to addCallback as all hooks (regardless of the type) will execute first before the callbacks, each hook may modify something or do something in the background
61
+ * and may pass it to callbacks (via the second parameter in callbacks). If an error occurs while executing one of the hooks,
62
+ * the execution of hooks will halt for that packet and callbacks will run without the states.
63
+ *
64
+ * NOTE: This is permanent, if a hook is added, it can't be removed.
65
+ */
66
+ addHook<HookState extends Pick<Partial<{
67
+ [K in keyof WorldEvents]: any;
68
+ }>, keyof WorldEvents>>(hook: Hook<HookState>): PWGameClient<StateT & HookState>;
69
+ /**
70
+ * Adds a listener for the event type, it can even be a promise too.
71
+ *
72
+ * If the callback returns a specific string "STOP", it will prevent further listeners from being invoked.
73
+ */
74
+ addCallback<Event extends keyof CustomBotEvents>(type: Event, ...cbs: Array<(data: MergedEvents[Event]) => Promisable<void | "STOP">>): this;
75
+ addCallback<Event extends keyof WorldEvents>(type: Event, ...cbs: Array<(data: MergedEvents[Event], states?: SafeCheck<Event, StateT>) => Promisable<void | "STOP">>): this;
76
+ /**
77
+ * Adds a listener for the event type, it can even be a promise too.
78
+ *
79
+ * If the callback returns a specific string "STOP", it will prevent further listeners from being invoked.
80
+ */
81
+ prependCallback<Event extends keyof CustomBotEvents>(type: Event, ...cbs: Array<(data: MergedEvents[Event]) => Promisable<void | "STOP">>): this;
82
+ prependCallback<Event extends keyof WorldEvents>(type: Event, ...cbs: Array<(data: MergedEvents[Event], states?: SafeCheck<Event, StateT>) => Promisable<void | "STOP">>): this;
83
+ /**
84
+ * @param type The type of the event
85
+ * @param cb It can be the function itself (to remove that specific function). If undefined, it will remove ALL functions from that list, it will return undefined.
86
+ */
87
+ removeCallback<Event extends keyof MergedEvents>(type: Event, cb?: (data: MergedEvents[Event], states: SafeCheck<Event, StateT>) => Promisable<void | "STOP">): undefined | ((data: MergedEvents[Event], states: SafeCheck<Event, StateT>) => Promisable<void | "STOP">);
88
+ /**
89
+ * INTERNAL. Invokes all functions of a callback type, unless one of them prohibits in transit.
90
+ */
91
+ protected invoke<Event extends keyof CustomBotEvents>(type: Event, data: MergedEvents[Event]): Promise<{
92
+ count: number;
93
+ stopped: boolean;
94
+ }>;
95
+ protected invoke<Event extends keyof WorldEvents>(type: Event, data: MergedEvents[Event], states: SafeCheck<Event, StateT>): Promise<{
96
+ count: number;
97
+ stopped: boolean;
98
+ }>;
99
+ /**
100
+ * This assumes that the connection
101
+ *
102
+ * @param type Type of the packet.
103
+ * @param value Value of the packet to send along with, note that some properties are optional.
104
+ * @param direct If it should skip queue.
105
+ */
106
+ send<Event extends keyof WorldEvents>(type: Event, value?: OmitRecursively<Sendable<Event, WorldEvents>, "$typeName" | "$unknown">, direct?: boolean): void;
107
+ /**
108
+ * By default this will set the game client settings reconnectable to false.
109
+ *
110
+ * If reconnect is true, an additionl parameter can be passed which is the amount of time to wait before it attempts to reconnect (DEFAULT: none)
111
+ */
112
+ disconnect(reconnect?: number | boolean): boolean;
113
+ }
114
+ type Sendable<E extends keyof WorldEvents, WE extends WorldEvents> = E extends "worldBlockPlacedPacket" ? Optional<WorldBlockPlacedPacket, "extraFields"> : E extends "WorldBlockFilledPacket" ? Optional<WorldBlockFilledPacket, "extraFields"> : E extends "playerChatPacket" ? Omit<PlayerChatPacket, "playerId"> : WE[E];
115
+ export {};