pw-js-world 0.0.4 → 0.0.5-dev.24aedef

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/lib/Constants.ts DELETED
@@ -1,4 +0,0 @@
1
- export enum LayerType {
2
- Background,
3
- Foreground
4
- }
package/lib/Helper.ts DELETED
@@ -1,593 +0,0 @@
1
- import { BlockNames, type CustomBotEvents, Hook } from "pw-js-api";
2
- import type { ProtoGen } from "pw-js-api";//"../node_modules/pw-js-api/dist/gen/world_pb";
3
-
4
- import Block from "./Block";
5
- import BufferReader from "./BufferReader";
6
- import Player, { PlayerEffect } from "./Player";
7
- import { LayerType } from "./Constants";
8
- import type { BlockArg, Point, PWGameHook, SendableBlockPacket } from "./types";
9
-
10
- /**
11
- * To use this helper, you must first create an instance of this,
12
- *
13
- * then: <PWGameClient>.addCallback("raw", helper.onRawPacketRecv)
14
- */
15
- export default class PWGameWorldHelper {
16
- /**
17
- * Arrays of blocks (by layer, x, y)
18
- */
19
- blocks: [Block[][], Block[][]] = [[], []];//Block[][][] = [];
20
-
21
- players = new Map<number, Player>();
22
-
23
- globalSwitches:boolean[] = [];
24
-
25
- private _meta?: ProtoGen.WorldMeta | null;
26
- private _width = 0;
27
- private _height = 0;
28
- private _init = false;
29
- private _selfPlayerId = -1;
30
-
31
- /**
32
- * The current world's width.
33
- *
34
- * If you didn't put the hook before init, this may throw error.
35
- */
36
- get width() {
37
- if (this._width === -1) throw Error("World not initialised, or was applied too late.");
38
- return this._width;
39
- }
40
-
41
- /**
42
- * The current world's height.
43
- *
44
- * If you didn't put the hook before init, this may throw error.
45
- */
46
- get height() {
47
- if (this._height === -1) throw Error("World not initialised, or was applied too late.");
48
- return this._height;
49
- }
50
-
51
- /**
52
- * The current world's metadata.
53
- *
54
- * If you didn't put the hook before init, this may throw error.
55
- */
56
- get meta() {
57
- if (this._meta === undefined) throw Error("World not initialised, or was applied too late.");
58
- return this._meta;
59
- }
60
-
61
- /**
62
- * If this helper is ready. When it's false, the helper will not return anything for any of the packets.
63
- */
64
- get initialised() {
65
- return this._init;
66
- }
67
-
68
- /**
69
- * The bot's player object.
70
- *
71
- * If you didn't put the hook before init, this may throw error.
72
- */
73
- get botPlayer() {
74
- let player = this.players.get(this._selfPlayerId);
75
-
76
- if (!player) throw Error("Player not stored, hook may have been applied too late?");
77
- return player;
78
- }
79
-
80
- /**
81
- * The bot's player id in the world.
82
- *
83
- * If you didn't put the hook before init, this may throw error.
84
- */
85
- get botPlayerId() {
86
- if (this._selfPlayerId === -1) throw Error("Player not stored, hook may have been applied too late.");
87
-
88
- return this._selfPlayerId;
89
- }
90
-
91
- /**
92
- * This must go in .use() of the main PW-JS-API Game Client class.
93
- *
94
- * <PWGameClient>.use(<PWGameWorldHelper>.receiveHook)
95
- *
96
- * DO NOT PUT () AFTER RECEIVEHOOK
97
- */
98
- receiveHook: Hook<PWGameHook> =
99
- (data: CustomBotEvents["raw"]) => {
100
-
101
- const { packet } = data;
102
-
103
- switch (packet.case) {
104
- //#region World
105
- case "playerInitPacket":
106
- {
107
- this._height = packet.value.worldHeight;
108
- this._width = packet.value.worldWidth;
109
- this._meta = packet.value.worldMeta ?? null;
110
-
111
- this.initialise(packet.value.worldData);
112
-
113
- const props = packet.value.playerProperties;
114
-
115
- this.globalSwitches = this.convertSwitchState(packet.value.globalSwitchState);
116
-
117
- if (props) {
118
- this.players.set(props.playerId, new Player(props, true));
119
- this._selfPlayerId = props.playerId;
120
-
121
- return { player: this.players.get(props.playerId) };
122
- }//packet.value..playerProperties?.)
123
- return;
124
- }
125
- case "worldMetaUpdatePacket":
126
- this._meta = packet.value.meta ?? null;
127
- return;
128
- case "worldReloadedPacket":
129
- this.initialise(packet.value.worldData);
130
- return;
131
- case "worldClearedPacket":
132
- this.clear();
133
- return;
134
- case "worldBlockPlacedPacket":
135
- {
136
- if (!this._init) return;
137
-
138
- const { positions, layer, blockId, extraFields, playerId } = packet.value;
139
-
140
- const player = this.players.get(playerId as number);
141
-
142
- const oldBlocks:Block[] = [];
143
- const newBlocks:Block[] = [];
144
-
145
- const args = Block.deserializeArgs(blockId, BufferReader.from(extraFields), true);
146
-
147
- for (let i = 0, len = positions.length; i < len; i++) {
148
- const { x, y } = positions[i];
149
-
150
- oldBlocks[i] = this.blocks[layer][x][y].clone();
151
- newBlocks[i] = this.blocks[layer][x][y] = new Block(blockId, args)
152
- }
153
-
154
- if (!player) return;
155
-
156
- return { player, oldBlocks, newBlocks };
157
- }
158
- //#endregion
159
- //#region Player
160
- case "playerJoinedPacket":
161
- {
162
- const { properties, worldState } = packet.value;
163
-
164
- let player: Player;
165
-
166
- if (properties && worldState) {
167
- this.players.set(properties.playerId, player = new Player(properties, { ...worldState, switches: this.convertSwitchState(worldState.switches) }));
168
-
169
- return { player };
170
- }
171
- }
172
- return;
173
- case "playerLeftPacket":
174
- {
175
- const player = this.players.get(packet.value.playerId);
176
-
177
- if (player) {
178
- this.players.delete(packet.value.playerId);
179
-
180
- return { player: player };
181
- }
182
- }
183
- return;
184
- case "playerFacePacket":
185
- {
186
- const player = this.players.get(packet.value?.playerId as number);
187
-
188
- if (player) {
189
- const oldie = player.face;
190
-
191
- player.face = packet.value.faceId;
192
-
193
- return { player, oldFace: oldie };//changes: { type: "face", oldValue: oldFace, newValue: player.face } };
194
- }
195
- }
196
- return;
197
- case "playerModModePacket": case "playerGodModePacket":
198
- {
199
- const player = this.players.get(packet.value?.playerId as number);
200
-
201
- if (player) {
202
- const state = packet.case === "playerGodModePacket" ? "godmode" : "modmode";
203
-
204
- const oldie = player.states[state];
205
-
206
- player.states[state] = packet.value.enabled;
207
-
208
- return { player, oldState: oldie };//changes: { type: "face", oldValue: oldFace, newValue: player.face } };
209
- }
210
- }
211
- return;
212
- case "playerAddEffectPacket": case "playerRemoveEffectPacket": case "playerResetEffectsPacket":
213
- {
214
- const player = this.players.get(packet.value?.playerId as number);
215
-
216
- if (player) {
217
- // const state = //packet.case === "playerGodModePacket" ? "godmode" : "modmode";
218
-
219
- let effects:PlayerEffect[] = [];
220
-
221
- if (packet.case === "playerAddEffectPacket") {
222
- const eff = {
223
- effectId: packet.value.effectId,
224
- duration: packet.value.duration,
225
- strength: packet.value.strength,
226
- };
227
-
228
- player.effects.push(new PlayerEffect(eff));
229
-
230
- return { player, effect: eff };
231
- } else if (packet.case === "playerRemoveEffectPacket") {
232
- const eff = player.effects.findIndex(v => v.effectId === packet.value.effectId);
233
-
234
- if (eff) {
235
- effects = player.effects.splice(eff, 1);
236
-
237
- return { player, effect: effects[0] };
238
- }
239
- } else {
240
- return { player, effects: player.effects.splice(0) };
241
- }
242
- }
243
- }
244
- return;
245
- case "playerMovedPacket":
246
- {
247
- const player = this.players.get(packet.value?.playerId as number);
248
-
249
- if (player) {
250
- if (packet.value.position) {
251
- player.position = {
252
- x: packet.value.position.x,
253
- y: packet.value.position.y,
254
- };
255
- }
256
-
257
- return { player };//changes: { type: "face", oldValue: oldFace, newValue: player.face } };
258
- }
259
- }
260
- return;
261
- case "playerResetPacket":
262
- {
263
- const player = this.players.get(packet.value?.playerId as number);
264
-
265
- if (player) {
266
- player.resetState();
267
-
268
- if (packet.value.position) {
269
- player.position = {
270
- x: packet.value.position.x,
271
- y: packet.value.position.y,
272
- }
273
- }
274
-
275
- return { player }
276
- }
277
- }
278
- return;
279
- case "playerRespawnPacket":
280
- {
281
- const player = this.players.get(packet.value?.playerId as number);
282
-
283
- if (player) { // deaths also reflect in counters update packet
284
- if (packet.value.position) {
285
- player.position = {
286
- x: packet.value.position.x,
287
- y: packet.value.position.y,
288
- }
289
- }
290
-
291
- return { player }
292
- }
293
- }
294
- return;
295
- case "playerUpdateRightsPacket":
296
- {
297
- const player = this.players.get(packet.value?.playerId as number);
298
-
299
- if (player) {
300
- if (packet.value.rights) {
301
- player.rights = {
302
- availableCommands: packet.value.rights.availableCommands,
303
- canChangeWorldSettings: packet.value.rights.canChangeWorldSettings,
304
- canEdit: packet.value.rights.canEdit,
305
- canGod: packet.value.rights.canGod,
306
- canToggleMinimap: packet.value.rights.canToggleMinimap,
307
- }
308
- } else player.resetRights();
309
-
310
- return { player, rights: player.rights }
311
- }
312
- }
313
- return;
314
- case "playerTeamUpdatePacket":
315
- {
316
- const player = this.players.get(packet.value?.playerId as number);
317
-
318
- if (player) {
319
- const oldTeam = player.states.teamId;
320
- player.states.teamId = packet.value.teamId;
321
-
322
- return { player, oldTeam };
323
- }
324
- }
325
- return;
326
- case "playerCountersUpdatePacket":
327
- {
328
- const player = this.players.get(packet.value?.playerId as number);
329
-
330
- if (player) {
331
- const oldState = {
332
- coinsBlue: player.states.coinsBlue,
333
- coinsGold: player.states.coinsGold,
334
- deaths: player.states.deaths,
335
- }
336
-
337
- player.states.coinsBlue = packet.value.blueCoins;
338
- player.states.coinsGold = packet.value.coins;
339
- player.states.deaths = packet.value.deaths;
340
-
341
- return { player, oldState };
342
- }
343
- }
344
- return;
345
- case "playerTeleportedPacket":
346
- {
347
- const player = this.players.get(packet.value?.playerId as number);
348
-
349
- if (player) {
350
- if (packet.value.position)
351
- player.position = {
352
- x: packet.value.position.x,
353
- y: packet.value.position.y,
354
- }
355
-
356
- return { player };
357
- }
358
- }
359
- return;
360
- case "globalSwitchChangedPacket": case "playerLocalSwitchChangedPacket":
361
- {
362
- const player = this.players.get(packet.value?.playerId as number);
363
-
364
- if (packet.case === "globalSwitchChangedPacket") {
365
- this.globalSwitches[packet.value.switchId] = packet.value.enabled;
366
- }
367
-
368
- if (player) {
369
- if (packet.case === "playerLocalSwitchChangedPacket") {
370
- player.states.switches[packet.value.switchId] = packet.value.switchEnabled;
371
- }
372
-
373
- return { player };
374
- }
375
- }
376
- return;
377
- case "globalSwitchResetPacket": case "playerLocalSwitchResetPacket":
378
- {
379
- const player = this.players.get(packet.value?.playerId as number);
380
-
381
- if (packet.case === "globalSwitchResetPacket") {
382
- this.globalSwitches = this.globalSwitches.fill(false);
383
- }
384
-
385
- if (player) {
386
- if (packet.case === "playerLocalSwitchResetPacket") {
387
- if (packet.value.switchId === undefined) player.states.switches.fill(false);
388
- else player.states.switches[packet.value.switchId] = packet.value.switchEnabled;
389
- }
390
-
391
- return { player };
392
- }
393
- }
394
- return;
395
- case "playerChatPacket": case "playerDirectMessagePacket":
396
- // case "playerDirectMessagePacket":
397
- {
398
- const player = this.players.get(packet.case === "playerChatPacket" ? packet.value?.playerId as number : (packet.value.fromPlayerId === this._selfPlayerId ? packet.value.fromPlayerId : packet.value.targetPlayerId));
399
-
400
- if (player) {
401
- return { player };
402
- }
403
- }
404
- return;
405
- case "playerTouchBlockPacket":
406
- {
407
- const player = this.players.get(packet.value.playerId as number);
408
-
409
- if (player && packet.value.position) {
410
- const blockName = BlockNames[packet.value.blockId];
411
-
412
- if (blockName === "COIN_GOLD" || blockName === "COIN_BLUE") {
413
- player.states.collectedItems.push({
414
- x: packet.value.position.x,
415
- y: packet.value.position.y,
416
- });
417
- }
418
- }
419
-
420
- return player ? { player } : {};
421
- }
422
- //#endregion
423
- }
424
-
425
- return;
426
- }
427
-
428
- /**
429
- * Internal function.
430
- */
431
- private initialise(bytes: Uint8Array, width?: number, height?: number) {
432
- if (width === undefined) width = this.width;
433
- if (height === undefined) height = this.height;
434
-
435
- this.blocks.splice(0);
436
-
437
- for (let l = 0; l < 2; l++) {
438
- this.blocks[l] = [];
439
- for (let x = 0; x < width; x++) {
440
- this.blocks[l][x] = [];
441
-
442
- for (let y = 0; y < height; y++) {
443
- this.blocks[l][x][y] = new Block(0);
444
- }
445
- }
446
- }
447
-
448
- this.deserialize(bytes);
449
- }
450
-
451
- /**
452
- * Internal function.
453
- */
454
- private deserialize(bytes: Uint8Array | Buffer | BufferReader) {
455
- const reader = bytes instanceof BufferReader ? bytes : BufferReader.from(bytes);
456
-
457
- for (let l = 0; l < 2; l++) {
458
- for (let x = 0; x < this.width; x++) {
459
- for (let y = 0; y < this.height; y++) {
460
- this.blocks[l][x][y] = Block.deserialize(reader);
461
- }
462
- }
463
- }
464
-
465
- this._init = true;
466
- }
467
-
468
- private convertSwitchState(arr: Uint8Array) {
469
- const list = new Array<boolean>(1000);
470
-
471
- for (let i = 0; i < 1000; i++) {
472
- list[i] = arr[i] === 1;
473
- }
474
-
475
- return list;
476
- }
477
-
478
- /**
479
- * Internal function, this triggers when the world gets cleared.
480
- *
481
- * Clears the blocks map and promptly fill it with empty except the border which becomes basci gray.
482
- */
483
- private clear() {
484
- this.blocks.splice(0);
485
-
486
- // To prevent subtracting every single time, can be costly computation wise.
487
- const lastWidth = this.width - 1;
488
- const lastHeight = this.width - 1;
489
-
490
- for (let l = 0; l < 2; l++) {
491
- this.blocks[l] = [];
492
-
493
- for (let x = 0; x < this.width; x++) {
494
- this.blocks[l][x] = [];
495
-
496
- for (let y = 0; y < this.height; y++) {
497
- this.blocks[l][x][y] = new Block(l === 1 && (x === 0 || x === lastWidth || y === 0 || y === lastHeight) ? "BASIC_GRAY" : "EMPTY");
498
- }
499
- }
500
- }
501
- }
502
-
503
- /**
504
- * Gets the block at the position.
505
- *
506
- * Difference between this and using this.blocks directly is that this function will validate the positions and the layer.
507
- */
508
- getBlockAt(pos: Point, l: LayerType) : Block;
509
- getBlockAt(x: number | Point, y: number, l: LayerType) : Block;
510
- getBlockAt(x: number | Point, y: number | LayerType, l?: LayerType) {
511
- if (typeof x !== "number") {
512
- l = y;
513
- y = x.y;
514
- x = x.x;
515
- }
516
-
517
- if (l === undefined || l < 2) throw Error("Unknown layer");
518
-
519
- if (x < 0 || x >= this.width) throw Error("X is outside the bound of the world.");
520
- if (y < 0 || y >= this.height) throw Error("Y is outside the bound of the world.");
521
-
522
- return this.blocks[l][x][y];
523
- }
524
-
525
- /**
526
- * Player ID.
527
- *
528
- * The main bot player is excluded from the criteria.
529
- */
530
- getPlayer(id: number, isAccount?: false) : Player | undefined;
531
- /**
532
- * Username is case insensitive.
533
- *
534
- * The main bot player is excluded from the criteria.
535
- */
536
- getPlayer(username: string, isAccount?: false) : Player | undefined;
537
- /**
538
- * The ID of the account (must have second parameter set to true)
539
- *
540
- * The main bot player is excluded from the criteria.
541
- */
542
- getPlayer(accountId: string, isAccount: true) : Player | undefined;
543
- getPlayer(id: string | number, isAccount?: boolean) : Player | undefined {
544
- if (typeof id === "string") {
545
- const players = this.getPlayers();
546
- // all names are upper case
547
- if (!isAccount) id = id.toUpperCase();
548
-
549
- for (let i = 0, len = players.length; i < len; i++) {
550
- if (isAccount) {
551
- if (players[i].accountId === id) return players[i];
552
- } else if (players[i].username === id) return players[i];
553
- }
554
-
555
- return undefined;
556
- }
557
-
558
- return this.players.get(id);
559
- }
560
-
561
- /**
562
- * Returns the list of current players in the world.
563
- */
564
- getPlayers() {
565
- return Array.from(this.players.values());
566
- }
567
-
568
- /**
569
- * For now this is slightly limited, but this will ONLY create a sendable packet which you must then send it yourself.
570
- */
571
- createBlockPacket(blockId: number | BlockNames | keyof typeof BlockNames, layer: LayerType, pos: Point | Point[], ...args: BlockArg[]) : SendableBlockPacket;
572
- createBlockPacket(block: Block, layer: LayerType, pos: Point | Point[]) : SendableBlockPacket;
573
- createBlockPacket(blockId: number | BlockNames | keyof typeof BlockNames | Block, layer: LayerType, pos: Point | Point[], ...args: BlockArg[]) {
574
- if (blockId instanceof Block) {
575
- args = blockId.args;
576
- blockId = blockId.bId
577
- }
578
- else if (typeof blockId !== "number") blockId = BlockNames[blockId];
579
-
580
- if (blockId === undefined) throw Error("Unknown block ID");
581
- if (layer === undefined || layer < 0 || layer > 1) throw Error("Unknown layer type");
582
-
583
- if (!Array.isArray(pos)) pos = [pos];
584
-
585
- return {
586
- isFillOperation: false,
587
- blockId,
588
- layer,
589
- positions: pos,
590
- extraFields: Block.serializeArgs(blockId, args, { endian: "big", writeId: false, readTypeByte: true })
591
- } satisfies SendableBlockPacket;
592
- }
593
- }
File without changes
File without changes
File without changes
File without changes
File without changes