@vaitosoi/minejs 0.5.1 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +25 -9
  2. package/assets/minecraft/26.2/components.json +113 -0
  3. package/assets/minecraft/26.2/packets.json +8 -28
  4. package/assets/minecraft/26.3/packets.json +4957 -0
  5. package/assets/minecraft/versionMapping.json +16 -0
  6. package/dist/binary/decoder.d.ts +35 -0
  7. package/dist/binary/decoder.d.ts.map +1 -1
  8. package/dist/binary/decoder.js +665 -2
  9. package/dist/binary/decoder.js.map +1 -1
  10. package/dist/binary/encoder.d.ts +3 -3
  11. package/dist/binary/encoder.d.ts.map +1 -1
  12. package/dist/binary/encoder.js +4 -4
  13. package/dist/binary/encoder.js.map +1 -1
  14. package/dist/client/client.d.ts +178 -22
  15. package/dist/client/client.d.ts.map +1 -1
  16. package/dist/client/client.js +132 -13
  17. package/dist/client/client.js.map +1 -1
  18. package/dist/net/tcp.d.ts +6 -9
  19. package/dist/net/tcp.d.ts.map +1 -1
  20. package/dist/net/tcp.js +16 -19
  21. package/dist/net/tcp.js.map +1 -1
  22. package/dist/packet/listener.d.ts +6 -1
  23. package/dist/packet/listener.d.ts.map +1 -1
  24. package/dist/packet/listener.js +220 -60
  25. package/dist/packet/listener.js.map +1 -1
  26. package/dist/packet/sender.d.ts +4 -1
  27. package/dist/packet/sender.d.ts.map +1 -1
  28. package/dist/packet/sender.js +30 -4
  29. package/dist/packet/sender.js.map +1 -1
  30. package/dist/physics/aabb.d.ts.map +1 -1
  31. package/dist/physics/aabb.js +17 -9
  32. package/dist/physics/aabb.js.map +1 -1
  33. package/dist/physics/direction.js +2 -2
  34. package/dist/physics/direction.js.map +1 -1
  35. package/dist/physics/player.js +1 -5
  36. package/dist/physics/player.js.map +1 -1
  37. package/dist/version/codec.d.ts.map +1 -1
  38. package/dist/version/codec.js +63 -14
  39. package/dist/version/codec.js.map +1 -1
  40. package/dist/version/registry.d.ts +26 -5
  41. package/dist/version/registry.d.ts.map +1 -1
  42. package/dist/version/registry.js +78 -18
  43. package/dist/version/registry.js.map +1 -1
  44. package/dist/world/block.d.ts +54 -10
  45. package/dist/world/block.d.ts.map +1 -1
  46. package/dist/world/block.js +78 -32
  47. package/dist/world/block.js.map +1 -1
  48. package/dist/world/container.d.ts +106 -0
  49. package/dist/world/container.d.ts.map +1 -0
  50. package/dist/world/container.js +240 -0
  51. package/dist/world/container.js.map +1 -0
  52. package/dist/world/entity.d.ts +3 -0
  53. package/dist/world/entity.d.ts.map +1 -1
  54. package/dist/world/entity.js +3 -0
  55. package/dist/world/entity.js.map +1 -1
  56. package/dist/world/state.d.ts +11 -5
  57. package/dist/world/state.d.ts.map +1 -1
  58. package/dist/world/state.js +11 -0
  59. package/dist/world/state.js.map +1 -1
  60. package/package.json +2 -2
  61. package/src/binary/decoder.ts +691 -2
  62. package/src/binary/encoder.ts +8 -9
  63. package/src/client/client.ts +234 -34
  64. package/src/net/tcp.ts +27 -22
  65. package/src/packet/listener.ts +275 -76
  66. package/src/packet/sender.ts +42 -7
  67. package/src/physics/aabb.ts +18 -9
  68. package/src/physics/direction.ts +2 -2
  69. package/src/physics/player.ts +5 -5
  70. package/src/version/codec.ts +56 -14
  71. package/src/version/registry.ts +92 -18
  72. package/src/world/block.ts +83 -39
  73. package/src/world/container.ts +180 -0
  74. package/src/world/entity.ts +3 -0
  75. package/src/world/state.ts +21 -6
  76. package/test/client/index.ts +56 -21
  77. package/test/client/registry.json +1735 -0
@@ -1,4 +1,4 @@
1
- import { Vec3 } from "../physics/direction";
1
+ import { BaseVec3 } from "../physics/direction";
2
2
  import { CONTINUATION_FLAG, CONTINUE_BIT, isFixedSizeTag, isTag, MAX_QUANTIZED_VALUE, SCALE_BITS, SEGMENT_BITS } from "./static";
3
3
  import { InvalidValue, NumberTooBig, UnexpectedValue } from "../base/error";
4
4
  import { FixedSizeTag, Tag } from "./static";
@@ -71,7 +71,7 @@ export class BinaryEncoder {
71
71
  public writeLong(val: bigint | number) {
72
72
  // Cast to BigInt
73
73
  const v = typeof val === "bigint" ? val : BigInt(val);
74
- return this.write(8, v, (buf) => buf.writeBigInt64BE);
74
+ return this.write(8, BigInt.asIntN(64, v), (buf) => buf.writeBigInt64BE);
75
75
  }
76
76
  /**
77
77
  * Write 4 bytes float
@@ -163,12 +163,11 @@ export class BinaryEncoder {
163
163
  *
164
164
  * @returns a Position
165
165
  */
166
- public writePosition(position: Vec3) {
167
- const val = BigInt(
168
- ((position.x & 0x3FFFFFF) << 38) |
169
- ((position.z & 0x3FFFFFF) << 12) |
170
- (position.y & 0xFFF)
171
- );
166
+ public writePosition(position: BaseVec3) {
167
+ const val =
168
+ (BigInt(position.x & 0x3FFFFFF) << 38n) |
169
+ (BigInt(position.z & 0x3FFFFFF) << 12n) |
170
+ BigInt(position.y & 0xFFF);
172
171
  this.writeLong(val);
173
172
  return this;
174
173
  }
@@ -219,7 +218,7 @@ export class BinaryEncoder {
219
218
  *
220
219
  * Read this article for more information: https://minecraft.wiki/w/Java_Edition_protocol/Data_types#LpVec3
221
220
  */
222
- public writeLpVec3(vec3: Vec3) {
221
+ public writeLpVec3(vec3: BaseVec3) {
223
222
  const maxCoordinate = Math.max(Math.abs(vec3.x), Math.max(Math.abs(vec3.y), Math.abs(vec3.z)));
224
223
 
225
224
  // Checking for NaN values in our maxCoordinate
@@ -1,5 +1,5 @@
1
1
  import { EventEmitter } from "node:events";
2
- import { BlockManager, BlockState } from "../world/block";
2
+ import { BlockGetter, BlockManager, BlockState } from "../world/block";
3
3
  import { EntitiesManager } from "../world/entity";
4
4
  import { Input, Player } from "../physics/player";
5
5
  import { TickLoop } from "../world/tick";
@@ -16,14 +16,18 @@ import { computeUUID } from "../base/math";
16
16
  import { HaveSignatureButNotIndex } from "../base/error";
17
17
  import { Sender } from "../packet/sender";
18
18
  import { CacheImplementation } from "../base/cache";
19
+ import { Container, Slot } from "../world/container";
19
20
 
20
21
  export type ClientOption = Omit<TCPClientOption, "protocolVersion"> & {
22
+ /**
23
+ * The client version. Supports 26.2 and 26.3
24
+ */
21
25
  version: string,
22
26
 
23
27
  /**
24
- * Whenever should the client verify the message against the signature, if any
28
+ * Whenever should the client verify the message against the signature, if any.
25
29
  *
26
- * When set this option to true, you HAVE TO set `shouldVerifyMessageOrder` to true
30
+ * In order to set this option to true, you HAVE TO set `shouldVerifyMessageOrder` to true
27
31
  */
28
32
  shouldVerifyMessageSignature?: boolean,
29
33
 
@@ -57,28 +61,50 @@ export interface ClientEvents {
57
61
  /**
58
62
  * When the client is ready.
59
63
  *
60
- * Specifically, when the packet `Login (play)` is received
64
+ * Specifically, when the packet `Login (play)` is received.
65
+ *
66
+ * Most of the client method require this event to be fired in order to work.
61
67
  */
62
68
  ready: [],
63
69
  /**
64
- * When the client got disconnected from sevrer
70
+ * When the client got disconnected from server.
71
+ *
72
+ * This event only provide the parsed string. To get the unparsed, or the raw one with decoration, use `disconnectRaw`.
73
+ * But, the `disconnectRaw` is only fired when the disconnection come from the server, or the server disconnect the client.
74
+ * Sometime, the disconnect will be fired within the client, meaning that there will be no `disconnectRaw`
65
75
  */
66
76
  disconnect: [reason: string],
67
77
  /**
68
- * When the disconection come with the raw Text Component
78
+ * When the disconnection come with the raw Text Component.
69
79
  */
70
80
  disconnectRaw: [textComponent: TextComponent],
71
81
 
82
+ /** The registry_data packet */
83
+ registryData: [data: RegistryData],
84
+
72
85
  /**
73
- * When server send `Player Position Synchronization` packet
86
+ * When server send `Player Position Synchronization` packet.
87
+ *
88
+ * **Note:** this event is not fired when the client is moved by holding the input.
74
89
  *
75
- * Note: this event is not fired when the client is moved by holding the input
90
+ * To get the player current position, use `getPosition` method
76
91
  */
77
92
  playerPosition: [position: BaseVec3],
78
93
 
79
- /** When the chunk is loaded */
94
+ /**
95
+ * When the chunk is loaded
96
+ *
97
+ * Explaining the `chunkX`, `sectionY`, `chunkZ`: A chunk in Minecraft is a region which length and width is 16 and the height extends to the limit.
98
+ * But when sending the packet, the chunk is divided into smaller section which volume is 16x16x16.
99
+ * So the `chunkX` and `chunkZ` is the chunk position and `sectionY` is the section within that chunk,
100
+ * counting from the bedrock up to the sky
101
+ */
80
102
  loadChunk: [chunkX: number, sectionY: number, chunkZ: number],
81
- /** When the chunk got deleted by the server */
103
+ /**
104
+ * When the chunk got deleted by the server
105
+ *
106
+ * See the `chunkX` and `chunkZ` explaination in `loadChunk` events
107
+ */
82
108
  unloadChunk: [chunkX: number, chunkZ: number],
83
109
 
84
110
  /** When an entity is spawned or appeared in the client view distance */
@@ -87,28 +113,86 @@ export interface ClientEvents {
87
113
  updateEntity: [entityId: number],
88
114
  /** When an entity go out of client view distance or despawned */
89
115
  removeEntity: [entityId: number],
90
- /** The registry_data packet */
91
- registryData: [data: RegistryData],
92
-
116
+
93
117
  // Chat
94
118
  /** When a chat message got broadcasted */
95
119
  message: [message: Message],
96
120
  /** When a message is failed to be verified against the signature sent with it */
97
121
  failedMessage: [message: Message],
98
- /** The system message */
122
+ /**
123
+ * The system message
124
+ *
125
+ * This event only provide the parsed string. To get the unparsed, or the raw one with decoration, use `systemMessageRaw`
126
+ */
99
127
  systemMessage: [message: string],
100
- /** The raw system message */
128
+ /**
129
+ * The system message with the Text Component for decorations
130
+ */
101
131
  systemMessageRaw: [textComponent: TextComponent],
102
- /** The action bar */
132
+ /**
133
+ * The action bar
134
+ *
135
+ * This event only provide the parsed string. To get the unparsed, or the raw one with decoration, use `actionBarRaw`
136
+ */
103
137
  actionBar: [message: string],
104
138
  /** The raw action bar */
105
139
  actionBarRaw: [textComponent: TextComponent],
140
+
141
+ // Container
142
+ /**
143
+ * When a container is opened
144
+ *
145
+ * This event will be fired when client click on a block (with `openBlock` method) that is a container
146
+ * or when server believe that you just open a container (with open_screen packet).
147
+ */
148
+ openContainer: [container: Container],
149
+ /** When the opening container is closed */
150
+ closeContainer: [],
151
+ /** When the packet contain the content of the container is received */
152
+ containerContent: [container: Container, carryingItem: Slot],
153
+ /** When the packet contain the property of the container is received */
154
+ containerProperty: [container: Container],
155
+
156
+ /**
157
+ * When tab list is updated
158
+ *
159
+ * `{"text":""}` mean remove header or footer.
160
+ */
161
+ tablist: [newTablist: { header: { text: string, raw: TextComponent }, footer: { text: string, raw: TextComponent } }]
106
162
  }
107
163
 
108
164
  /**
109
165
  * High-level client.
166
+ *
167
+ * @example
168
+ * ```ts
169
+ * const client = new Client({
170
+ * playerName: "bot", // Put your name here
171
+ * host: "localhost", // Put the server address
172
+ * port: 25565, // 25565 is the default port, change to your server's port if needed
173
+ * version: "26.2", // The client version
174
+ * loadRegistry: false, //
175
+ * // auth: { // This things is not working yet
176
+ * // client_id: "d86254d8-edf7-4640-90eb-643c99af188e",
177
+ * // method: "loopback",
178
+ * // openBrowser: true,
179
+ * // port: 12345
180
+ * // },
181
+ * // shouldVerifyMessageOrder: true,
182
+ * // shouldVerifyMessageSignature: true
183
+ * });
184
+ *
185
+ * // MineJs is a event driven library, the same way DiscordJS work (if you know them).
186
+ * // One thing to note is most of method in this client require client to be ready,
187
+ * // meaning that unless the "ready" event is fired, you can't do, mostly, anything :D
188
+ * client.on("ready", () => console.log("Client is ready :yay:"));
189
+ *
190
+ * // The init step before is just init the data and does not create the connection yet.
191
+ * // This method will create that connection.
192
+ * client.connect();
193
+ * ```
110
194
  */
111
- export class Client<IsReady extends boolean = boolean> extends (EventEmitter as new () => TypedEmitter<ClientEvents>) {
195
+ export class Client extends (EventEmitter as new () => TypedEmitter<ClientEvents>) {
112
196
  private static loadRegistry: boolean = false;
113
197
 
114
198
  private tickLoop: TickLoop;
@@ -118,7 +202,7 @@ export class Client<IsReady extends boolean = boolean> extends (EventEmitter as
118
202
  private player: Player;
119
203
 
120
204
  private tcp: TCPClient;
121
- private state: SharedState<IsReady>;
205
+ private state: SharedState;
122
206
  private packetListener: Listener;
123
207
  private packetSender: Sender;
124
208
 
@@ -127,6 +211,7 @@ export class Client<IsReady extends boolean = boolean> extends (EventEmitter as
127
211
  throw new HaveSignatureButNotIndex();
128
212
 
129
213
  super();
214
+ this.loadRegistries();
130
215
 
131
216
  // For managing shared data
132
217
  this.state = new SharedState(options);
@@ -182,7 +267,7 @@ export class Client<IsReady extends boolean = boolean> extends (EventEmitter as
182
267
  this.tcp.on("destroy", () => this.emit("destroy"));
183
268
  this.on("loadChunk", (sx, sy, sz) => this.blocks.deleteChunkCache(sx, sy, sz));
184
269
  this.on("unloadChunk", (sx, sz) => {
185
- for (let sy = 0; sy < 16; sy++)
270
+ for (let sy = 0; sy < 16; sy++)
186
271
  this.blocks.deleteChunkCache(sx, sy, sz);
187
272
  });
188
273
  }
@@ -191,14 +276,14 @@ export class Client<IsReady extends boolean = boolean> extends (EventEmitter as
191
276
  this.emit(event.event, ...event.args);
192
277
  }
193
278
 
194
- private async loadRegistries() {
279
+ private loadRegistries() {
195
280
  if (Client.loadRegistry) return;
196
281
  Client.loadRegistry = true;
197
282
  const { version } = this.options;
198
- await BlockRegistry.load(version);
199
- await EntityRegistry.load(version);
200
- await PacketRegistry.load(version);
201
- await EffectRegistry.load(version);
283
+ BlockRegistry.load(version);
284
+ EntityRegistry.load(version);
285
+ PacketRegistry.load(version);
286
+ EffectRegistry.load(version);
202
287
  }
203
288
 
204
289
  // Start / stop
@@ -207,7 +292,6 @@ export class Client<IsReady extends boolean = boolean> extends (EventEmitter as
207
292
  * Create a connection to the server
208
293
  */
209
294
  public async connect() {
210
- await this.loadRegistries();
211
295
  if (!this.state.playerUUID) {
212
296
  if (this.options.auth) {
213
297
  this.state.authClient = new AuthClient(this.options.auth);
@@ -231,7 +315,9 @@ export class Client<IsReady extends boolean = boolean> extends (EventEmitter as
231
315
  });
232
316
  }
233
317
  /**
234
- * Destroy the connection
318
+ * Destroy the connection.
319
+ *
320
+ * Calling this method will also fire the "disconnect" event.
235
321
  */
236
322
  public disconnect(reason: string = "Disconnect", raw?: TextComponent) {
237
323
  this.state.state = ConnectionState.Disconnected;
@@ -249,48 +335,162 @@ export class Client<IsReady extends boolean = boolean> extends (EventEmitter as
249
335
 
250
336
  // Inputs
251
337
  /**
252
- * Press and hold a key
338
+ * Press and hold a key.
339
+ *
340
+ * This is pretty the same idea as when you play Minecraft.
341
+ * When you need to go forward, you have to hold the key `W`, `S` for backward, etc...
342
+ *
343
+ * @throws {ClientNotReady} When the client is not ready
253
344
  */
254
- public hold(inout: Input) {
255
- this.player.input(inout);
345
+ public hold(input: Input) {
346
+ this.state.checkReady();
347
+ this.player.input(input);
256
348
  }
257
349
  /**
258
- * Release a key
350
+ * Release a key.
351
+ *
352
+ * This is also pretty the same idea as when you play Minecraft.
353
+ * Need to stop, stop holding `W`, `S` key, etc...
354
+ *
355
+ * @throws {ClientNotReady} When the client is not ready
259
356
  */
260
357
  public release(input: Input) {
358
+ this.state.checkReady();
261
359
  this.player.releaseInput(input);
262
360
  }
263
361
  /**
264
- * Release all key
362
+ * Release all key.
363
+ *
364
+ * This is the shortcut for release all keys.
365
+ * Instead of calling `release` method for each keys, just call this
366
+ *
367
+ * @throws {ClientNotReady} When the client is not ready
265
368
  */
266
369
  public stopMoving() {
370
+ this.state.checkReady();
267
371
  this.player.releaseAllInputs();
268
372
  }
269
373
 
270
374
  /**
271
375
  * Send a message
376
+ *
377
+ * @throws {ClientNotReady} When the client is not ready
272
378
  */
273
379
  public chat(message: string) {
380
+ this.state.checkReady();
274
381
  this.packetSender.sendMessage(message);
275
382
  }
276
383
 
277
384
  // World
278
385
  /**
279
386
  * Get the block state at position
387
+ *
388
+ * @throws {ClientNotReady} When the client is not ready
280
389
  */
281
- public at(x: number, y: number, z: number): BlockState | null;
282
- public at(position: BaseVec3): BlockState | null;
283
- public at(a: BaseVec3 | number, b?: number, c?: number): BlockState | null {
390
+ public getBlock(x: number, y: number, z: number): BlockState | null;
391
+ public getBlock(position: BaseVec3): BlockState | null;
392
+ public getBlock(a: BaseVec3 | number, b?: number, c?: number): BlockState | null {
284
393
  const vec3 = Vec3.loadArgs(a, b, c);
285
394
  return this.blocks.at(vec3);
286
395
  }
287
396
 
397
+ /**
398
+ * Get player position
399
+ *
400
+ * @throws {ClientNotReady} When the client is not ready
401
+ */
402
+ public getPosition() {
403
+ this.state.checkReady();
404
+ return structuredClone(this.state.player!.position);
405
+ }
406
+
288
407
  /**
289
408
  * Rotate your face
409
+ *
410
+ * "Yaw is measured in degrees and does not follow classical trigonometry rules.
411
+ * The unit circle of yaw on the XZ-plane starts at (0, 1) and turns counterclockwise, with 90 at (-1, 0), 180 at (0, -1) and 270 at (1, 0).
412
+ *
413
+ * Pitch is measured in degrees, where 0 is looking straight ahead, -90 is looking straight up, and 90 is looking straight down."
414
+ *
415
+ * @see https://minecraft.wiki/w/Java_Edition_protocol/Packets#Synchronize_Player_Position For Yaw and Pitch definition
416
+ *
290
417
  * @param yaw In degree
291
418
  * @param pitch In degree
419
+ *
420
+ * @throws {ClientNotReady} When the client is not ready
292
421
  */
293
422
  public lookAt(yaw: number, pitch: number) {
423
+ this.state.checkReady();
294
424
  this.player.setAngle(yaw, pitch);
295
425
  }
426
+
427
+ /**
428
+ * Get opening container.
429
+ *
430
+ * Return `undefined` if nothing is opening
431
+ *
432
+ * @throws {ClientNotReady} When the client is not ready
433
+ */
434
+ public getOpeningContainer() {
435
+ this.state.checkReady();
436
+ return this.state.openingContainer;
437
+ }
438
+ /**
439
+ * Get carrying item.
440
+ *
441
+ * Return `undefined` if nothing is carried
442
+ *
443
+ * @throws {ClientNotReady} When the client is not ready
444
+ */
445
+ public getCarryingItem() {
446
+ this.state.checkReady();
447
+ return this.state.player?.carryingItem;
448
+ }
449
+ /**
450
+ * Get player's inventory
451
+ *
452
+ * @throws {ClientNotReady} When the client is not ready
453
+ */
454
+ public getInventory() {
455
+ this.state.checkReady();
456
+ return this.state.player?.inventory;
457
+ }
458
+
459
+ /**
460
+ * Open a block.
461
+ *
462
+ * @throws {ClientNotReady} When the client is not ready
463
+ * @returns `true` if the target block is a solid block, or else, return `false`
464
+ */
465
+ public openBlock(x: number, y: number, z: number): boolean;
466
+ public openBlock(position: BaseVec3): boolean;
467
+ public openBlock(a: BaseVec3 | number, b?: number, c?: number): boolean {
468
+ this.state.checkReady();
469
+ const vec3 = Vec3.loadArgs(a, b, c);
470
+ const eyePos = new Vec3(this.state.player!.position).add(0, 1.62, 0);
471
+ const target = new Vec3(vec3).add(0.5, 0.5, 0.5); // aim at block center, or use look direction
472
+ const reach = 4.5; // survival reach, adjust as needed
473
+ const dir = target.subtract(eyePos).normalize();
474
+ const to = eyePos.add(dir.scale(reach));
475
+ const clipResult = BlockGetter.clip(
476
+ eyePos,
477
+ to,
478
+ (pos) => this.blocks.at(pos)!.shape
479
+ )!;
480
+ if (clipResult.miss) return false;
481
+ const cursorX = Math.abs(clipResult.location.x - clipResult.pos.x),
482
+ cursorY = Math.abs(clipResult.location.y - clipResult.pos.y),
483
+ cursorZ = Math.abs(clipResult.location.z - clipResult.pos.z);
484
+ if (cursorX > 1 || cursorY > 1 || cursorZ > 1)
485
+ return false;
486
+ this.packetSender.sendUseItemOn(
487
+ "main",
488
+ vec3,
489
+ clipResult.direction,
490
+ { x: cursorX, y: cursorY, z: cursorZ },
491
+ false,
492
+ false
493
+ );
494
+ return true;
495
+ }
296
496
  }
package/src/net/tcp.ts CHANGED
@@ -34,7 +34,11 @@ export interface TCPClientOption {
34
34
 
35
35
  debug?: {
36
36
  /** Log the incoming packet */
37
- packetLogger: boolean
37
+ packetLogger: boolean,
38
+ /** Packet to ignore */
39
+ ignorePackets?: string[],
40
+ /** Ignore logs from TCP client (`packet X length Y`) */
41
+ ignoreTCPPacketLogs?: number[] | true
38
42
  },
39
43
 
40
44
  // For premium account
@@ -52,8 +56,8 @@ export interface Message {
52
56
  target: string | undefined,
53
57
  content: string,
54
58
  raw: {
55
- sender: TextComponent,
56
- target: TextComponent | undefined,
59
+ sender: string | TextComponent,
60
+ target: string | TextComponent | undefined,
57
61
  content: TextComponent | undefined
58
62
  }
59
63
  }
@@ -74,13 +78,6 @@ export class TCPClient extends (EventEmitter as new () => TypedEmmiter<TCPClient
74
78
  public readonly socket: Socket;
75
79
 
76
80
  // Internal var
77
- /**
78
- * | Value | Meaning |
79
- * |-------|---------|
80
- * | 0 | not set yet |
81
- * | -1 | dont compress |
82
- * | > 0 | compression threshold |
83
- */
84
81
  private bufferPool: Buffer = Buffer.alloc(0);
85
82
 
86
83
  constructor(
@@ -137,7 +134,7 @@ export class TCPClient extends (EventEmitter as new () => TypedEmmiter<TCPClient
137
134
 
138
135
  private handlePacket() {
139
136
  while (this.bufferPool.length > 0) {
140
- let decoder = new BinaryDecoder(this.bufferPool);
137
+ const decoder = new BinaryDecoder(this.bufferPool);
141
138
  let packetLength: number;
142
139
  try {
143
140
  packetLength = decoder.readVarInt();
@@ -149,27 +146,35 @@ export class TCPClient extends (EventEmitter as new () => TypedEmmiter<TCPClient
149
146
  const expectedPacketEnd = decoder.offset + packetLength;
150
147
 
151
148
  let packetID: number;
149
+ let packetDecoder = new BinaryDecoder(decoder.buffer.subarray(decoder.offset, expectedPacketEnd));
152
150
  if (this.state.compressionThreshold === 0)
153
- packetID = decoder.readVarInt();
151
+ packetID = packetDecoder.readVarInt();
154
152
  else if (this.state.compressionThreshold === -1) {
155
- decoder.readVarInt();
156
- packetID = decoder.readVarInt();
153
+ packetDecoder.readVarInt();
154
+ packetID = packetDecoder.readVarInt();
157
155
  } else {
158
- const dataLength = decoder.readVarInt();
156
+ const dataLength = packetDecoder.readVarInt();
159
157
  if (dataLength === 0) {
160
- packetID = decoder.readVarInt();
158
+ packetID = packetDecoder.readVarInt();
161
159
  } else {
162
- const dataBuffer = this.bufferPool.subarray(decoder.offset, expectedPacketEnd);
160
+ const dataBuffer = packetDecoder.buffer.subarray(packetDecoder.offset);
163
161
  const decompressed = inflateSync(dataBuffer);
164
162
  if (decompressed.length !== dataLength)
165
163
  throw new UnexpectedValue("decompressed packet data", decompressed.length.toString(), dataLength.toString());
166
- decoder = new BinaryDecoder(decompressed);
167
- packetID = decoder.readVarInt();
164
+ packetDecoder = new BinaryDecoder(decompressed);
165
+ packetID = packetDecoder.readVarInt();
168
166
  }
169
167
  }
170
- if (this.state.clientOptions.debug?.packetLogger == true)
171
- console.log("packet", packetID, "length", decoder.buffer.length);
172
- this.forwardPacket(packetID, decoder);
168
+ if (
169
+ this.state.clientOptions.debug &&
170
+ this.state.clientOptions.debug.packetLogger &&
171
+ (
172
+ (Array.isArray(this.state.clientOptions.debug.ignoreTCPPacketLogs) && !this.state.clientOptions.debug.ignoreTCPPacketLogs.includes(packetID)) ||
173
+ (!this.state.clientOptions.debug.ignoreTCPPacketLogs)
174
+ )
175
+ )
176
+ console.log("packet", packetID, "length", packetDecoder.buffer.length);
177
+ this.forwardPacket(packetID, packetDecoder);
173
178
 
174
179
  this.bufferPool = this.bufferPool.subarray(expectedPacketEnd);
175
180
  }