@vaitosoi/minejs 0.2.1 → 0.3.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 (118) hide show
  1. package/assets/minecraft/26.2/packets.json +4741 -0
  2. package/dist/base/bitset.d.ts +9 -0
  3. package/dist/base/bitset.d.ts.map +1 -0
  4. package/dist/base/bitset.js +46 -0
  5. package/dist/base/bitset.js.map +1 -0
  6. package/dist/base/error.d.ts +105 -0
  7. package/dist/base/error.d.ts.map +1 -0
  8. package/dist/base/error.js +194 -0
  9. package/dist/base/error.js.map +1 -0
  10. package/dist/base/event.d.ts +7 -0
  11. package/dist/base/event.d.ts.map +1 -0
  12. package/dist/base/event.js +3 -0
  13. package/dist/base/event.js.map +1 -0
  14. package/dist/base/math.d.ts +25 -0
  15. package/dist/base/math.d.ts.map +1 -0
  16. package/dist/base/math.js +69 -0
  17. package/dist/base/math.js.map +1 -0
  18. package/dist/base/typing.d.ts +9 -0
  19. package/dist/base/typing.d.ts.map +1 -0
  20. package/dist/base/typing.js +3 -0
  21. package/dist/base/typing.js.map +1 -0
  22. package/dist/client/auth.d.ts +39 -0
  23. package/dist/client/auth.d.ts.map +1 -0
  24. package/dist/client/auth.js +307 -0
  25. package/dist/client/auth.js.map +1 -0
  26. package/dist/client/client.d.ts +73 -0
  27. package/dist/client/client.d.ts.map +1 -0
  28. package/dist/client/client.js +136 -0
  29. package/dist/client/client.js.map +1 -0
  30. package/dist/client/static.d.ts +28 -0
  31. package/dist/client/static.d.ts.map +1 -0
  32. package/dist/client/static.js +43 -0
  33. package/dist/client/static.js.map +1 -0
  34. package/dist/client/tcp.d.ts +84 -0
  35. package/dist/client/tcp.d.ts.map +1 -0
  36. package/dist/client/tcp.js +173 -0
  37. package/dist/client/tcp.js.map +1 -0
  38. package/dist/index.d.ts +21 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +12 -12
  41. package/dist/index.js.map +1 -0
  42. package/dist/packet/decoder.d.ts +293 -0
  43. package/dist/packet/decoder.d.ts.map +1 -0
  44. package/dist/packet/decoder.js +668 -0
  45. package/dist/packet/decoder.js.map +1 -0
  46. package/dist/packet/dispatcher.d.ts +46 -0
  47. package/dist/packet/dispatcher.d.ts.map +1 -0
  48. package/dist/packet/dispatcher.js +626 -0
  49. package/dist/packet/dispatcher.js.map +1 -0
  50. package/dist/packet/encoder.d.ts +163 -0
  51. package/dist/packet/encoder.d.ts.map +1 -0
  52. package/dist/packet/encoder.js +441 -0
  53. package/dist/packet/encoder.js.map +1 -0
  54. package/dist/packet/static.d.ts +33 -0
  55. package/dist/packet/static.d.ts.map +1 -0
  56. package/dist/packet/static.js +42 -0
  57. package/dist/packet/static.js.map +1 -0
  58. package/dist/physics/aabb.d.ts +197 -0
  59. package/dist/physics/aabb.d.ts.map +1 -0
  60. package/dist/physics/aabb.js +576 -0
  61. package/dist/physics/aabb.js.map +1 -0
  62. package/dist/physics/direction.d.ts +153 -0
  63. package/dist/physics/direction.d.ts.map +1 -0
  64. package/dist/physics/direction.js +288 -0
  65. package/dist/physics/direction.js.map +1 -0
  66. package/dist/physics/player.d.ts +110 -0
  67. package/dist/physics/player.d.ts.map +1 -0
  68. package/dist/physics/player.js +558 -0
  69. package/dist/physics/player.js.map +1 -0
  70. package/dist/version/codec.d.ts +18 -0
  71. package/dist/version/codec.d.ts.map +1 -0
  72. package/dist/version/codec.js +214 -0
  73. package/dist/version/codec.js.map +1 -0
  74. package/dist/version/registry.d.ts +236 -0
  75. package/dist/version/registry.d.ts.map +1 -0
  76. package/dist/version/registry.js +289 -0
  77. package/dist/version/registry.js.map +1 -0
  78. package/dist/world/block.d.ts +86 -0
  79. package/dist/world/block.d.ts.map +1 -0
  80. package/dist/world/block.js +232 -0
  81. package/dist/world/block.js.map +1 -0
  82. package/dist/world/entity.d.ts +43 -0
  83. package/dist/world/entity.d.ts.map +1 -0
  84. package/dist/world/entity.js +97 -0
  85. package/dist/world/entity.js.map +1 -0
  86. package/dist/world/state.d.ts +151 -0
  87. package/dist/world/state.d.ts.map +1 -0
  88. package/dist/world/state.js +108 -0
  89. package/dist/world/state.js.map +1 -0
  90. package/dist/world/tick.d.ts +19 -0
  91. package/dist/world/tick.d.ts.map +1 -0
  92. package/dist/world/tick.js +49 -0
  93. package/dist/world/tick.js.map +1 -0
  94. package/package.json +7 -2
  95. package/src/base/error.ts +36 -0
  96. package/src/base/typing.ts +9 -1
  97. package/src/client/client.ts +99 -42
  98. package/src/client/tcp.ts +49 -954
  99. package/src/index.ts +12 -12
  100. package/src/{translator → packet}/decoder.ts +3 -3
  101. package/src/packet/dispatcher.ts +785 -0
  102. package/src/{translator → packet}/encoder.ts +20 -9
  103. package/src/{base → physics}/aabb.ts +5 -5
  104. package/src/{base → physics}/player.ts +41 -25
  105. package/src/version/codec.ts +227 -0
  106. package/src/version/registry.ts +333 -0
  107. package/src/{base → world}/block.ts +12 -11
  108. package/src/{base → world}/entity.ts +5 -5
  109. package/src/world/state.ts +232 -0
  110. package/test/adapter/index.ts +14 -0
  111. package/test/client/index.ts +1 -1
  112. package/test/json/index.ts +3 -0
  113. package/src/base/registry.ts +0 -87
  114. /package/assets/minecraft/{blocks.json → 26.2/blocks.json} +0 -0
  115. /package/assets/minecraft/{entities.json → 26.2/entities.json} +0 -0
  116. /package/src/{translator → packet}/static.ts +0 -0
  117. /package/src/{base → physics}/direction.ts +0 -0
  118. /package/src/{base → world}/tick.ts +0 -0
package/src/client/tcp.ts CHANGED
@@ -1,142 +1,19 @@
1
1
  import { Socket, SocketConstructorOpts } from "node:net";
2
2
  import { EventEmitter } from "node:events";
3
- import {
4
- constants as crypto_constants,
5
- createPublicKey,
6
- publicEncrypt,
7
- randomBytes,
8
- createDecipheriv,
9
- createCipheriv,
10
- Cipheriv,
11
- Decipheriv
12
- } from "node:crypto";
13
3
  import { deflateSync, inflateSync } from "node:zlib";
14
4
 
15
5
  import { TypedEmmiter } from "../base/event";
16
- import { BinaryDecoder, getTextFromTextComponent } from "../translator/decoder";
17
- import { BinaryEncoder } from "../translator/encoder";
18
- import { ClientNotReady, MissingAuthOption, SockerIsNotWritable } from "../base/error";
19
- import { computeUUID } from "../base/math";
20
- import { If } from "../base/typing";
21
- import { Angle, BaseVec3 } from "../base/direction";
22
- import { packBlockPos, SectionsPerChunk } from "./static";
23
- import { AuthClient, AuthOption } from "./auth";
6
+ import { BinaryDecoder } from "../packet/decoder";
7
+ import { BinaryEncoder } from "../packet/encoder";
8
+ import { AuthOption } from "./auth";
9
+ import { ClientStatus, ConnectionState, SharedState } from "../world/state";
10
+ import { EncodeResult } from "../version/codec";
11
+ import { TextComponent } from "../base/typing";
12
+ import { MissingAuthOption, SockerIsNotWritable } from "../base/error";
24
13
 
25
14
  // Minecraft related typing
26
- /**
27
- * Representing a TextComponent
28
- *
29
- * @see https://minecraft.wiki/w/Text_component_format
30
- */
31
- export type TextComponent = Record<string, any>;
32
-
33
-
34
- export interface Server {
35
- knownPacks?: ServerKnownPack
36
- }
37
-
38
- export interface ServerKnownPack {
39
- namespace: string,
40
- id: string,
41
- version: string
42
- }
43
-
44
- /**
45
- * Represent world information
46
- */
47
- export interface ServerWorld {
48
- /** Is hardcore enabled */
49
- hardcore: boolean,
50
- /** All dimensions */
51
- dimensions: string[],
52
- /** Max players allowed */
53
- maxPlayers: number,
54
- /** View distances */
55
- viewDistance: number,
56
- /** Simulation distance */
57
- simulationDistance: number,
58
-
59
- /**
60
- * The record key is a chunk section position packed as `Player Dimension:Chunk X:Chunk Z[Section Y]`
61
- *
62
- * For `Section Y`, a chunk is splitted into several cubic 16x16x16 sections, or in other word, a chunk is a bund of 16x16x16 sections stacked on each other.
63
- */
64
- chunks: Record<string, ChunkColumn>,
65
- /**
66
- * The record key is entity ID
67
- */
68
- entities: Record<number, Entity>,
69
- }
70
-
71
- /**
72
- * Represent a chunk collumns, which may contains multiple chunks sections
73
- */
74
- export interface ChunkColumn {
75
- sections: Record<number, ChunkSection>,
76
- blockEntities: Record<number, BlockEntity>
77
- }
78
-
79
- export interface ChunkSection {
80
- block: PaletteContainer,
81
- biome: PaletteContainer,
82
- }
83
-
84
- /**
85
- * Used for indirect mapping
86
- *
87
- * @see https://minecraft.wiki/w/Java_Edition_protocol/Chunk_format#Paletted_Container_structure
88
- */
89
- export interface PaletteContainer {
90
- bpe: number, // Bit per entry
91
- palette: number[],
92
- data: BigInt64Array | null, // null if the whole section contains one 1 type of block
93
- }
94
-
95
- /** Represent a block entity */
96
- export interface BlockEntity {
97
- type: number,
98
- data: Record<string, any>
99
- }
100
-
101
- /** Represent an entity */
102
- export interface Entity {
103
- id: number,
104
- type: number,
105
- position: BaseVec3,
106
- velocity: BaseVec3,
107
- angle: Angle,
108
- data: number
109
- }
110
-
111
- export enum GameMode {
112
- Survival = 0,
113
- Creative = 1,
114
- Adventure = 2,
115
- Spectator = 3
116
- }
117
-
118
- export interface ClientPlayer {
119
- /** Player UUID */
120
- uuid: string,
121
- /** Player username */
122
- username: string,
123
- /** Player entity ID */
124
- entityId: number,
125
- /** Current game mode */
126
- gameMode: GameMode,
127
-
128
- position: BaseVec3,
129
- velocity: BaseVec3,
130
- angle: Angle,
131
15
 
132
- /** Current dimension */
133
- dimension: string
134
- }
135
16
 
136
- export interface ServerRegistryEntry {
137
- id: string,
138
- data: object
139
- }
140
17
 
141
18
  // TCP related typing
142
19
  export interface TCPClientOption {
@@ -175,71 +52,21 @@ export interface TCPClientOption {
175
52
 
176
53
  export interface TCPClientEvents {
177
54
  connect: [],
178
- disconnect: [reason: string],
179
- disconnectRaw: [textComponent: TextComponent],
180
- raw: [buf: Buffer],
181
-
182
- /** Whenever client is ready to use */
183
- ready: [readyClient: TCPClient<true>],
184
-
185
- // Position
186
- /**
187
- * Sync player position.
188
- *
189
- * Noted that this fired when recived packet from server, not from the internal movement, meaning that calling `input` function would not fire this event.
190
- */
191
- playerPosition: [position: BaseVec3],
192
-
193
- /** Load chunk section */
194
- loadChunk: [chunkX: number, sectionY: number, chunkZ: number],
195
- /** Unload chunk column */
196
- unloadChunk: [chunkX: number, chunkZ: number],
197
-
198
- /** Spawn an entity */
199
- spawnEntity: [entity: Entity],
200
- /** Update spawned entity */
201
- updateEntity: [entity: Entity],
202
- /** Remove entity */
203
- removeEntity: [entityId: number],
204
-
205
- // Chat
206
- /** Message, usually sent from player */
207
- message: [message: Message],
208
- /** Parsed system message, usually sent from the console, plugins, etc... */
209
- systemMessage: [message: string],
210
- /** Raw system messgae */
211
- systemMessageRaw: [textComponent: TextComponent],
212
- /** Parsed action bar message, the message appeared above your hot bar */
213
- actionBar: [message: string],
214
- /** Raw action bar */
215
- actionBarRaw: [textComponent: TextComponent],
55
+ raw: [buffer: Buffer]
56
+ destroy: [],
216
57
  }
217
58
 
218
59
  export interface Message {
219
60
  sender: string,
220
- target?: string,
61
+ target: string | undefined,
221
62
  content: string,
222
63
  raw: {
223
64
  sender: TextComponent,
224
- target?: TextComponent,
225
- content?: TextComponent
65
+ target: TextComponent | undefined,
66
+ content: TextComponent | undefined
226
67
  }
227
68
  }
228
69
 
229
- export enum ClientStatus {
230
- Disconnected,
231
- Connecting,
232
- Logining,
233
- Ready,
234
- }
235
-
236
- export enum ClientState {
237
- Disconnected,
238
- Handshake,
239
- Login,
240
- Configure,
241
- Play
242
- }
243
70
 
244
71
  // export enum TCPServerIntent {
245
72
  // Status = 1,
@@ -252,11 +79,9 @@ export enum ClientState {
252
79
  *
253
80
  * @see https://minecraft.wiki/w/Java_Edition_protocol/Packets?oldid=3445844
254
81
  */
255
- export class TCPClient<IsReady extends boolean = boolean> extends (EventEmitter as new () => TypedEmmiter<TCPClientEvents>) {
82
+ export class TCPClient extends (EventEmitter as new () => TypedEmmiter<TCPClientEvents>) {
256
83
  public readonly socket: Socket;
257
84
 
258
- public server: Server | undefined = undefined;
259
-
260
85
  // Internal var
261
86
  /**
262
87
  * | Value | Meaning |
@@ -265,56 +90,29 @@ export class TCPClient<IsReady extends boolean = boolean> extends (EventEmitter
265
90
  * | -1 | dont compress |
266
91
  * | > 0 | compression threshold |
267
92
  */
268
- private compressionThreshold: number = 0;
269
93
  private bufferPool: Buffer = Buffer.alloc(0);
270
- public status: ClientStatus = ClientStatus.Disconnected;
271
- private state: ClientState = ClientState.Disconnected;
272
-
273
- // Encryption
274
- private sharedSecret: Buffer | undefined = undefined;
275
- private cipher: Cipheriv | undefined = undefined;
276
- private decipher: Decipheriv | undefined = undefined;
277
-
278
- // Play data
279
- public world?: If<IsReady, ServerWorld>;
280
- public player?: If<IsReady, ClientPlayer>;
281
- public registry?: If<IsReady, Record<string, ServerRegistryEntry[]>>;
282
-
283
- // Initial data
284
- private playerUUID?: Buffer;
285
94
 
286
95
  constructor(
96
+ private state: SharedState,
287
97
  public readonly option: TCPClientOption,
288
- socketOption?: SocketConstructorOpts
98
+ socketOption?: SocketConstructorOpts,
289
99
  ) {
290
100
  super();
291
101
  this.socket = new Socket(socketOption);
292
- this.wipePlayData();
293
102
 
294
103
  if (!option.isOffline && !option.auth)
295
104
  throw new MissingAuthOption();
296
105
  }
297
106
 
298
- private wipePlayData() {
299
- this.world = null as any;
300
- this.player = null as any;
301
- this.registry = null as any;
302
- }
107
+ public sendInitPacket: () => void = () => { throw new Error("method not implemented"); };
108
+ public forwardPacket: (packetId: number, decoder: BinaryDecoder) => void = (...args) => { throw new Error("method not implemented"); };
109
+ public parsePacket: (packetId: string | number, data: object) => EncodeResult = (...args) => { throw new Error("method not implemented"); };
303
110
 
304
111
  /**
305
112
  * Connect to server
306
113
  */
307
114
  public async connect() {
308
- if (!this.playerUUID) {
309
- if (this.option.auth) {
310
- const authClient = new AuthClient(this.option.auth);
311
- const { uuid } = await authClient.auth();
312
- this.playerUUID = Buffer.from(uuid);
313
- } else
314
- this.playerUUID = computeUUID(this.option.playerName);
315
- }
316
-
317
- this.status = ClientStatus.Connecting;
115
+ this.state.status = ClientStatus.Connecting;
318
116
  const connection = this.socket.connect({
319
117
  host: this.option.host,
320
118
  port: this.option.port
@@ -322,30 +120,30 @@ export class TCPClient<IsReady extends boolean = boolean> extends (EventEmitter
322
120
 
323
121
  connection.on("connect", () => {
324
122
  this.emit("connect");
325
- this.wipePlayData();
326
- this.sendHandshake();
327
- this.sendLoginStart();
123
+ this.sendInitPacket();
328
124
  });
329
125
  connection.on("data", (data) => {
330
126
  let buf = Buffer.from(data);
331
- if (this.decipher) {
332
- buf = this.decipher.update(buf);
127
+ if (this.state.decipher) {
128
+ buf = this.state.decipher.update(buf);
333
129
  }
334
130
  this.emit("raw", Buffer.from(buf));
335
131
  this.bufferPool = Buffer.concat([this.bufferPool, buf]);
336
132
  this.handlePacket();
337
133
  });
338
134
  connection.once("end", () => {
339
- if (this.status === ClientStatus.Disconnected) return;
340
- this.status = ClientStatus.Disconnected;
341
- this.state = ClientState.Disconnected;
342
- this.emit("disconnect", "socket close");
135
+ this.emit("destroy");
136
+ if (this.state.status === ClientStatus.Disconnected) return;
137
+ this.state.status = ClientStatus.Disconnected;
138
+ this.state.state = ConnectionState.Disconnected;
139
+ // this.emit("disconnect", "socket close");
343
140
  });
344
141
  connection.once("close", () => {
345
- if (this.status === ClientStatus.Disconnected) return;
346
- this.status = ClientStatus.Disconnected;
347
- this.state = ClientState.Disconnected;
348
- this.emit("disconnect", "socket close");
142
+ this.emit("destroy");
143
+ if (this.state.status === ClientStatus.Disconnected) return;
144
+ this.state.status = ClientStatus.Disconnected;
145
+ this.state.state = ConnectionState.Disconnected;
146
+ // this.emit("disconnect", "socket close");
349
147
  });
350
148
  }
351
149
 
@@ -354,16 +152,6 @@ export class TCPClient<IsReady extends boolean = boolean> extends (EventEmitter
354
152
  this.socket.destroy();
355
153
  }
356
154
 
357
- public isReady(): this is TCPClient<true> {
358
- return this.status === ClientStatus.Ready;
359
- }
360
-
361
- public checkReady() {
362
- if (!this.isReady())
363
- throw new ClientNotReady();
364
- return true;
365
- }
366
-
367
155
  /*
368
156
  * Read packet
369
157
  */
@@ -384,9 +172,9 @@ export class TCPClient<IsReady extends boolean = boolean> extends (EventEmitter
384
172
  const expectedPacketEnd = decoder.offset + packetLength;
385
173
 
386
174
  let packetID: number;
387
- if (this.compressionThreshold === 0)
175
+ if (this.state.compressionThreshold === 0)
388
176
  packetID = decoder.readVarInt();
389
- else if (this.compressionThreshold === -1) {
177
+ else if (this.state.compressionThreshold === -1) {
390
178
  decoder.readVarInt();
391
179
  packetID = decoder.readVarInt();
392
180
  } else {
@@ -400,600 +188,38 @@ export class TCPClient<IsReady extends boolean = boolean> extends (EventEmitter
400
188
  packetID = decoder.readVarInt();
401
189
  }
402
190
  }
403
-
404
- // Debug
405
- if (this.option.debug?.packetLogger)
406
- console.dir({
407
- state: ClientState[this.state],
408
- packetID: "0x" + packetID.toString(16),
409
- length: decoder.buffer.length
410
- });
411
-
412
- switch (packetID) {
413
- case 0x00:
414
- if (this.state === ClientState.Login) this.handleLoginDisconnect(decoder);
415
- break;
416
- case 0x01:
417
- if (this.state === ClientState.Login) this.handleEncryption(decoder);
418
- if (this.state === ClientState.Play) this.handleSpawnEntity(decoder);
419
- break;
420
- case 0x02:
421
- if (this.state === ClientState.Configure) this.handleConfiguarionPlayDisconnect(decoder);
422
- if (this.state === ClientState.Login) this.handleLoginSucess(decoder);
423
- break;
424
- case 0x03:
425
- if (this.state === ClientState.Login) this.handleSetCompression(decoder);
426
- if (this.state === ClientState.Configure) this.sendConfigureAck();
427
- break;
428
- case 0x06:
429
- if (this.state === ClientState.Play) this.handleBlockEntityData(decoder);
430
- break;
431
- case 0x07:
432
- if (this.state === ClientState.Configure) this.handleRegistryData(decoder);
433
- break;
434
- case 0x0A:
435
- if (this.state === ClientState.Play) this.handleChangeGameMode(decoder);
436
- break;
437
- case 0x0E:
438
- if (this.state === ClientState.Configure) this.handleKnownPack(decoder);
439
- break;
440
- case 0x20:
441
- if (this.state === ClientState.Play) this.handleConfiguarionPlayDisconnect(decoder);
442
- break;
443
- case 0x21:
444
- if (this.state === ClientState.Play) this.handleDisguisedChatMessage(decoder);
445
- break;
446
- case 0x23:
447
- if (this.state === ClientState.Play) this.handleTeleportEntity(decoder);
448
- break;
449
- case 0x25:
450
- if (this.state === ClientState.Play) this.handleUnloadChunk(decoder);
451
- break;
452
- case 0x2D:
453
- if (this.state === ClientState.Play) this.handleChunkData(decoder);
454
- break;
455
- case 0x2C:
456
- if (this.state === ClientState.Play) this.handleKeepAlive(decoder);
457
- break;
458
- case 0x31:
459
- if (this.state === ClientState.Play) this.handlePlayLogin(decoder);
460
- break;
461
- case 0x35:
462
- if (this.state === ClientState.Play) this.handleUpdateEntityPosition(decoder);
463
- break;
464
- case 0x36:
465
- if (this.state === ClientState.Play) this.handleUpdateEntityPositionRotation(decoder);
466
- break;
467
- case 0x41:
468
- if (this.state === ClientState.Play) this.handlePlayerChat(decoder);
469
- break;
470
- case 0x48:
471
- if (this.state === ClientState.Play) this.handleSynchronizePlayerPosition(decoder);
472
- break;
473
- case 0x4D:
474
- if (this.state === ClientState.Play) this.handleRemoveEntity(decoder);
475
- break;
476
- case 0x57:
477
- if (this.state === ClientState.Play) this.handleSetActionBar(decoder);
478
- break;
479
- case 0x65:
480
- if (this.state === ClientState.Play) this.handleSetEntityVelocity(decoder);
481
- break;
482
- case 0x79:
483
- if (this.state === ClientState.Play) this.handleSystemMessage(decoder);
484
- break;
485
- }
191
+ this.forwardPacket(packetID, decoder);
486
192
 
487
193
  this.bufferPool = this.bufferPool.subarray(expectedPacketEnd);
488
194
  }
489
195
  }
490
196
 
491
- // Login
492
-
493
- private handleLoginDisconnect(decoder: BinaryDecoder) {
494
- const reason = JSON.parse(decoder.readString());
495
- const text = getTextFromTextComponent(reason);
496
-
497
- this.status = ClientStatus.Disconnected;
498
- this.state = ClientState.Disconnected;
499
- this.wipePlayData();
500
-
501
- this.emit("disconnect", text.toString());
502
- this.emit("disconnectRaw", reason);
503
- this.disconnect();
504
- }
505
-
506
- private handleEncryption(decoder: BinaryDecoder) {
507
- const serverId = decoder.readString(); // Should be ignored in 1.7+ server
508
- const publicKey = decoder.readRawPrefixedArray(8);
509
- const verifyToken = decoder.readRawPrefixedArray(8);
510
- const shoudlCallMojang = decoder.readBoolean(); // I'm too lazy to do this D:
511
-
512
- const sharedSecret = randomBytes(16);
513
- this.sharedSecret = sharedSecret;
514
- this.cipher = createCipheriv("aes-128-cfb8", this.sharedSecret, this.sharedSecret);
515
- this.decipher = createDecipheriv("aes-128-cfb8", this.sharedSecret, this.sharedSecret);
516
-
517
- this.sendEncryptionResponse(publicKey, verifyToken);
518
- }
519
-
520
- private handleSetCompression(decoder: BinaryDecoder) {
521
- const threshold = decoder.readVarInt();
522
- if (threshold < 0) this.compressionThreshold = -1;
523
- else this.compressionThreshold = threshold;
524
- }
525
-
526
- private handleLoginSucess(decoder: BinaryDecoder) {
527
- const uuid = decoder.readUUID();
528
- const username = decoder.readString();
529
- this.player = {
530
- uuid,
531
- username,
532
- entityId: 0,
533
- dimension: "",
534
- gameMode: GameMode.Survival,
535
-
536
- position: {
537
- x: 0,
538
- y: 0,
539
- z: 0,
540
- },
541
- velocity: {
542
- x: 0,
543
- y: 0,
544
- z: 0,
545
- },
546
- angle: {
547
- yaw: 0,
548
- pitch: 0,
549
- }
550
- } satisfies ClientPlayer as any;
551
- this.sendLoginAck();
552
- }
553
-
554
- // Configure
555
-
556
- private handleKnownPack(decoder: BinaryDecoder) {
557
- const packs = decoder.readPrefixedArray((decoder) => ({
558
- namespace: decoder.readString(),
559
- id: decoder.readString(),
560
- version: decoder.readString()
561
- }));
562
- this.server!.knownPacks = packs satisfies ServerKnownPack[] as any;
563
- // this.sendKnownPack(this.option.loadRegistry === true ? [] : packs);
564
- this.sendKnownPack([]);
565
- }
566
-
567
- private handleRegistryData(decoder: BinaryDecoder) {
568
- const id = decoder.readString();
569
- const entries = decoder.readPrefixedArray((decoder) => ({
570
- id: decoder.readString(),
571
- data: decoder.readPrefixedOptional((decoder) => decoder.readNBT())
572
- }));
573
-
574
- if (!this.registry) this.registry = {} as any;
575
- const registry = this.registry as Record<string, any[]>;
576
- if (!(id in registry)) registry[id] = [];
577
- registry[id]!.push(...entries);
578
- }
579
-
580
- private handleConfiguarionPlayDisconnect(decoder: BinaryDecoder) {
581
- const reason = decoder.readNBT();
582
- const text = getTextFromTextComponent(reason);
583
-
584
- this.status = ClientStatus.Disconnected;
585
- this.state = ClientState.Disconnected;
586
- this.wipePlayData();
587
-
588
- this.emit("disconnect", text.toString());
589
- this.emit("disconnectRaw", reason);
590
- this.disconnect();
591
- }
592
-
593
- // Play
594
-
595
- private handlePlayLogin(decoder: BinaryDecoder) {
596
- const entityId = decoder.readInt(),
597
- isHardcore = decoder.readBoolean(),
598
- dimensions = decoder.readPrefixedArray((decoder) => decoder.readString()),
599
- maxPlayers = decoder.readVarInt(),
600
- viewDistance = decoder.readVarInt(),
601
- simulationDistance = decoder.readVarInt();
602
- decoder.readBoolean(); // Reduced Debug Info
603
- decoder.readBoolean(); // Enable respawn screen
604
- decoder.readBoolean(); // Do limited crafting
605
- decoder.readVarInt(); // Dimension Type
606
- const dimensionName = decoder.readString();
607
- decoder.readLong(); // Hashed seed
608
- const gameMode = decoder.readUByte();
609
-
610
- this.world = {
611
- hardcore: isHardcore,
612
- dimensions,
613
- maxPlayers,
614
- viewDistance,
615
- simulationDistance,
616
- chunks: {},
617
- entities: {}
618
- } satisfies ServerWorld as any; // To avoid type conflict
619
- this.player!.dimension = dimensionName;
620
- this.player!.entityId = entityId;
621
- this.player!.gameMode = gameMode;
622
-
623
- this.status = ClientStatus.Ready;
624
- this.emit("ready", this as TCPClient<true>);
625
- }
626
-
627
- private handleSynchronizePlayerPosition(decoder: BinaryDecoder) {
628
- const teleportId = decoder.readVarInt();
629
- const x = decoder.readDouble(),
630
- y = decoder.readDouble(),
631
- z = decoder.readDouble(),
632
- velX = decoder.readDouble(),
633
- velY = decoder.readDouble(),
634
- velZ = decoder.readDouble(),
635
- yaw = decoder.readFloat() % 360,
636
- pitch = decoder.readFloat() % 360;
637
- const flag = decoder.readTeleportFlag();
638
-
639
- const { position, velocity, angle } = this.player!;
640
- let { x: newPosX, y: newPosY, z: newPosZ } = position;
641
- let { x: newVelX, y: newVelY, z: newVelZ } = velocity;
642
- let { yaw: newYaw, pitch: newPitch } = angle;
643
- if (flag.x) newPosX += x; else newPosX = x;
644
- if (flag.y) newPosY += y; else newPosY = y;
645
- if (flag.z) newPosZ += z; else newPosZ = z;
646
- if (flag.velX) newVelX += velX; else newVelX = velX;
647
- if (flag.velY) newVelY += velY; else newVelY = velY;
648
- if (flag.velZ) newVelZ += velZ; else newVelZ = velZ;
649
- if (flag.yaw) newYaw += yaw; else newYaw = yaw;
650
- if (flag.pitch) newPitch += pitch; else newPitch = pitch;
651
- const newPosition = { x: newPosX, y: newPosY, z: newPosZ },
652
- newVelocity = { x: newVelX, y: newVelY, z: newVelZ },
653
- newAngle = { yaw: newYaw, pitch: newPitch };
654
- this.player = {
655
- ...this.player!,
656
- position: newPosition,
657
- velocity: newVelocity,
658
- angle: newAngle,
659
- } satisfies ClientPlayer as any;
660
- this.emit("playerPosition", { x: newPosX, y: newPosY, z: newPosZ });
661
- this.sendConfirmTeleportation(teleportId);
662
- this.sendPlayerPosRot(newPosition, newAngle, true, false);
663
- }
664
-
665
- private handleKeepAlive(decoder: BinaryDecoder) {
666
- const aliveID = decoder.readLong();
667
- this.sendKeepAlive(aliveID);
668
- }
669
-
670
- private handleChangeGameMode(decoder: BinaryDecoder) {
671
- const gameMode = decoder.readUByte();
672
- this.player!.gameMode = gameMode;
673
- }
674
-
675
- // Chunk
676
- private handleChunkData(decoder: BinaryDecoder) {
677
- const chunkX = decoder.readInt(),
678
- chunkZ = decoder.readInt(),
679
- heightMaps = decoder.readPrefixedArray(decoder => ({
680
- type: decoder.readVarInt(),
681
- data: decoder.readPrefixedArray(decoder => decoder.readLong())
682
- })), // Not used yet
683
- chunkData = decoder.readPrefixedArray(decoder => decoder.readByte()),
684
- blockEntities = decoder.readPrefixedArray(decoder => {
685
- const packedXZ = decoder.readByte(),
686
- y = decoder.readShort(),
687
- type = decoder.readVarInt(),
688
- nbt = decoder.readNBT();
689
- const x = (packedXZ >> 4) & 15, z = packedXZ & 15;
690
- const packedPosition = packBlockPos(x, y, z);
691
- return { packedPosition, type, nbt };
692
- });
693
-
694
- // this.world!.chunks[`${this.player!.dimension}:${chunkX}:${chunkZ}`] = [];
695
- const chunkSections: Record<number, ChunkSection> = {};
696
-
697
- const chunkDataDecoder = new BinaryDecoder(Buffer.from(chunkData));
698
- for (let height = 0; height < (SectionsPerChunk[this.player!.dimension] || 0); height++) {
699
- const blockCount = chunkDataDecoder.readShort();
700
- const fluidCount = chunkDataDecoder.readShort();
701
-
702
- // Blocks
703
- let blockStateBPE = chunkDataDecoder.readUByte();
704
- let blockStatePalettes: number[] = [];
705
-
706
- if (blockStateBPE === 0) {
707
- blockStatePalettes = [chunkDataDecoder.readVarInt()];
708
- } else if (blockStateBPE <= 8) {
709
- // Indirect palette
710
- if (blockStateBPE < 4) blockStateBPE = 4; // BPE smaller than 4 will be rounđe up to 4
711
- blockStatePalettes = chunkDataDecoder.readPrefixedArray(decoder => decoder.readVarInt());
712
- } else {
713
- // Direct palette (no palette array)
714
- }
715
-
716
- const blockEntriesPerSection = 4096;
717
- const blockEntriesPerLong = Math.floor(64 / blockStateBPE);
718
- let blockDataArray: BigInt64Array | null = null;
719
- if (blockStateBPE !== 0) {
720
- const blockDataArrayLength = Math.floor((blockEntriesPerSection + blockEntriesPerLong - 1) / blockEntriesPerLong);
721
- blockDataArray = new BigInt64Array(chunkDataDecoder.readArray(blockDataArrayLength, (decoder) => decoder.readLong()));
722
- }
723
-
724
- // Biomes - Not used yet, but need to be read to advance decoder
725
- const biomeBPE = chunkDataDecoder.readUByte();
726
- let biomePalettes: number[] = [];
727
- if (biomeBPE === 0) {
728
- biomePalettes = [chunkDataDecoder.readVarInt()]; // Palette value
729
- } else if (biomeBPE <= 3) {
730
- // Indirect palette
731
- biomePalettes = chunkDataDecoder.readPrefixedArray(decoder => decoder.readVarInt());
732
- } else {
733
- // Direct palette (no palette array)
734
- }
735
-
736
- const biomeEntriesPerSection = 64;
737
- const biomeEntriesPerLong = Math.floor(64 / biomeBPE);
738
- let biomeDataArray: BigInt64Array | null = null;
739
- if (biomeBPE !== 0) {
740
- const biomeDataArrayLength = Math.floor((biomeEntriesPerSection + biomeEntriesPerLong - 1) / biomeEntriesPerLong);
741
- biomeDataArray = new BigInt64Array(chunkDataDecoder.readArray(biomeDataArrayLength, (decoder) => decoder.readLong()));
742
- }
743
-
744
- chunkSections[height] = {
745
- block: {
746
- bpe: blockStateBPE,
747
- palette: blockStatePalettes,
748
- data: blockDataArray
749
- },
750
- biome: {
751
- bpe: biomeBPE,
752
- palette: biomePalettes,
753
- data: biomeDataArray
754
- }
755
- };
756
- this.emit("loadChunk", chunkX, height, chunkZ);
757
- }
758
-
759
- const blockEntitiesObj: Record<number, BlockEntity> = Object.fromEntries(
760
- blockEntities.map(val => [val.packedPosition, { type: val.type, data: val.nbt }])
761
- );
762
-
763
- this.world!.chunks[`${this.player!.dimension}:${chunkX}:${chunkZ}`] = {
764
- sections: chunkSections,
765
- blockEntities: blockEntitiesObj
766
- };
767
- }
768
-
769
- private handleUnloadChunk(decoder: BinaryDecoder) {
770
- const chunkZ = decoder.readInt(),
771
- chunkX = decoder.readInt();
772
- delete this.world!.chunks[`${this.player!.dimension}:${chunkX}:${chunkZ}`];
773
- this.emit("unloadChunk", chunkX, chunkZ);
774
- }
775
-
776
- private handleBlockEntityData(decoder: BinaryDecoder) {
777
- const location = decoder.readPosition(),
778
- type = decoder.readVarInt(),
779
- data = decoder.readNBT();
780
-
781
- const chunkX = Math.floor(location.x / 16),
782
- chunkZ = Math.floor(location.z / 16);
783
- const xWitinChunk = location.x % 16,
784
- zWitinChunk = location.z % 16;
785
- const packedPosition = packBlockPos(xWitinChunk, location.y, zWitinChunk);
786
- if (`${this.player!.dimension}:${chunkX}:${chunkZ}` in this.world!.chunks)
787
- this.world!.chunks[`${this.player!.dimension}:${chunkX}:${chunkZ}`]!.blockEntities[packedPosition] = {
788
- type,
789
- data
790
- };
791
- }
792
-
793
- // Entity
794
- private handleSpawnEntity(decoder: BinaryDecoder) {
795
- const id = decoder.readVarInt(),
796
- UUID = decoder.readUUID(),
797
- type = decoder.readVarInt(),
798
- x = decoder.readDouble(),
799
- y = decoder.readDouble(),
800
- z = decoder.readDouble(),
801
- velocity = decoder.readLpVec3(),
802
- pitch = decoder.readAngle(),
803
- yaw = decoder.readAngle(),
804
- headYaw = decoder.readAngle(),
805
- data = decoder.readVarInt();
806
-
807
- this.world!.entities[id] = {
808
- id,
809
- type,
810
- position: { x, y, z },
811
- velocity,
812
- angle: {
813
- pitch,
814
- yaw
815
- },
816
- data
817
- };
818
- this.emit("spawnEntity", this.world!.entities[id]!);
819
- }
820
-
821
- private handleTeleportEntity(decoder: BinaryDecoder) {
822
- const id = decoder.readVarInt(),
823
- x = decoder.readDouble(),
824
- y = decoder.readDouble(),
825
- z = decoder.readDouble(),
826
- velX = decoder.readDouble(),
827
- velY = decoder.readDouble(),
828
- velZ = decoder.readDouble(),
829
- pitch = decoder.readAngle(),
830
- yaw = decoder.readAngle();
831
-
832
- if (id in this.world!.entities) {
833
- this.world!.entities[id]!.position = { x, y, z };
834
- this.world!.entities[id]!.velocity = { x: velX, y: velY, z: velZ };
835
- this.world!.entities[id]!.angle = { pitch, yaw };
836
- this.emit("updateEntity", this.world!.entities[id]!);
837
- }
838
- }
839
-
840
- private handleUpdateEntityPosition(decoder: BinaryDecoder) {
841
- const id = decoder.readVarInt(),
842
- delX = decoder.readFixedPoint(decoder.readShort(), 12),
843
- delY = decoder.readFixedPoint(decoder.readShort(), 12),
844
- delZ = decoder.readFixedPoint(decoder.readShort(), 12);
845
-
846
- if (id in this.world!.entities) {
847
- let { x, y, z } = this.world!.entities[id]!.position;
848
- x += delX;
849
- y += delY;
850
- z += delZ;
851
- this.world!.entities[id]!.position = { x, y, z };
852
- this.emit("updateEntity", this.world!.entities[id]!);
853
- }
854
- }
855
-
856
- private handleUpdateEntityPositionRotation(decoder: BinaryDecoder) {
857
- const id = decoder.readVarInt(),
858
- delX = decoder.readFixedPoint(decoder.readShort(), 12),
859
- delY = decoder.readFixedPoint(decoder.readShort(), 12),
860
- delZ = decoder.readFixedPoint(decoder.readShort(), 12),
861
- pitch = decoder.readAngle(),
862
- yaw = decoder.readAngle();
863
-
864
- if (id in this.world!.entities) {
865
- let { x, y, z } = this.world!.entities[id]!.position;
866
- x += delX;
867
- y += delY;
868
- z += delZ;
869
- this.world!.entities[id]!.position = { x, y, z };
870
- this.world!.entities[id]!.angle = { yaw, pitch };
871
- this.emit("updateEntity", this.world!.entities[id]!);
872
- }
873
- }
874
-
875
- private handleSetEntityVelocity(decoder: BinaryDecoder) {
876
- const entityId = decoder.readVarInt(),
877
- velocity = decoder.readLpVec3();
878
-
879
- if (entityId in this.world!.entities)
880
- this.world!.entities[entityId]!.velocity = velocity;
881
- }
882
-
883
- private handleRemoveEntity(decoder: BinaryDecoder) {
884
- const entities = decoder.readPrefixedArray((decoder) => decoder.readVarInt());
885
-
886
- for (const entityId of entities) {
887
- delete this.world!.entities[entityId];
888
- this.emit("removeEntity", entityId);
889
- }
890
- }
891
-
892
- // Chat
893
- private handlePlayerChat(decoder: BinaryDecoder) {
894
- const globalIndex = decoder.readVarInt(),
895
- senderUUID = decoder.readUUID(),
896
- index = decoder.readVarInt(),
897
- messageSignature = decoder.readPrefixedOptional(decoder => decoder.readArray(256, decoder => decoder.readByte())),
898
- message = decoder.readString(),
899
- timestamp = decoder.readLong(),
900
- salt = decoder.readLong(),
901
- previousMessages = decoder.readPrefixedArray(decoder => {
902
- const id = decoder.readVarInt();
903
- let signature;
904
- if (id === 0)
905
- signature = decoder.readArray(256, decoder => decoder.readByte());
906
- return { id, signature };
907
- }),
908
- unsignedContent = decoder.readPrefixedOptional(decoder => decoder.readNBT()), // Text component
909
- filterType = decoder.readVarInt(),
910
- filterTypeBits = filterType === 1 ? decoder.readPrefixedArray(decoder => decoder.readLong()) : undefined,
911
- chatType = decoder.readIdOrX(decoder => decoder.readChatType()),
912
- senderName = decoder.readNBT(),
913
- targetName = decoder.readPrefixedOptional(decoder => decoder.readNBT());
914
-
915
- const senderNameText = getTextFromTextComponent(senderName).toString(),
916
- targetNameText = targetName ?? getTextFromTextComponent(targetName).toString();
917
-
918
- this.emit("message", {
919
- sender: senderNameText,
920
- target: targetNameText,
921
- content: message,
922
- raw: {
923
- sender: senderName,
924
- target: targetName,
925
- content: unsignedContent,
926
- }
927
- });
928
- }
929
-
930
- private handleSystemMessage(decoder: BinaryDecoder) {
931
- const content = decoder.readNBT(),
932
- isActionbar = decoder.readBoolean();
933
- const text = getTextFromTextComponent(content);
934
-
935
- if (isActionbar) {
936
- this.emit("actionBar", text.toString());
937
- this.emit("actionBarRaw", content);
938
- } else {
939
- this.emit("systemMessage", text.toString());
940
- this.emit("systemMessageRaw", content);
941
- }
942
- }
943
-
944
- private handleSetActionBar(decoder: BinaryDecoder) {
945
- const content = decoder.readNBT();
946
- const text = getTextFromTextComponent(content);
947
- this.emit("actionBar", text.toString());
948
- this.emit("actionBarRaw", content);
949
- }
950
-
951
- private handleDisguisedChatMessage(decoder: BinaryDecoder) {
952
- const message = decoder.readNBT(),
953
- chatType = decoder.readChatType(),
954
- senderName = decoder.readNBT(),
955
- targetName = decoder.readPrefixedOptional(decoder => decoder.readNBT());
956
- const messageText = getTextFromTextComponent(message).toString(),
957
- senderNameText = getTextFromTextComponent(senderName).toString(),
958
- targetNameText = targetName ?? getTextFromTextComponent(targetName).toString();
959
- this.emit("message", {
960
- sender: senderNameText,
961
- target: targetNameText,
962
- content: messageText,
963
- raw: {
964
- sender: senderName,
965
- target: targetName,
966
- content: message,
967
- }
968
- });
969
- }
970
-
971
197
  /*
972
- * Send packet
973
- */
974
-
198
+ * Send packet
199
+ */
975
200
  public write(buf: Buffer) {
976
- if (this.status == ClientStatus.Disconnected || !this.socket.writable)
201
+ if (!this.socket.writable)
977
202
  throw new SockerIsNotWritable();
978
203
 
979
204
  let sendBuffer = buf;
980
- if (this.cipher)
981
- sendBuffer = this.cipher.update(sendBuffer);
205
+ if (this.state.cipher)
206
+ sendBuffer = this.state.cipher.update(sendBuffer);
982
207
 
983
208
  this.socket.write(sendBuffer);
984
209
  }
985
210
 
986
- public sendPacket(packetId: number, content: Buffer) {
211
+ public sendPacket(packetId: number | string, data: Record<string, any>) {
212
+ const { buffer: content, packet } = this.parsePacket(packetId, data);
987
213
  const encodePacketId = new BinaryEncoder();
988
- encodePacketId.writeVarInt(packetId);
214
+ encodePacketId.writeVarInt(packet.id);
989
215
  const sendData = Buffer.concat([encodePacketId.getBuffer(), content]);
990
216
 
991
- let packet: Buffer;
992
- if (this.compressionThreshold !== 0) {
217
+ let sendingPacket: Buffer;
218
+ if (this.state.compressionThreshold !== 0) {
993
219
  let data: Buffer;
994
220
  let uncompressedLength: number;
995
221
 
996
- if (this.compressionThreshold > 0 && sendData.length > this.compressionThreshold) {
222
+ if (this.state.compressionThreshold > 0 && sendData.length > this.state.compressionThreshold) {
997
223
  uncompressedLength = sendData.length;
998
224
  data = deflateSync(sendData);
999
225
  } else {
@@ -1007,145 +233,14 @@ export class TCPClient<IsReady extends boolean = boolean> extends (EventEmitter
1007
233
 
1008
234
  const packetLengthEncoder = new BinaryEncoder();
1009
235
  packetLengthEncoder.writeVarInt(dataLengthBuf.length + data.length);
1010
- packet = Buffer.concat([packetLengthEncoder.getBuffer(), dataLengthBuf, data]);
236
+ sendingPacket = Buffer.concat([packetLengthEncoder.getBuffer(), dataLengthBuf, data]);
1011
237
  } else {
1012
238
  const packetLengthEncoder = new BinaryEncoder();
1013
239
  packetLengthEncoder.writeVarInt(sendData.length);
1014
- packet = Buffer.concat([packetLengthEncoder.getBuffer(), sendData]);
240
+ sendingPacket = Buffer.concat([packetLengthEncoder.getBuffer(), sendData]);
1015
241
  }
1016
242
 
1017
- this.write(packet);
243
+ this.write(sendingPacket);
1018
244
  }
1019
245
 
1020
- // Login
1021
-
1022
- private sendHandshake() {
1023
- this.state = ClientState.Handshake;
1024
- const encoder = new BinaryEncoder();
1025
- encoder.writeVarInt(this.option.protocolVersion);
1026
- encoder.writeString(this.option.host);
1027
- encoder.writeUShort(this.option.port);
1028
- encoder.writeVarInt(2);
1029
- this.sendPacket(0x00, encoder.getBuffer());
1030
- }
1031
-
1032
- private sendLoginStart() {
1033
- this.state = ClientState.Login;
1034
- this.status = ClientStatus.Logining;
1035
- const encoder = new BinaryEncoder();
1036
- const playerName = this.option.playerName;
1037
- const playerUUID = this.playerUUID!;
1038
- encoder.writeString(playerName);
1039
- encoder.concat(playerUUID);
1040
- this.sendPacket(0x00, encoder.getBuffer());
1041
- }
1042
-
1043
- private sendEncryptionResponse(publicKey: Buffer, verifyToken: Buffer) {
1044
- const encryptedSecret = publicEncrypt({
1045
- key: createPublicKey({ key: publicKey, format: 'der', type: 'spki' }),
1046
- padding: crypto_constants.RSA_PKCS1_PADDING
1047
- }, this.sharedSecret!);
1048
- const encryptedVerifyToken = publicEncrypt({
1049
- key: createPublicKey({ key: publicKey, format: 'der', type: 'spki' }),
1050
- padding: crypto_constants.RSA_PKCS1_PADDING
1051
- }, verifyToken);
1052
- const encoder = new BinaryEncoder();
1053
- encoder.writeRawPrefixedArray(encryptedSecret, 8);
1054
- encoder.writeRawPrefixedArray(encryptedVerifyToken, 8);
1055
- this.sendPacket(0x01, encoder.getBuffer());
1056
- }
1057
-
1058
- private sendLoginAck() {
1059
- this.state = ClientState.Configure;
1060
- this.server = {};
1061
- this.sendPacket(0x03, Buffer.alloc(0));
1062
- }
1063
-
1064
- // Configuring
1065
-
1066
- private sendKnownPack(knownPacks: ServerKnownPack[]) {
1067
- const encoder = new BinaryEncoder();
1068
- encoder.writePrefixedArray(knownPacks.length, (encoder, ind) => {
1069
- const pack = knownPacks[ind]!;
1070
- return encoder
1071
- .writeString(pack.namespace)
1072
- .writeString(pack.id)
1073
- .writeString(pack.version);
1074
- });
1075
- this.sendPacket(0x07, encoder.getBuffer());
1076
- }
1077
-
1078
- private sendConfigureAck() {
1079
- this.state = ClientState.Play;
1080
- this.sendPacket(0x3, Buffer.alloc(0));
1081
- }
1082
-
1083
- // Play
1084
-
1085
- private sendConfirmTeleportation(teleportId: number) {
1086
- const encoder = new BinaryEncoder();
1087
- encoder.writeVarInt(teleportId);
1088
- this.sendPacket(0, encoder.getBuffer());
1089
- }
1090
-
1091
- private sendKeepAlive(id: bigint) {
1092
- const encoder = new BinaryEncoder();
1093
- encoder.writeLong(id);
1094
- this.sendPacket(0x1C, encoder.getBuffer());
1095
- }
1096
-
1097
- public sendPlayerPosRot(pos: BaseVec3, rot: Angle, onGround: boolean, pushingWall: boolean) {
1098
- let flag = 0;
1099
- if (onGround)
1100
- flag |= 1;
1101
- if (pushingWall)
1102
- flag |= 1 << 2;
1103
- // // console.log({ pos, rot, flag });
1104
- const encoder = new BinaryEncoder();
1105
- encoder.writeDouble(pos.x);
1106
- encoder.writeDouble(pos.y);
1107
- encoder.writeDouble(pos.z);
1108
- encoder.writeFloat(rot.yaw);
1109
- encoder.writeFloat(rot.pitch);
1110
- encoder.writeByte(flag);
1111
- this.sendPacket(0x1F, encoder.getBuffer());
1112
- }
1113
- public sendPlayerPos(pos: BaseVec3, onGround: boolean, pushingWall: boolean) {
1114
- let flag = 0;
1115
- if (onGround)
1116
- flag &= 1;
1117
- if (pushingWall)
1118
- flag |= 1 << 2;
1119
- // // console.log({ pos, flag });
1120
- const encoder = new BinaryEncoder();
1121
- encoder.writeDouble(pos.x);
1122
- encoder.writeDouble(pos.y);
1123
- encoder.writeDouble(pos.z);
1124
- encoder.writeByte(flag);
1125
- this.sendPacket(0x1E, encoder.getBuffer());
1126
- }
1127
- public sendPlayerRot(rot: Angle, onGround: boolean, pushingWall: boolean) {
1128
- let flag = 0;
1129
- if (onGround)
1130
- flag &= 1;
1131
- if (pushingWall)
1132
- flag |= 1 << 2;
1133
- // // console.log({ rot, flag });
1134
- const encoder = new BinaryEncoder();
1135
- encoder.writeFloat(rot.yaw);
1136
- encoder.writeFloat(rot.pitch);
1137
- encoder.writeByte(flag);
1138
- this.sendPacket(0x20, encoder.getBuffer());
1139
- }
1140
- public sendPlayerStatus(onGround: boolean, pushingWall: boolean) {
1141
- let flag = 0;
1142
- if (onGround)
1143
- flag &= 1;
1144
- if (pushingWall)
1145
- flag |= 1 << 2;
1146
- // // console.log({ flag });
1147
- const encoder = new BinaryEncoder();
1148
- encoder.writeByte(flag);
1149
- this.sendPacket(0x21, encoder.getBuffer());
1150
- }
1151
246
  }