@vaitosoi/minejs 0.2.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/README.md +1 -1
  2. package/assets/minecraft/26.2/packets.json +4758 -0
  3. package/dist/base/buffer.d.ts +2 -0
  4. package/dist/base/buffer.d.ts.map +1 -0
  5. package/dist/base/buffer.js +12 -0
  6. package/dist/base/buffer.js.map +1 -0
  7. package/dist/base/error.d.ts +59 -3
  8. package/dist/base/error.d.ts.map +1 -1
  9. package/dist/base/error.js +123 -7
  10. package/dist/base/error.js.map +1 -1
  11. package/dist/base/http.d.ts +2 -0
  12. package/dist/base/http.d.ts.map +1 -0
  13. package/dist/base/http.js +14 -0
  14. package/dist/base/http.js.map +1 -0
  15. package/dist/base/math.d.ts +22 -1
  16. package/dist/base/math.d.ts.map +1 -1
  17. package/dist/base/math.js +49 -2
  18. package/dist/base/math.js.map +1 -1
  19. package/dist/base/typing.d.ts +7 -1
  20. package/dist/base/typing.d.ts.map +1 -1
  21. package/dist/client/auth.d.ts +41 -7
  22. package/dist/client/auth.d.ts.map +1 -1
  23. package/dist/client/auth.js +96 -39
  24. package/dist/client/auth.js.map +1 -1
  25. package/dist/client/client.d.ts +73 -17
  26. package/dist/client/client.d.ts.map +1 -1
  27. package/dist/client/client.js +111 -44
  28. package/dist/client/client.js.map +1 -1
  29. package/dist/client/tcp.d.ts +17 -206
  30. package/dist/client/tcp.d.ts.map +1 -1
  31. package/dist/client/tcp.js +37 -715
  32. package/dist/client/tcp.js.map +1 -1
  33. package/dist/index.d.ts +12 -12
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +12 -12
  36. package/dist/index.js.map +1 -1
  37. package/dist/message/link.d.ts +10 -0
  38. package/dist/message/link.d.ts.map +1 -0
  39. package/dist/message/link.js +22 -0
  40. package/dist/message/link.js.map +1 -0
  41. package/dist/message/sigCache.d.ts +13 -0
  42. package/dist/message/sigCache.d.ts.map +1 -0
  43. package/dist/message/sigCache.js +26 -0
  44. package/dist/message/sigCache.js.map +1 -0
  45. package/dist/{translator → packet}/decoder.d.ts +14 -1
  46. package/dist/packet/decoder.d.ts.map +1 -0
  47. package/dist/{translator → packet}/decoder.js +24 -3
  48. package/dist/packet/decoder.js.map +1 -0
  49. package/dist/packet/dispatcher.d.ts +53 -0
  50. package/dist/packet/dispatcher.d.ts.map +1 -0
  51. package/dist/packet/dispatcher.js +738 -0
  52. package/dist/packet/dispatcher.js.map +1 -0
  53. package/dist/{translator → packet}/encoder.d.ts +4 -3
  54. package/dist/packet/encoder.d.ts.map +1 -0
  55. package/dist/{translator → packet}/encoder.js +18 -7
  56. package/dist/packet/encoder.js.map +1 -0
  57. package/dist/packet/static.d.ts.map +1 -0
  58. package/dist/packet/static.js.map +1 -0
  59. package/dist/{base → physics}/aabb.d.ts +2 -2
  60. package/dist/physics/aabb.d.ts.map +1 -0
  61. package/dist/{base → physics}/aabb.js +5 -5
  62. package/dist/physics/aabb.js.map +1 -0
  63. package/dist/physics/direction.d.ts.map +1 -0
  64. package/dist/physics/direction.js.map +1 -0
  65. package/dist/{base → physics}/player.d.ts +25 -28
  66. package/dist/physics/player.d.ts.map +1 -0
  67. package/dist/{base → physics}/player.js +81 -68
  68. package/dist/physics/player.js.map +1 -0
  69. package/dist/version/codec.d.ts +18 -0
  70. package/dist/version/codec.d.ts.map +1 -0
  71. package/dist/version/codec.js +235 -0
  72. package/dist/version/codec.js.map +1 -0
  73. package/dist/version/registry.d.ts +236 -0
  74. package/dist/version/registry.d.ts.map +1 -0
  75. package/dist/version/registry.js +284 -0
  76. package/dist/version/registry.js.map +1 -0
  77. package/dist/{base → world}/block.d.ts +5 -5
  78. package/dist/world/block.d.ts.map +1 -0
  79. package/dist/{base → world}/block.js +13 -13
  80. package/dist/world/block.js.map +1 -0
  81. package/dist/{base → world}/entity.d.ts +4 -4
  82. package/dist/world/entity.d.ts.map +1 -0
  83. package/dist/{base → world}/entity.js +6 -6
  84. package/dist/world/entity.js.map +1 -0
  85. package/dist/world/state.d.ts +175 -0
  86. package/dist/world/state.d.ts.map +1 -0
  87. package/dist/world/state.js +163 -0
  88. package/dist/world/state.js.map +1 -0
  89. package/dist/world/tick.d.ts.map +1 -0
  90. package/dist/world/tick.js.map +1 -0
  91. package/package.json +7 -2
  92. package/src/base/buffer.ts +12 -0
  93. package/src/base/error.ts +93 -4
  94. package/src/base/http.ts +10 -0
  95. package/src/base/math.ts +55 -3
  96. package/src/base/typing.ts +9 -1
  97. package/src/client/auth.ts +130 -52
  98. package/src/client/client.ts +182 -50
  99. package/src/client/tcp.ts +45 -967
  100. package/src/index.ts +12 -12
  101. package/src/message/link.ts +17 -0
  102. package/src/message/sigCache.ts +25 -0
  103. package/src/{translator → packet}/decoder.ts +24 -3
  104. package/src/packet/dispatcher.ts +919 -0
  105. package/src/{translator → packet}/encoder.ts +20 -9
  106. package/src/{base → physics}/aabb.ts +5 -5
  107. package/src/{base → physics}/player.ts +106 -65
  108. package/src/version/codec.ts +248 -0
  109. package/src/version/registry.ts +328 -0
  110. package/src/{base → world}/block.ts +12 -11
  111. package/src/{base → world}/entity.ts +5 -5
  112. package/src/world/state.ts +300 -0
  113. package/test/adapter/index.ts +14 -0
  114. package/test/client/index.ts +28 -21
  115. package/test/json/index.ts +3 -0
  116. package/dist/base/aabb.d.ts.map +0 -1
  117. package/dist/base/aabb.js.map +0 -1
  118. package/dist/base/block.d.ts.map +0 -1
  119. package/dist/base/block.js.map +0 -1
  120. package/dist/base/direction.d.ts.map +0 -1
  121. package/dist/base/direction.js.map +0 -1
  122. package/dist/base/entity.d.ts.map +0 -1
  123. package/dist/base/entity.js.map +0 -1
  124. package/dist/base/player.d.ts.map +0 -1
  125. package/dist/base/player.js.map +0 -1
  126. package/dist/base/registry.d.ts +0 -50
  127. package/dist/base/registry.d.ts.map +0 -1
  128. package/dist/base/registry.js +0 -89
  129. package/dist/base/registry.js.map +0 -1
  130. package/dist/base/tick.d.ts.map +0 -1
  131. package/dist/base/tick.js.map +0 -1
  132. package/dist/translator/decoder.d.ts.map +0 -1
  133. package/dist/translator/decoder.js.map +0 -1
  134. package/dist/translator/encoder.d.ts.map +0 -1
  135. package/dist/translator/encoder.js.map +0 -1
  136. package/dist/translator/static.d.ts.map +0 -1
  137. package/dist/translator/static.js.map +0 -1
  138. package/src/base/registry.ts +0 -87
  139. /package/assets/minecraft/{blocks.json → 26.2/blocks.json} +0 -0
  140. /package/assets/minecraft/{entities.json → 26.2/entities.json} +0 -0
  141. /package/dist/{translator → packet}/static.d.ts +0 -0
  142. /package/dist/{translator → packet}/static.js +0 -0
  143. /package/dist/{base → physics}/direction.d.ts +0 -0
  144. /package/dist/{base → physics}/direction.js +0 -0
  145. /package/dist/{base → world}/tick.d.ts +0 -0
  146. /package/dist/{base → world}/tick.js +0 -0
  147. /package/src/{translator → packet}/static.ts +0 -0
  148. /package/src/{base → physics}/direction.ts +0 -0
  149. /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, SharedState } from "../world/state";
10
+ import { EncodeResult } from "../version/codec";
11
+ import { TextComponent } from "../base/typing";
12
+ import { NotImplemented, SockerIsNotWritable, UnexpectedValue } 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
15
 
33
16
 
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
-
132
- /** Current dimension */
133
- dimension: string
134
- }
135
-
136
- export interface ServerRegistryEntry {
137
- id: string,
138
- data: object
139
- }
140
17
 
141
18
  // TCP related typing
142
19
  export interface TCPClientOption {
@@ -154,11 +31,6 @@ export interface TCPClientOption {
154
31
  protocolVersion: number,
155
32
  /** Player name */
156
33
  playerName: string,
157
- /**
158
- * Set to true only if you are playing in offline server or crack server
159
- */
160
- isOffline?: boolean,
161
-
162
34
  /**
163
35
  * Send empty `Known Packet` to let server send all Registry data, which may consume a lot of bandwith
164
36
  */
@@ -175,71 +47,21 @@ export interface TCPClientOption {
175
47
 
176
48
  export interface TCPClientEvents {
177
49
  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],
50
+ raw: [buffer: Buffer]
51
+ destroy: [],
216
52
  }
217
53
 
218
54
  export interface Message {
219
55
  sender: string,
220
- target?: string,
56
+ target: string | undefined,
221
57
  content: string,
222
58
  raw: {
223
59
  sender: TextComponent,
224
- target?: TextComponent,
225
- content?: TextComponent
60
+ target: TextComponent | undefined,
61
+ content: TextComponent | undefined
226
62
  }
227
63
  }
228
64
 
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
65
 
244
66
  // export enum TCPServerIntent {
245
67
  // Status = 1,
@@ -252,11 +74,9 @@ export enum ClientState {
252
74
  *
253
75
  * @see https://minecraft.wiki/w/Java_Edition_protocol/Packets?oldid=3445844
254
76
  */
255
- export class TCPClient<IsReady extends boolean = boolean> extends (EventEmitter as new () => TypedEmmiter<TCPClientEvents>) {
77
+ export class TCPClient extends (EventEmitter as new () => TypedEmmiter<TCPClientEvents>) {
256
78
  public readonly socket: Socket;
257
79
 
258
- public server: Server | undefined = undefined;
259
-
260
80
  // Internal var
261
81
  /**
262
82
  * | Value | Meaning |
@@ -265,56 +85,26 @@ export class TCPClient<IsReady extends boolean = boolean> extends (EventEmitter
265
85
  * | -1 | dont compress |
266
86
  * | > 0 | compression threshold |
267
87
  */
268
- private compressionThreshold: number = 0;
269
88
  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
89
 
286
90
  constructor(
91
+ private state: SharedState,
287
92
  public readonly option: TCPClientOption,
288
- socketOption?: SocketConstructorOpts
93
+ socketOption?: SocketConstructorOpts,
289
94
  ) {
290
95
  super();
291
96
  this.socket = new Socket(socketOption);
292
- this.wipePlayData();
293
-
294
- if (!option.isOffline && !option.auth)
295
- throw new MissingAuthOption();
296
97
  }
297
98
 
298
- private wipePlayData() {
299
- this.world = null as any;
300
- this.player = null as any;
301
- this.registry = null as any;
302
- }
99
+ public sendInitPacket: () => void = () => { throw new NotImplemented(); };
100
+ public forwardPacket: (packetId: number, decoder: BinaryDecoder) => void = () => { throw new NotImplemented(); };
101
+ public parsePacket: (packetId: string | number, data: object) => EncodeResult = () => { throw new NotImplemented(); };
303
102
 
304
103
  /**
305
104
  * Connect to server
306
105
  */
307
- 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;
106
+ public connect() {
107
+ this.state.status = ClientStatus.Connecting;
318
108
  const connection = this.socket.connect({
319
109
  host: this.option.host,
320
110
  port: this.option.port
@@ -322,30 +112,21 @@ export class TCPClient<IsReady extends boolean = boolean> extends (EventEmitter
322
112
 
323
113
  connection.on("connect", () => {
324
114
  this.emit("connect");
325
- this.wipePlayData();
326
- this.sendHandshake();
327
- this.sendLoginStart();
115
+ this.sendInitPacket();
328
116
  });
329
117
  connection.on("data", (data) => {
330
118
  let buf = Buffer.from(data);
331
- if (this.decipher) {
332
- buf = this.decipher.update(buf);
333
- }
119
+ if (this.state.decipher)
120
+ buf = this.state.decipher.update(buf);
334
121
  this.emit("raw", Buffer.from(buf));
335
122
  this.bufferPool = Buffer.concat([this.bufferPool, buf]);
336
123
  this.handlePacket();
337
124
  });
338
125
  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");
126
+ this.emit("destroy");
343
127
  });
344
128
  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");
129
+ this.emit("destroy");
349
130
  });
350
131
  }
351
132
 
@@ -354,24 +135,12 @@ export class TCPClient<IsReady extends boolean = boolean> extends (EventEmitter
354
135
  this.socket.destroy();
355
136
  }
356
137
 
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
138
  /*
368
139
  * Read packet
369
140
  */
370
141
 
371
142
  private handlePacket() {
372
- while (true) {
373
- if (this.bufferPool.length === 0) break;
374
-
143
+ while (this.bufferPool.length > 0) {
375
144
  let decoder = new BinaryDecoder(this.bufferPool);
376
145
  let packetLength: number;
377
146
  try {
@@ -384,9 +153,9 @@ export class TCPClient<IsReady extends boolean = boolean> extends (EventEmitter
384
153
  const expectedPacketEnd = decoder.offset + packetLength;
385
154
 
386
155
  let packetID: number;
387
- if (this.compressionThreshold === 0)
156
+ if (this.state.compressionThreshold === 0)
388
157
  packetID = decoder.readVarInt();
389
- else if (this.compressionThreshold === -1) {
158
+ else if (this.state.compressionThreshold === -1) {
390
159
  decoder.readVarInt();
391
160
  packetID = decoder.readVarInt();
392
161
  } else {
@@ -396,604 +165,44 @@ export class TCPClient<IsReady extends boolean = boolean> extends (EventEmitter
396
165
  } else {
397
166
  const dataBuffer = this.bufferPool.subarray(decoder.offset, expectedPacketEnd);
398
167
  const decompressed = inflateSync(dataBuffer);
168
+ if (decompressed.length !== dataLength)
169
+ throw new UnexpectedValue("decompressed packet data", decompressed.length.toString(), dataLength.toString());
399
170
  decoder = new BinaryDecoder(decompressed);
400
171
  packetID = decoder.readVarInt();
401
172
  }
402
173
  }
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
- }
174
+ this.forwardPacket(packetID, decoder);
486
175
 
487
176
  this.bufferPool = this.bufferPool.subarray(expectedPacketEnd);
488
177
  }
489
178
  }
490
179
 
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
180
  /*
972
- * Send packet
973
- */
974
-
181
+ * Send packet
182
+ */
975
183
  public write(buf: Buffer) {
976
- if (this.status == ClientStatus.Disconnected || !this.socket.writable)
184
+ if (!this.socket.writable)
977
185
  throw new SockerIsNotWritable();
978
186
 
979
187
  let sendBuffer = buf;
980
- if (this.cipher)
981
- sendBuffer = this.cipher.update(sendBuffer);
188
+ if (this.state.cipher)
189
+ sendBuffer = this.state.cipher.update(sendBuffer);
982
190
 
983
191
  this.socket.write(sendBuffer);
984
192
  }
985
193
 
986
- public sendPacket(packetId: number, content: Buffer) {
194
+ public sendPacket(packetId: number | string, data: Record<string, any>) {
195
+ const { buffer: content, packet } = this.parsePacket(packetId, data);
987
196
  const encodePacketId = new BinaryEncoder();
988
- encodePacketId.writeVarInt(packetId);
197
+ encodePacketId.writeVarInt(packet.id);
989
198
  const sendData = Buffer.concat([encodePacketId.getBuffer(), content]);
990
199
 
991
- let packet: Buffer;
992
- if (this.compressionThreshold !== 0) {
200
+ let sendingPacket: Buffer;
201
+ if (this.state.compressionThreshold !== 0) {
993
202
  let data: Buffer;
994
203
  let uncompressedLength: number;
995
204
 
996
- if (this.compressionThreshold > 0 && sendData.length > this.compressionThreshold) {
205
+ if (this.state.compressionThreshold > 0 && sendData.length > this.state.compressionThreshold) {
997
206
  uncompressedLength = sendData.length;
998
207
  data = deflateSync(sendData);
999
208
  } else {
@@ -1007,145 +216,14 @@ export class TCPClient<IsReady extends boolean = boolean> extends (EventEmitter
1007
216
 
1008
217
  const packetLengthEncoder = new BinaryEncoder();
1009
218
  packetLengthEncoder.writeVarInt(dataLengthBuf.length + data.length);
1010
- packet = Buffer.concat([packetLengthEncoder.getBuffer(), dataLengthBuf, data]);
219
+ sendingPacket = Buffer.concat([packetLengthEncoder.getBuffer(), dataLengthBuf, data]);
1011
220
  } else {
1012
221
  const packetLengthEncoder = new BinaryEncoder();
1013
222
  packetLengthEncoder.writeVarInt(sendData.length);
1014
- packet = Buffer.concat([packetLengthEncoder.getBuffer(), sendData]);
223
+ sendingPacket = Buffer.concat([packetLengthEncoder.getBuffer(), sendData]);
1015
224
  }
1016
225
 
1017
- this.write(packet);
226
+ this.write(sendingPacket);
1018
227
  }
1019
228
 
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
229
  }