@vaitosoi/minejs 0.4.3 → 0.5.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 (133) hide show
  1. package/README.md +12 -4
  2. package/assets/minecraft/26.2/effects.json +42 -0
  3. package/assets/minecraft/26.2/packets.json +1 -1
  4. package/dist/base/bitset.d.ts +43 -4
  5. package/dist/base/bitset.d.ts.map +1 -1
  6. package/dist/base/bitset.js +251 -30
  7. package/dist/base/bitset.js.map +1 -1
  8. package/dist/base/buffer.d.ts +1 -0
  9. package/dist/base/buffer.d.ts.map +1 -1
  10. package/dist/base/buffer.js +1 -0
  11. package/dist/base/buffer.js.map +1 -1
  12. package/dist/base/cache.d.ts +24 -0
  13. package/dist/base/cache.d.ts.map +1 -0
  14. package/dist/base/cache.js +58 -0
  15. package/dist/base/cache.js.map +1 -0
  16. package/dist/base/error.d.ts +7 -0
  17. package/dist/base/error.d.ts.map +1 -1
  18. package/dist/base/error.js +12 -1
  19. package/dist/base/error.js.map +1 -1
  20. package/dist/base/http.d.ts +1 -0
  21. package/dist/base/http.d.ts.map +1 -1
  22. package/dist/base/http.js +1 -0
  23. package/dist/base/http.js.map +1 -1
  24. package/dist/base/math.d.ts +14 -0
  25. package/dist/base/math.d.ts.map +1 -1
  26. package/dist/base/math.js +41 -0
  27. package/dist/base/math.js.map +1 -1
  28. package/dist/base/typing.d.ts +12 -0
  29. package/dist/base/typing.d.ts.map +1 -1
  30. package/dist/{packet → binary}/decoder.d.ts +4 -0
  31. package/dist/binary/decoder.d.ts.map +1 -0
  32. package/dist/{packet → binary}/decoder.js +4 -0
  33. package/dist/binary/decoder.js.map +1 -0
  34. package/dist/{packet → binary}/encoder.d.ts +6 -2
  35. package/dist/binary/encoder.d.ts.map +1 -0
  36. package/dist/{packet → binary}/encoder.js +10 -2
  37. package/dist/binary/encoder.js.map +1 -0
  38. package/dist/{packet → binary}/static.d.ts.map +1 -1
  39. package/dist/{packet → binary}/static.js.map +1 -1
  40. package/dist/client/client.d.ts +23 -2
  41. package/dist/client/client.d.ts.map +1 -1
  42. package/dist/client/client.js +32 -15
  43. package/dist/client/client.js.map +1 -1
  44. package/dist/index.d.ts +12 -4
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +12 -4
  47. package/dist/index.js.map +1 -1
  48. package/dist/message/link.d.ts +3 -0
  49. package/dist/message/link.d.ts.map +1 -1
  50. package/dist/message/link.js +3 -0
  51. package/dist/message/link.js.map +1 -1
  52. package/dist/message/sigCache.d.ts +5 -0
  53. package/dist/message/sigCache.d.ts.map +1 -1
  54. package/dist/message/sigCache.js +5 -0
  55. package/dist/message/sigCache.js.map +1 -1
  56. package/dist/{client → net}/tcp.d.ts +3 -3
  57. package/dist/net/tcp.d.ts.map +1 -0
  58. package/dist/{client → net}/tcp.js +3 -3
  59. package/dist/net/tcp.js.map +1 -0
  60. package/dist/packet/{dispatcher.d.ts → listener.d.ts} +10 -18
  61. package/dist/packet/listener.d.ts.map +1 -0
  62. package/dist/packet/{dispatcher.js → listener.js} +74 -137
  63. package/dist/packet/listener.js.map +1 -0
  64. package/dist/packet/sender.d.ts +28 -0
  65. package/dist/packet/sender.d.ts.map +1 -0
  66. package/dist/packet/sender.js +147 -0
  67. package/dist/packet/sender.js.map +1 -0
  68. package/dist/physics/aabb.d.ts +3 -0
  69. package/dist/physics/aabb.d.ts.map +1 -1
  70. package/dist/physics/aabb.js +12 -8
  71. package/dist/physics/aabb.js.map +1 -1
  72. package/dist/physics/direction.d.ts +3 -0
  73. package/dist/physics/direction.d.ts.map +1 -1
  74. package/dist/physics/direction.js +3 -0
  75. package/dist/physics/direction.js.map +1 -1
  76. package/dist/physics/player.d.ts +4 -0
  77. package/dist/physics/player.d.ts.map +1 -1
  78. package/dist/physics/player.js +24 -3
  79. package/dist/physics/player.js.map +1 -1
  80. package/dist/version/codec.d.ts +5 -1
  81. package/dist/version/codec.d.ts.map +1 -1
  82. package/dist/version/codec.js +25 -5
  83. package/dist/version/codec.js.map +1 -1
  84. package/dist/version/registry.d.ts +25 -2
  85. package/dist/version/registry.d.ts.map +1 -1
  86. package/dist/version/registry.js +43 -6
  87. package/dist/version/registry.js.map +1 -1
  88. package/dist/world/block.d.ts +5 -0
  89. package/dist/world/block.d.ts.map +1 -1
  90. package/dist/world/block.js +56 -0
  91. package/dist/world/block.js.map +1 -1
  92. package/dist/world/state.d.ts +22 -0
  93. package/dist/world/state.d.ts.map +1 -1
  94. package/dist/world/state.js +19 -0
  95. package/dist/world/state.js.map +1 -1
  96. package/package.json +8 -10
  97. package/src/base/bitset.ts +311 -31
  98. package/src/base/buffer.ts +1 -0
  99. package/src/base/cache.ts +62 -0
  100. package/src/base/error.ts +9 -0
  101. package/src/base/http.ts +1 -0
  102. package/src/base/math.ts +45 -1
  103. package/src/base/typing.ts +11 -0
  104. package/src/{packet → binary}/decoder.ts +4 -0
  105. package/src/{packet → binary}/encoder.ts +10 -2
  106. package/src/client/client.ts +54 -19
  107. package/src/index.ts +12 -4
  108. package/src/message/link.ts +3 -0
  109. package/src/message/sigCache.ts +5 -0
  110. package/src/{client → net}/tcp.ts +4 -8
  111. package/src/packet/{dispatcher.ts → listener.ts} +93 -175
  112. package/src/packet/sender.ts +179 -0
  113. package/src/physics/aabb.ts +12 -8
  114. package/src/physics/direction.ts +3 -0
  115. package/src/physics/player.ts +22 -3
  116. package/src/version/codec.ts +27 -6
  117. package/src/version/registry.ts +59 -3
  118. package/src/world/block.ts +72 -2
  119. package/src/world/state.ts +42 -2
  120. package/test/bitset/index.ts +3 -8
  121. package/test/client/index.ts +12 -2
  122. package/test/state/index.ts +7 -0
  123. package/dist/client/tcp.d.ts.map +0 -1
  124. package/dist/client/tcp.js.map +0 -1
  125. package/dist/packet/decoder.d.ts.map +0 -1
  126. package/dist/packet/decoder.js.map +0 -1
  127. package/dist/packet/dispatcher.d.ts.map +0 -1
  128. package/dist/packet/dispatcher.js.map +0 -1
  129. package/dist/packet/encoder.d.ts.map +0 -1
  130. package/dist/packet/encoder.js.map +0 -1
  131. /package/dist/{packet → binary}/static.d.ts +0 -0
  132. /package/dist/{packet → binary}/static.js +0 -0
  133. /package/src/{packet → binary}/static.ts +0 -0
@@ -1,61 +1,70 @@
1
1
  import zod from "zod";
2
- import { createCipheriv, createDecipheriv, createPublicKey, publicEncrypt, randomBytes, constants as crypto_constants, createVerify } from "node:crypto";
3
- import { BlockEntity, ChunkSection, ClientPlayer, ClientStatus, ConnectionState, Entity, GameMode, PaletteContainer, ServerKnownPack, ServerWorld, SharedState } from "../world/state";
4
- import { BinaryDecoder, getTextFromTextComponent } from "./decoder";
2
+ import { createCipheriv, createDecipheriv, randomBytes, createVerify } from "node:crypto";
3
+ import { BlockEntity, ChunkSection, ClientPlayer, ClientStatus, Entity, GameMode, ServerKnownPack, ServerWorld, SharedState } from "../world/state";
4
+ import { BinaryDecoder, getTextFromTextComponent } from "../binary/decoder";
5
5
  import { packBlockPos, SectionsPerChunk } from "../client/static";
6
- import { Angle, BaseVec3, Vec3 } from "../physics/direction";
7
- import { ProtocolVersionMapping } from "../version/registry";
6
+ import { Vec3 } from "../physics/direction";
8
7
  import { TypedEmmiter } from "../base/event";
9
8
  import { ClientEvents } from "../client/client";
10
- import { makeMovementFlag } from "./encoder";
9
+ import { makeMovementFlag } from "../binary/encoder";
11
10
  import { TextComponent } from "../base/typing";
12
- import { AuthRelatedNotFound, HaveSignatureButNotIndex, MessageLinkNotFound, MissingAuthOption, NotImplemented, UnexpectedValue } from "../base/error";
13
- import { randomUUIDBytes, uuidToBuffer } from "../base/math";
11
+ import { AuthRelatedNotFound, HaveSignatureButNotIndex, MessageLinkNotFound, NotImplemented, UnexpectedValue } from "../base/error";
12
+ import { uuidToBuffer } from "../base/math";
14
13
  import { MessageLink } from "../message/link";
15
- import { sliceBuffer } from "../base/buffer";
14
+ import { Sender } from "./sender";
16
15
 
17
16
  function zodParse<Type extends zod.ZodType>(data: object, zod: Type): zod.infer<Type> {
18
17
  return zod.parse(data);
19
18
  }
20
19
 
21
- export class Dispatcher {
20
+ /**
21
+ * Packet listener
22
+ */
23
+ export class Listener {
22
24
  private readonly mapping: Record<string, (data: object) => void>;
23
25
 
24
26
  constructor(
25
27
  private state: SharedState,
26
- private emit: TypedEmmiter<ClientEvents>["emit"]
28
+ private emit: TypedEmmiter<ClientEvents>["emit"],
29
+ private sender: Sender,
27
30
  ) {
28
31
  this.mapping = {
29
32
  "login:login_disconnect": this.handleLoginDisconnect,
30
33
  "login:hello": this.handleEncryption,
31
34
  "login:login_finished": this.handleLoginSucess,
32
35
  "login:login_compression": this.handleSetCompression,
36
+
33
37
  "configuration:disconnect": this.handleConfiguarionPlayDisconnect,
34
38
  "configuration:keep_alive": this.handleKeepAlive,
35
39
  "configuration:registry_data": this.handleRegistryData,
36
40
  "configuration:select_known_packs": this.handleKnownPack,
37
41
  "configuration:finish_configuration": this.handleFinishConfiguration,
38
- "play:add_entity": this.handleSpawnEntity,
42
+
43
+ "play:login": this.handlePlayLogin,
39
44
  "play:disconnect": this.handleConfiguarionPlayDisconnect,
40
- "play:disguised_chat": this.handleDisguisedChatMessage,
41
- "play:entity_position_sync": this.handleTeleportEntity,
42
- "play:forget_level_chunk": this.handleUnloadChunk,
43
45
  "play:keep_alive": this.handleKeepAlive,
46
+
47
+ "play:player_chat": this.handlePlayerChat,
48
+ "play:disguised_chat": this.handleDisguisedChatMessage,
49
+ "play:system_chat": this.handleSystemMessage,
50
+ "play:set_action_bar_text": this.handleSetActionBar,
51
+
44
52
  "play:level_chunk_with_light": this.handleChunkData,
45
- "play:login": this.handlePlayLogin,
53
+ "play:forget_level_chunk": this.handleUnloadChunk,
54
+
55
+ "play:add_entity": this.handleSpawnEntity,
46
56
  "play:move_entity_pos": this.handleUpdateEntityPosition,
47
57
  "play:move_entity_pos_rot": this.handleUpdateEntityPositionRotation,
48
- "play:player_chat": this.handlePlayerChat,
58
+ "play:entity_position_sync": this.handleTeleportEntity,
49
59
  "play:player_position": this.handleSynchronizePlayerPosition,
60
+ "play:update_mob_effect": this.handleUpdateMobEffect,
50
61
  "play:remove_entities": this.handleRemoveEntity,
51
- // "play:rotate_head":
52
- "play:set_action_bar_text": this.handleSetActionBar,
62
+ "play:remove_mob_effect": this.handleRemoveMobEffect,
63
+ // "play:rotate_head": ,
53
64
  "play:set_entity_motion": this.handleSetEntityVelocity,
54
- "play:system_chat": this.handleSystemMessage,
55
65
  };
56
66
  }
57
67
 
58
- public sendPacket: (packetId: string, data: object) => void = () => { throw new NotImplemented(); };
59
68
  public disconnect: (reason: string, reasonRaw?: TextComponent) => void = () => { throw new NotImplemented(); };
60
69
 
61
70
 
@@ -99,9 +108,9 @@ export class Dispatcher {
99
108
  throw new AuthRelatedNotFound("auth client");
100
109
  else
101
110
  this.state.authClient.sendAuth(server_id, sharedSecret, publicKey)
102
- .then(() => this.sendEncryptionResponse(publicKey, verifyToken));
111
+ .then(() => this.sender.sendEncryptionResponse(publicKey, verifyToken));
103
112
  else
104
- this.sendEncryptionResponse(publicKey, verifyToken);
113
+ this.sender.sendEncryptionResponse(publicKey, verifyToken);
105
114
  }
106
115
 
107
116
  private handleSetCompression(data: object) {
@@ -136,9 +145,10 @@ export class Dispatcher {
136
145
  angle: {
137
146
  yaw: 0,
138
147
  pitch: 0,
139
- }
148
+ },
149
+ effects: {}
140
150
  } satisfies ClientPlayer as any;
141
- this.sendLoginAck();
151
+ this.sender.sendLoginAck();
142
152
  }
143
153
 
144
154
  // Configure
@@ -152,8 +162,8 @@ export class Dispatcher {
152
162
  }))
153
163
  }));
154
164
  this.state.server!.knownPacks = known_packs satisfies ServerKnownPack[] as any;
155
- this.sendKnownPack(this.state.clientOptions.loadRegistry === true ? [] : known_packs);
156
- // this.sendKnownPack([]);
165
+ this.sender.sendKnownPack(this.state.clientOptions.loadRegistry === true ? [] : known_packs);
166
+ // this.sender.sendKnownPack([]);
157
167
  }
158
168
 
159
169
  private handleRegistryData(data: object) {
@@ -171,10 +181,11 @@ export class Dispatcher {
171
181
  const registry = this.state.registry as Record<string, any[]>;
172
182
  if (!(registry_id in registry)) registry[registry_id] = [];
173
183
  registry[registry_id]!.push(...entries);
184
+ this.emit("registryData", { registry_id, entries });
174
185
  }
175
186
 
176
187
  private handleFinishConfiguration(data: object) {
177
- this.sendConfigureAck();
188
+ this.sender.sendConfigureAck();
178
189
  }
179
190
 
180
191
  private handleConfiguarionPlayDisconnect(data: object) {
@@ -225,7 +236,7 @@ export class Dispatcher {
225
236
  this.state.status = ClientStatus.Ready;
226
237
 
227
238
  if (this.state.useEncryption)
228
- this.sendPlayerSession();
239
+ this.sender.sendPlayerSession();
229
240
 
230
241
  this.emit("ready");
231
242
  }
@@ -291,8 +302,8 @@ export class Dispatcher {
291
302
  } satisfies ClientPlayer as any
292
303
  );
293
304
  this.state.enqueueEvent("playerPosition", { x: newPosX, y: newPosY, z: newPosZ });
294
- this.sendConfirmTeleportation(teleport_id);
295
- this.sendPacket("move_player_pos_rot", {
305
+ this.sender.sendConfirmTeleportation(teleport_id);
306
+ this.sender.sendPacket("move_player_pos_rot", {
296
307
  x: newPosition.x,
297
308
  feet_y: newPosition.y,
298
309
  z: newPosition.z,
@@ -308,7 +319,7 @@ export class Dispatcher {
308
319
  keep_alive_id: zod.bigint().or(zod.number())
309
320
  })
310
321
  );
311
- this.sendKeepAlive(BigInt(keep_alive_id));
322
+ this.sender.sendKeepAlive(BigInt(keep_alive_id));
312
323
  }
313
324
 
314
325
  private handleChangeGameMode(data: object) {
@@ -602,6 +613,53 @@ export class Dispatcher {
602
613
  });
603
614
  }
604
615
 
616
+ private handleUpdateMobEffect(data: object) {
617
+ const {
618
+ entity_id,
619
+ effect_id,
620
+ amplifier,
621
+ duration,
622
+ flags
623
+ } = zodParse(data, zod.object({
624
+ entity_id: zod.number(),
625
+ effect_id: zod.number(),
626
+ amplifier: zod.number(),
627
+ duration: zod.number(),
628
+ flags: zod.number(),
629
+ }));
630
+ const isAmbient = (flags & 0x01) == 1,
631
+ showParticles = (flags & 0x02) == 1,
632
+ showIcon = (flags & 0x04) == 1,
633
+ blend = (flags & 0x08) == 1;
634
+ this.state.enqueueMutation((state) => {
635
+ if (state.player!.entityId === entity_id)
636
+ state.player!.effects[effect_id] = {
637
+ amplifier,
638
+ duration,
639
+ id: effect_id,
640
+ flag: {
641
+ blend,
642
+ isAmbient,
643
+ showIcon,
644
+ showParticles
645
+ },
646
+ date: Date.now()
647
+ };
648
+ });
649
+ }
650
+
651
+ private handleRemoveMobEffect(data: object) {
652
+ const { entity_id, effect_id } = zodParse(data, zod.object({
653
+ entity_id: zod.number(),
654
+ effect_id: zod.number(),
655
+ }));
656
+
657
+ this.state.enqueueMutation((state) => {
658
+ if (state.player!.entityId === entity_id)
659
+ delete state.player!.effects[effect_id];
660
+ });
661
+ }
662
+
605
663
  // Chat
606
664
  private handlePlayerChat(data: object) {
607
665
  const {
@@ -677,6 +735,8 @@ export class Dispatcher {
677
735
  }
678
736
  }
679
737
 
738
+ if (message_signature_bytes !== null)
739
+ this.state.messageCount += 1;
680
740
  if (this.state.clientOptions.shouldVerifyMessageSignature === true && message_signature_bytes) {
681
741
  if (!this.state.sessionID)
682
742
  throw new AuthRelatedNotFound("session uuid");
@@ -716,7 +776,7 @@ export class Dispatcher {
716
776
  const signature = Buffer.from(message_signature_bytes);
717
777
 
718
778
  if (!verify.verify(publicKey!, signature))
719
- this.emit("failedMessage", emitObject);
779
+ return this.emit("failedMessage", emitObject);
720
780
  }
721
781
 
722
782
  this.emit("message", emitObject);
@@ -774,146 +834,4 @@ export class Dispatcher {
774
834
  }
775
835
  });
776
836
  }
777
-
778
- /*
779
- * Send packet
780
- */
781
-
782
- // Login
783
-
784
- public sendHandshake() {
785
- this.state.state = ConnectionState.Handshake;
786
- this.sendPacket("intention",
787
- {
788
- protocol_version: ProtocolVersionMapping[this.state.clientOptions.version]!,
789
- server_address: this.state.clientOptions.host,
790
- server_port: this.state.clientOptions.port,
791
- intent: 2
792
- }
793
- );
794
- }
795
-
796
- public sendLoginStart() {
797
- this.state.state = ConnectionState.Login;
798
- this.state.status = ClientStatus.Logining;
799
- this.sendPacket("hello", {
800
- name: this.state.clientOptions.playerName,
801
- player_uuid: Buffer.from(this.state.playerUUID!, "hex")
802
- });
803
- }
804
-
805
- private sendEncryptionResponse(publicKey: Buffer, verifyToken: Buffer) {
806
- const encryptedSecret = publicEncrypt({
807
- key: createPublicKey({ key: publicKey, format: 'der', type: 'spki' }),
808
- padding: crypto_constants.RSA_PKCS1_PADDING
809
- }, this.state.sharedSecret!);
810
- const encryptedVerifyToken = publicEncrypt({
811
- key: createPublicKey({ key: publicKey, format: 'der', type: 'spki' }),
812
- padding: crypto_constants.RSA_PKCS1_PADDING
813
- }, verifyToken);
814
- const secretBuf = sliceBuffer(encryptedSecret, 1, (buf) => buf.readInt8());
815
- const token = sliceBuffer(encryptedVerifyToken, 1, (buf) => buf.readInt8());
816
- this.sendPacket("key", {
817
- shared_secret: { value: secretBuf, length: secretBuf.length },
818
- verify_token: { value: token, length: token.length }
819
- });
820
- }
821
-
822
- private sendLoginAck() {
823
- this.sendPacket("login_acknowledged", {});
824
- this.state.state = ConnectionState.Configure;
825
- this.state.server = {};
826
- }
827
-
828
- // Configuring
829
-
830
- private sendKnownPack(knownPacks: ServerKnownPack[]) {
831
- this.sendPacket("select_known_packs", {
832
- known_packs: {
833
- value: knownPacks,
834
- length: knownPacks.length
835
- }
836
- });
837
- }
838
-
839
- private sendConfigureAck() {
840
- this.sendPacket("finish_configuration", {});
841
- this.state.state = ConnectionState.Play;
842
- }
843
-
844
- // Play
845
-
846
- private sendPlayerSession() {
847
- const sessionUUID = randomUUIDBytes();
848
- const expireTime = 15 * 60 * 1000; // 15min in ms
849
- const expiredAt = Date.now() + expireTime;
850
- const { publicKey, signature } = this.state.getSignature();
851
- this.state.sessionID = sessionUUID;
852
- this.sendPacket("chat_session_update", {
853
- session_id: sessionUUID,
854
- expire_at: expiredAt,
855
- public_key: publicKey,
856
- signature
857
- });
858
- }
859
-
860
- private sendConfirmTeleportation(teleportId: number) {
861
- this.sendPacket("accept_teleportation", {
862
- teleport_id: teleportId
863
- });
864
- }
865
-
866
- private sendKeepAlive(id: bigint) {
867
- this.sendPacket("keep_alive", {
868
- keep_alive_id: id
869
- });
870
- }
871
-
872
- public sendPlayerPos(
873
- position: BaseVec3,
874
- onGround: boolean,
875
- horizontalCollision: boolean
876
- ) {
877
- const { x, y, z } = position;
878
- this.state.enqueuePacket("move_player_pos", {
879
- x, feet_y: y, z,
880
- flags: makeMovementFlag(onGround, horizontalCollision)
881
- });
882
- }
883
-
884
- public sendPlayerPosRot(
885
- position: BaseVec3,
886
- angle: Angle,
887
- onGround: boolean,
888
- horizontalCollision: boolean
889
- ) {
890
- const { x, y, z } = position,
891
- { yaw, pitch } = angle;
892
- this.state.enqueuePacket("move_player_pos_rot", {
893
- x, feet_y: y, z,
894
- yaw, pitch,
895
- flags: makeMovementFlag(onGround, horizontalCollision)
896
- });
897
- }
898
-
899
- public sendPlayerRot(
900
- angle: Angle,
901
- onGround: boolean,
902
- horizontalCollision: boolean
903
- ) {
904
- const { yaw, pitch } = angle;
905
- this.state.enqueuePacket("move_player_rot", {
906
- yaw, pitch,
907
- flags: makeMovementFlag(onGround, horizontalCollision)
908
- });
909
- }
910
-
911
- public sendPlayerStatus(
912
- onGround: boolean,
913
- horizontalCollision: boolean
914
- ) {
915
- this.state.enqueuePacket("move_player_status_only", {
916
- flags: makeMovementFlag(onGround, horizontalCollision)
917
- });
918
- }
919
837
  }
@@ -0,0 +1,179 @@
1
+ import { createPublicKey, publicEncrypt, constants as crypto_constants, randomBytes } from "node:crypto";
2
+ import { TypedEmmiter } from "../base/event";
3
+ import { ClientEvents } from "../client/client";
4
+ import { ProtocolVersionMapping } from "../version/registry";
5
+ import { ClientStatus, ConnectionState, ServerKnownPack, SharedState } from "../world/state";
6
+ import { sliceBuffer } from "../base/buffer";
7
+ import { randomUUIDBytes } from "../base/math";
8
+ import { Angle, BaseVec3 } from "../physics/direction";
9
+ import { MessageTooLong, NotImplemented } from "../base/error";
10
+ import BitSet from "../base/bitset";
11
+ import { makeMovementFlag } from "../binary/encoder";
12
+
13
+ /**
14
+ * Packet sender
15
+ */
16
+ export class Sender {
17
+ constructor(
18
+ private state: SharedState,
19
+ private emit: TypedEmmiter<ClientEvents>["emit"]
20
+ ) { }
21
+
22
+ public sendPacket: (packetId: string, data: object) => void = () => { throw new NotImplemented(); };
23
+
24
+ public sendHandshake() {
25
+ this.state.state = ConnectionState.Handshake;
26
+ this.sendPacket("intention",
27
+ {
28
+ protocol_version: ProtocolVersionMapping[this.state.clientOptions.version]!,
29
+ server_address: this.state.clientOptions.host,
30
+ server_port: this.state.clientOptions.port,
31
+ intent: 2
32
+ }
33
+ );
34
+ }
35
+
36
+ public sendLoginStart() {
37
+ this.state.state = ConnectionState.Login;
38
+ this.state.status = ClientStatus.Logining;
39
+ this.sendPacket("hello", {
40
+ name: this.state.clientOptions.playerName,
41
+ player_uuid: Buffer.from(this.state.playerUUID!, "hex")
42
+ });
43
+ }
44
+
45
+ public sendEncryptionResponse(publicKey: Buffer, verifyToken: Buffer) {
46
+ const encryptedSecret = publicEncrypt({
47
+ key: createPublicKey({ key: publicKey, format: 'der', type: 'spki' }),
48
+ padding: crypto_constants.RSA_PKCS1_PADDING
49
+ }, this.state.sharedSecret!);
50
+ const encryptedVerifyToken = publicEncrypt({
51
+ key: createPublicKey({ key: publicKey, format: 'der', type: 'spki' }),
52
+ padding: crypto_constants.RSA_PKCS1_PADDING
53
+ }, verifyToken);
54
+ const secretBuf = sliceBuffer(encryptedSecret, 1, (buf) => buf.readInt8());
55
+ const token = sliceBuffer(encryptedVerifyToken, 1, (buf) => buf.readInt8());
56
+ this.sendPacket("key", {
57
+ shared_secret: { value: secretBuf, length: secretBuf.length },
58
+ verify_token: { value: token, length: token.length }
59
+ });
60
+ }
61
+
62
+ public sendLoginAck() {
63
+ this.sendPacket("login_acknowledged", {});
64
+ this.state.state = ConnectionState.Configure;
65
+ this.state.server = {};
66
+ }
67
+
68
+ // Configuring
69
+
70
+ public sendKnownPack(knownPacks: ServerKnownPack[]) {
71
+ this.sendPacket("select_known_packs", {
72
+ known_packs: {
73
+ value: knownPacks,
74
+ length: knownPacks.length
75
+ }
76
+ });
77
+ }
78
+
79
+ public sendConfigureAck() {
80
+ this.sendPacket("finish_configuration", {});
81
+ this.state.state = ConnectionState.Play;
82
+ }
83
+
84
+ // Play
85
+
86
+ public sendPlayerSession() {
87
+ const sessionUUID = randomUUIDBytes();
88
+ const expireTime = 15 * 60 * 1000; // 15min in ms
89
+ const expiredAt = Date.now() + expireTime;
90
+ const { publicKey, signature } = this.state.getSignature();
91
+ this.state.sessionID = sessionUUID;
92
+ this.sendPacket("chat_session_update", {
93
+ session_id: sessionUUID,
94
+ expire_at: expiredAt,
95
+ public_key: publicKey,
96
+ signature
97
+ });
98
+ }
99
+
100
+ public sendConfirmTeleportation(teleportId: number) {
101
+ this.sendPacket("accept_teleportation", {
102
+ teleport_id: teleportId
103
+ });
104
+ }
105
+
106
+ public sendKeepAlive(id: bigint) {
107
+ this.sendPacket("keep_alive", {
108
+ keep_alive_id: id
109
+ });
110
+ }
111
+
112
+ public sendPlayerPos(
113
+ position: BaseVec3,
114
+ onGround: boolean,
115
+ horizontalCollision: boolean
116
+ ) {
117
+ const { x, y, z } = position;
118
+ this.state.enqueuePacket("move_player_pos", {
119
+ x, feet_y: y, z,
120
+ flags: makeMovementFlag(onGround, horizontalCollision)
121
+ });
122
+ }
123
+
124
+ public sendPlayerPosRot(
125
+ position: BaseVec3,
126
+ angle: Angle,
127
+ onGround: boolean,
128
+ horizontalCollision: boolean
129
+ ) {
130
+ const { x, y, z } = position,
131
+ { yaw, pitch } = angle;
132
+ this.state.enqueuePacket("move_player_pos_rot", {
133
+ x, feet_y: y, z,
134
+ yaw, pitch,
135
+ flags: makeMovementFlag(onGround, horizontalCollision)
136
+ });
137
+ }
138
+
139
+ public sendPlayerRot(
140
+ angle: Angle,
141
+ onGround: boolean,
142
+ horizontalCollision: boolean
143
+ ) {
144
+ const { yaw, pitch } = angle;
145
+ this.state.enqueuePacket("move_player_rot", {
146
+ yaw, pitch,
147
+ flags: makeMovementFlag(onGround, horizontalCollision)
148
+ });
149
+ }
150
+
151
+ public sendPlayerStatus(
152
+ onGround: boolean,
153
+ horizontalCollision: boolean
154
+ ) {
155
+ this.state.enqueuePacket("move_player_status_only", {
156
+ flags: makeMovementFlag(onGround, horizontalCollision)
157
+ });
158
+ }
159
+
160
+ public sendMessage(
161
+ content: string
162
+ ) {
163
+ if (content.length > 256)
164
+ throw new MessageTooLong(content);
165
+ const bitset = new BitSet(20);
166
+ const timestamp = Date.now();
167
+ const salt = randomBytes(8).readBigInt64BE();
168
+ this.sendPacket("chat", {
169
+ message: content,
170
+ timestamp,
171
+ salt,
172
+ signature: null, // skip for now
173
+ message_count: this.state.messageCount,
174
+ acknowledged: bitset,
175
+ checksum: 0
176
+ });
177
+ this.state.messageCount = 0;
178
+ }
179
+ }
@@ -14,6 +14,9 @@ export interface BaseAABB {
14
14
  maxZ: number;
15
15
  }
16
16
 
17
+ /**
18
+ * Represent an axis-aligned bounding box
19
+ */
17
20
  export class AABB implements BaseAABB {
18
21
  public minX: number;
19
22
  public minY: number;
@@ -348,7 +351,7 @@ export class VoxelShape {
348
351
  mergeY.forMergedIndex((y1, y2, yr) => {
349
352
  mergeZ.forMergedIndex((z1, z2, zr) => {
350
353
  if (a.isFullWide(x1, y1, z1) || b.isFullWide(x2, y2, z2))
351
- storage.set(getCoords(xr, yr, zr), 1);
354
+ storage.set(getCoords(xr, yr, zr));
352
355
  });
353
356
  });
354
357
  });
@@ -377,12 +380,13 @@ export class VoxelShape {
377
380
  this.storage = cells;
378
381
  else {
379
382
  this.storage = new BitSet();
380
- this.storage.setRange(0, (((xs.length - 1) * ys.length) + (ys.length - 1)) * zs.length + (zs.length - 1), 0);
383
+ if ((((xs.length - 1) * ys.length) + (ys.length - 1)) * zs.length + (zs.length - 1) > 0)
384
+ this.storage.clearRange(0, (((xs.length - 1) * ys.length) + (ys.length - 1)) * zs.length + (zs.length - 1));
381
385
  for (let x = 0; x < cells.length; x++)
382
386
  for (let y = 0; y < cells[x]!.length; y++)
383
387
  for (let z = 0; z < cells[x]![y]!.length; z++)
384
388
  if (cells[x]![y]![z] === true)
385
- this.storage.set(this.getIndex(x, y, z), 1);
389
+ this.storage.set(this.getIndex(x, y, z));
386
390
  }
387
391
  }
388
392
 
@@ -432,7 +436,7 @@ export class VoxelShape {
432
436
  if (x < 0 || x >= this.xs.length - 1) return false;
433
437
  if (y < 0 || y >= this.ys.length - 1) return false;
434
438
  if (z < 0 || z >= this.zs.length - 1) return false;
435
- return this.storage.get(this.getIndex(x, y, z)) === 1;
439
+ return this.storage.get(this.getIndex(x, y, z));
436
440
  }
437
441
 
438
442
  /**
@@ -637,7 +641,7 @@ export class VoxelShape {
637
641
  return true;
638
642
  }
639
643
  private clearZStrip(startZ: number, endZ: number, x: number, y: number) {
640
- this.storage.clear(this.getIndex(x, y, startZ), this.getIndex(x, y, endZ));
644
+ this.storage.clearRange(this.getIndex(x, y, startZ), this.getIndex(x, y, endZ));
641
645
  }
642
646
  }
643
647
 
@@ -679,10 +683,10 @@ class NoneOverlappingMerger extends IndexMerger {
679
683
  }
680
684
 
681
685
  private forMergedIndexNotSwapped(consumer: IndexMergerConsumer) {
682
- for (const i of this.lower)
686
+ for (let i = 0; i < this.lower.length; i++)
683
687
  consumer(i, -1, i);
684
688
 
685
- for (const i of this.upper)
689
+ for (let i = 0; i < this.upper.length; i++)
686
690
  consumer(this.lower.length - 1, i, this.lower.length + i);
687
691
  }
688
692
 
@@ -702,7 +706,7 @@ class IdenticalMerger extends IndexMerger {
702
706
  }
703
707
 
704
708
  public forMergedIndex(consumer: IndexMergerConsumer): void {
705
- for (const i of this.coords)
709
+ for (let i = 0; i < this.coords.length; i++)
706
710
  consumer(i, i, i);
707
711
  }
708
712
 
@@ -4,6 +4,9 @@ export interface BaseVec3 {
4
4
  z: number
5
5
  }
6
6
 
7
+ /**
8
+ * Represent a vector which has 3 coords
9
+ */
7
10
  export class Vec3 implements BaseVec3 {
8
11
  public static readonly Zero = new Vec3(0, 0, 0);
9
12
  public static readonly XAxis = new Vec3(1, 0, 0);