@vaitosoi/minejs 0.4.3 → 0.5.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 (105) 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/cache.d.ts +24 -0
  9. package/dist/base/cache.d.ts.map +1 -0
  10. package/dist/base/cache.js +58 -0
  11. package/dist/base/cache.js.map +1 -0
  12. package/dist/base/error.d.ts +7 -0
  13. package/dist/base/error.d.ts.map +1 -1
  14. package/dist/base/error.js +12 -1
  15. package/dist/base/error.js.map +1 -1
  16. package/dist/base/math.d.ts +12 -0
  17. package/dist/base/math.d.ts.map +1 -1
  18. package/dist/base/math.js +39 -0
  19. package/dist/base/math.js.map +1 -1
  20. package/dist/base/typing.d.ts +7 -0
  21. package/dist/base/typing.d.ts.map +1 -1
  22. package/dist/{packet → binary}/decoder.d.ts.map +1 -1
  23. package/dist/{packet → binary}/decoder.js.map +1 -1
  24. package/dist/{packet → binary}/encoder.d.ts +2 -2
  25. package/dist/binary/encoder.d.ts.map +1 -0
  26. package/dist/{packet → binary}/encoder.js +6 -2
  27. package/dist/binary/encoder.js.map +1 -0
  28. package/dist/{packet → binary}/static.d.ts.map +1 -1
  29. package/dist/{packet → binary}/static.js.map +1 -1
  30. package/dist/client/client.d.ts +23 -2
  31. package/dist/client/client.d.ts.map +1 -1
  32. package/dist/client/client.js +32 -15
  33. package/dist/client/client.js.map +1 -1
  34. package/dist/index.d.ts +12 -4
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +12 -4
  37. package/dist/index.js.map +1 -1
  38. package/dist/{client → net}/tcp.d.ts +2 -2
  39. package/dist/net/tcp.d.ts.map +1 -0
  40. package/dist/{client → net}/tcp.js +2 -2
  41. package/dist/net/tcp.js.map +1 -0
  42. package/dist/packet/{dispatcher.d.ts → listener.d.ts} +7 -18
  43. package/dist/packet/listener.d.ts.map +1 -0
  44. package/dist/packet/{dispatcher.js → listener.js} +71 -137
  45. package/dist/packet/listener.js.map +1 -0
  46. package/dist/packet/sender.d.ts +25 -0
  47. package/dist/packet/sender.d.ts.map +1 -0
  48. package/dist/packet/sender.js +144 -0
  49. package/dist/packet/sender.js.map +1 -0
  50. package/dist/physics/aabb.d.ts.map +1 -1
  51. package/dist/physics/aabb.js +9 -8
  52. package/dist/physics/aabb.js.map +1 -1
  53. package/dist/physics/player.d.ts +1 -0
  54. package/dist/physics/player.d.ts.map +1 -1
  55. package/dist/physics/player.js +21 -3
  56. package/dist/physics/player.js.map +1 -1
  57. package/dist/version/codec.d.ts +1 -1
  58. package/dist/version/codec.d.ts.map +1 -1
  59. package/dist/version/codec.js +21 -5
  60. package/dist/version/codec.js.map +1 -1
  61. package/dist/version/registry.d.ts +16 -1
  62. package/dist/version/registry.d.ts.map +1 -1
  63. package/dist/version/registry.js +31 -2
  64. package/dist/version/registry.js.map +1 -1
  65. package/dist/world/block.d.ts +5 -0
  66. package/dist/world/block.d.ts.map +1 -1
  67. package/dist/world/block.js +56 -0
  68. package/dist/world/block.js.map +1 -1
  69. package/dist/world/state.d.ts +19 -0
  70. package/dist/world/state.d.ts.map +1 -1
  71. package/dist/world/state.js +16 -0
  72. package/dist/world/state.js.map +1 -1
  73. package/package.json +8 -10
  74. package/src/base/bitset.ts +312 -31
  75. package/src/base/cache.ts +62 -0
  76. package/src/base/error.ts +9 -0
  77. package/src/base/math.ts +43 -1
  78. package/src/base/typing.ts +5 -0
  79. package/src/{packet → binary}/encoder.ts +6 -2
  80. package/src/client/client.ts +54 -19
  81. package/src/index.ts +12 -4
  82. package/src/{client → net}/tcp.ts +3 -3
  83. package/src/packet/{dispatcher.ts → listener.ts} +90 -175
  84. package/src/packet/sender.ts +176 -0
  85. package/src/physics/aabb.ts +9 -8
  86. package/src/physics/player.ts +19 -3
  87. package/src/version/codec.ts +22 -6
  88. package/src/version/registry.ts +49 -2
  89. package/src/world/block.ts +72 -2
  90. package/src/world/state.ts +39 -2
  91. package/test/bitset/index.ts +3 -8
  92. package/test/client/index.ts +12 -2
  93. package/test/state/index.ts +7 -0
  94. package/dist/client/tcp.d.ts.map +0 -1
  95. package/dist/client/tcp.js.map +0 -1
  96. package/dist/packet/dispatcher.d.ts.map +0 -1
  97. package/dist/packet/dispatcher.js.map +0 -1
  98. package/dist/packet/encoder.d.ts.map +0 -1
  99. package/dist/packet/encoder.js.map +0 -1
  100. /package/dist/{packet → binary}/decoder.d.ts +0 -0
  101. /package/dist/{packet → binary}/decoder.js +0 -0
  102. /package/dist/{packet → binary}/static.d.ts +0 -0
  103. /package/dist/{packet → binary}/static.js +0 -0
  104. /package/src/{packet → binary}/decoder.ts +0 -0
  105. /package/src/{packet → binary}/static.ts +0 -0
package/src/index.ts CHANGED
@@ -1,14 +1,22 @@
1
1
  export * from "./base/bitset";
2
+ export * from "./base/buffer";
3
+ export * from "./base/cache";
2
4
  export * from "./base/error";
3
5
  export * from "./base/event";
6
+ export * from "./base/http";
4
7
  export * from "./base/math";
5
8
  export * from "./base/typing";
9
+ export * from "./binary/decoder";
10
+ export * from "./binary/encoder";
11
+ export * from "./binary/static";
6
12
  export * from "./client/auth";
7
13
  export * from "./client/client";
8
- export * from "./client/tcp";
9
- export * from "./packet/decoder";
10
- export * from "./packet/encoder";
11
- export * from "./packet/dispatcher";
14
+ export * from "./client/static";
15
+ export * from "./message/link";
16
+ export * from "./message/sigCache";
17
+ export * from "./net/tcp";
18
+ export * from "./packet/listener";
19
+ export * from "./packet/sender";
12
20
  export * from "./physics/aabb";
13
21
  export * from "./physics/direction";
14
22
  export * from "./physics/player";
@@ -3,9 +3,9 @@ import { EventEmitter } from "node:events";
3
3
  import { deflateSync, inflateSync } from "node:zlib";
4
4
 
5
5
  import { TypedEmmiter } from "../base/event";
6
- import { BinaryDecoder } from "../packet/decoder";
7
- import { BinaryEncoder } from "../packet/encoder";
8
- import { AuthOption } from "./auth";
6
+ import { BinaryDecoder } from "../binary/decoder";
7
+ import { BinaryEncoder } from "../binary/encoder";
8
+ import { AuthOption } from "../client/auth";
9
9
  import { ClientStatus, SharedState } from "../world/state";
10
10
  import { EncodeResult } from "../version/codec";
11
11
  import { TextComponent } from "../base/typing";
@@ -1,61 +1,67 @@
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
+ export class Listener {
22
21
  private readonly mapping: Record<string, (data: object) => void>;
23
22
 
24
23
  constructor(
25
24
  private state: SharedState,
26
- private emit: TypedEmmiter<ClientEvents>["emit"]
25
+ private emit: TypedEmmiter<ClientEvents>["emit"],
26
+ private sender: Sender,
27
27
  ) {
28
28
  this.mapping = {
29
29
  "login:login_disconnect": this.handleLoginDisconnect,
30
30
  "login:hello": this.handleEncryption,
31
31
  "login:login_finished": this.handleLoginSucess,
32
32
  "login:login_compression": this.handleSetCompression,
33
+
33
34
  "configuration:disconnect": this.handleConfiguarionPlayDisconnect,
34
35
  "configuration:keep_alive": this.handleKeepAlive,
35
36
  "configuration:registry_data": this.handleRegistryData,
36
37
  "configuration:select_known_packs": this.handleKnownPack,
37
38
  "configuration:finish_configuration": this.handleFinishConfiguration,
38
- "play:add_entity": this.handleSpawnEntity,
39
+
40
+ "play:login": this.handlePlayLogin,
39
41
  "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
42
  "play:keep_alive": this.handleKeepAlive,
43
+
44
+ "play:player_chat": this.handlePlayerChat,
45
+ "play:disguised_chat": this.handleDisguisedChatMessage,
46
+ "play:system_chat": this.handleSystemMessage,
47
+ "play:set_action_bar_text": this.handleSetActionBar,
48
+
44
49
  "play:level_chunk_with_light": this.handleChunkData,
45
- "play:login": this.handlePlayLogin,
50
+ "play:forget_level_chunk": this.handleUnloadChunk,
51
+
52
+ "play:add_entity": this.handleSpawnEntity,
46
53
  "play:move_entity_pos": this.handleUpdateEntityPosition,
47
54
  "play:move_entity_pos_rot": this.handleUpdateEntityPositionRotation,
48
- "play:player_chat": this.handlePlayerChat,
55
+ "play:entity_position_sync": this.handleTeleportEntity,
49
56
  "play:player_position": this.handleSynchronizePlayerPosition,
57
+ "play:update_mob_effect": this.handleUpdateMobEffect,
50
58
  "play:remove_entities": this.handleRemoveEntity,
51
- // "play:rotate_head":
52
- "play:set_action_bar_text": this.handleSetActionBar,
59
+ "play:remove_mob_effect": this.handleRemoveMobEffect,
60
+ // "play:rotate_head": ,
53
61
  "play:set_entity_motion": this.handleSetEntityVelocity,
54
- "play:system_chat": this.handleSystemMessage,
55
62
  };
56
63
  }
57
64
 
58
- public sendPacket: (packetId: string, data: object) => void = () => { throw new NotImplemented(); };
59
65
  public disconnect: (reason: string, reasonRaw?: TextComponent) => void = () => { throw new NotImplemented(); };
60
66
 
61
67
 
@@ -99,9 +105,9 @@ export class Dispatcher {
99
105
  throw new AuthRelatedNotFound("auth client");
100
106
  else
101
107
  this.state.authClient.sendAuth(server_id, sharedSecret, publicKey)
102
- .then(() => this.sendEncryptionResponse(publicKey, verifyToken));
108
+ .then(() => this.sender.sendEncryptionResponse(publicKey, verifyToken));
103
109
  else
104
- this.sendEncryptionResponse(publicKey, verifyToken);
110
+ this.sender.sendEncryptionResponse(publicKey, verifyToken);
105
111
  }
106
112
 
107
113
  private handleSetCompression(data: object) {
@@ -136,9 +142,10 @@ export class Dispatcher {
136
142
  angle: {
137
143
  yaw: 0,
138
144
  pitch: 0,
139
- }
145
+ },
146
+ effects: {}
140
147
  } satisfies ClientPlayer as any;
141
- this.sendLoginAck();
148
+ this.sender.sendLoginAck();
142
149
  }
143
150
 
144
151
  // Configure
@@ -152,8 +159,8 @@ export class Dispatcher {
152
159
  }))
153
160
  }));
154
161
  this.state.server!.knownPacks = known_packs satisfies ServerKnownPack[] as any;
155
- this.sendKnownPack(this.state.clientOptions.loadRegistry === true ? [] : known_packs);
156
- // this.sendKnownPack([]);
162
+ this.sender.sendKnownPack(this.state.clientOptions.loadRegistry === true ? [] : known_packs);
163
+ // this.sender.sendKnownPack([]);
157
164
  }
158
165
 
159
166
  private handleRegistryData(data: object) {
@@ -171,10 +178,11 @@ export class Dispatcher {
171
178
  const registry = this.state.registry as Record<string, any[]>;
172
179
  if (!(registry_id in registry)) registry[registry_id] = [];
173
180
  registry[registry_id]!.push(...entries);
181
+ this.emit("registryData", { registry_id, entries });
174
182
  }
175
183
 
176
184
  private handleFinishConfiguration(data: object) {
177
- this.sendConfigureAck();
185
+ this.sender.sendConfigureAck();
178
186
  }
179
187
 
180
188
  private handleConfiguarionPlayDisconnect(data: object) {
@@ -225,7 +233,7 @@ export class Dispatcher {
225
233
  this.state.status = ClientStatus.Ready;
226
234
 
227
235
  if (this.state.useEncryption)
228
- this.sendPlayerSession();
236
+ this.sender.sendPlayerSession();
229
237
 
230
238
  this.emit("ready");
231
239
  }
@@ -291,8 +299,8 @@ export class Dispatcher {
291
299
  } satisfies ClientPlayer as any
292
300
  );
293
301
  this.state.enqueueEvent("playerPosition", { x: newPosX, y: newPosY, z: newPosZ });
294
- this.sendConfirmTeleportation(teleport_id);
295
- this.sendPacket("move_player_pos_rot", {
302
+ this.sender.sendConfirmTeleportation(teleport_id);
303
+ this.sender.sendPacket("move_player_pos_rot", {
296
304
  x: newPosition.x,
297
305
  feet_y: newPosition.y,
298
306
  z: newPosition.z,
@@ -308,7 +316,7 @@ export class Dispatcher {
308
316
  keep_alive_id: zod.bigint().or(zod.number())
309
317
  })
310
318
  );
311
- this.sendKeepAlive(BigInt(keep_alive_id));
319
+ this.sender.sendKeepAlive(BigInt(keep_alive_id));
312
320
  }
313
321
 
314
322
  private handleChangeGameMode(data: object) {
@@ -602,6 +610,53 @@ export class Dispatcher {
602
610
  });
603
611
  }
604
612
 
613
+ private handleUpdateMobEffect(data: object) {
614
+ const {
615
+ entity_id,
616
+ effect_id,
617
+ amplifier,
618
+ duration,
619
+ flags
620
+ } = zodParse(data, zod.object({
621
+ entity_id: zod.number(),
622
+ effect_id: zod.number(),
623
+ amplifier: zod.number(),
624
+ duration: zod.number(),
625
+ flags: zod.number(),
626
+ }));
627
+ const isAmbient = (flags & 0x01) == 1,
628
+ showParticles = (flags & 0x02) == 1,
629
+ showIcon = (flags & 0x04) == 1,
630
+ blend = (flags & 0x08) == 1;
631
+ this.state.enqueueMutation((state) => {
632
+ if (state.player!.entityId === entity_id)
633
+ state.player!.effects[effect_id] = {
634
+ amplifier,
635
+ duration,
636
+ id: effect_id,
637
+ flag: {
638
+ blend,
639
+ isAmbient,
640
+ showIcon,
641
+ showParticles
642
+ },
643
+ date: Date.now()
644
+ };
645
+ });
646
+ }
647
+
648
+ private handleRemoveMobEffect(data: object) {
649
+ const { entity_id, effect_id } = zodParse(data, zod.object({
650
+ entity_id: zod.number(),
651
+ effect_id: zod.number(),
652
+ }));
653
+
654
+ this.state.enqueueMutation((state) => {
655
+ if (state.player!.entityId === entity_id)
656
+ delete state.player!.effects[effect_id];
657
+ });
658
+ }
659
+
605
660
  // Chat
606
661
  private handlePlayerChat(data: object) {
607
662
  const {
@@ -677,6 +732,8 @@ export class Dispatcher {
677
732
  }
678
733
  }
679
734
 
735
+ if (message_signature_bytes !== null)
736
+ this.state.messageCount += 1;
680
737
  if (this.state.clientOptions.shouldVerifyMessageSignature === true && message_signature_bytes) {
681
738
  if (!this.state.sessionID)
682
739
  throw new AuthRelatedNotFound("session uuid");
@@ -716,7 +773,7 @@ export class Dispatcher {
716
773
  const signature = Buffer.from(message_signature_bytes);
717
774
 
718
775
  if (!verify.verify(publicKey!, signature))
719
- this.emit("failedMessage", emitObject);
776
+ return this.emit("failedMessage", emitObject);
720
777
  }
721
778
 
722
779
  this.emit("message", emitObject);
@@ -774,146 +831,4 @@ export class Dispatcher {
774
831
  }
775
832
  });
776
833
  }
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
834
  }
@@ -0,0 +1,176 @@
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
+ export class Sender {
14
+ constructor(
15
+ private state: SharedState,
16
+ private emit: TypedEmmiter<ClientEvents>["emit"]
17
+ ) { }
18
+
19
+ public sendPacket: (packetId: string, data: object) => void = () => { throw new NotImplemented(); };
20
+
21
+ public sendHandshake() {
22
+ this.state.state = ConnectionState.Handshake;
23
+ this.sendPacket("intention",
24
+ {
25
+ protocol_version: ProtocolVersionMapping[this.state.clientOptions.version]!,
26
+ server_address: this.state.clientOptions.host,
27
+ server_port: this.state.clientOptions.port,
28
+ intent: 2
29
+ }
30
+ );
31
+ }
32
+
33
+ public sendLoginStart() {
34
+ this.state.state = ConnectionState.Login;
35
+ this.state.status = ClientStatus.Logining;
36
+ this.sendPacket("hello", {
37
+ name: this.state.clientOptions.playerName,
38
+ player_uuid: Buffer.from(this.state.playerUUID!, "hex")
39
+ });
40
+ }
41
+
42
+ public sendEncryptionResponse(publicKey: Buffer, verifyToken: Buffer) {
43
+ const encryptedSecret = publicEncrypt({
44
+ key: createPublicKey({ key: publicKey, format: 'der', type: 'spki' }),
45
+ padding: crypto_constants.RSA_PKCS1_PADDING
46
+ }, this.state.sharedSecret!);
47
+ const encryptedVerifyToken = publicEncrypt({
48
+ key: createPublicKey({ key: publicKey, format: 'der', type: 'spki' }),
49
+ padding: crypto_constants.RSA_PKCS1_PADDING
50
+ }, verifyToken);
51
+ const secretBuf = sliceBuffer(encryptedSecret, 1, (buf) => buf.readInt8());
52
+ const token = sliceBuffer(encryptedVerifyToken, 1, (buf) => buf.readInt8());
53
+ this.sendPacket("key", {
54
+ shared_secret: { value: secretBuf, length: secretBuf.length },
55
+ verify_token: { value: token, length: token.length }
56
+ });
57
+ }
58
+
59
+ public sendLoginAck() {
60
+ this.sendPacket("login_acknowledged", {});
61
+ this.state.state = ConnectionState.Configure;
62
+ this.state.server = {};
63
+ }
64
+
65
+ // Configuring
66
+
67
+ public sendKnownPack(knownPacks: ServerKnownPack[]) {
68
+ this.sendPacket("select_known_packs", {
69
+ known_packs: {
70
+ value: knownPacks,
71
+ length: knownPacks.length
72
+ }
73
+ });
74
+ }
75
+
76
+ public sendConfigureAck() {
77
+ this.sendPacket("finish_configuration", {});
78
+ this.state.state = ConnectionState.Play;
79
+ }
80
+
81
+ // Play
82
+
83
+ public sendPlayerSession() {
84
+ const sessionUUID = randomUUIDBytes();
85
+ const expireTime = 15 * 60 * 1000; // 15min in ms
86
+ const expiredAt = Date.now() + expireTime;
87
+ const { publicKey, signature } = this.state.getSignature();
88
+ this.state.sessionID = sessionUUID;
89
+ this.sendPacket("chat_session_update", {
90
+ session_id: sessionUUID,
91
+ expire_at: expiredAt,
92
+ public_key: publicKey,
93
+ signature
94
+ });
95
+ }
96
+
97
+ public sendConfirmTeleportation(teleportId: number) {
98
+ this.sendPacket("accept_teleportation", {
99
+ teleport_id: teleportId
100
+ });
101
+ }
102
+
103
+ public sendKeepAlive(id: bigint) {
104
+ this.sendPacket("keep_alive", {
105
+ keep_alive_id: id
106
+ });
107
+ }
108
+
109
+ public sendPlayerPos(
110
+ position: BaseVec3,
111
+ onGround: boolean,
112
+ horizontalCollision: boolean
113
+ ) {
114
+ const { x, y, z } = position;
115
+ this.state.enqueuePacket("move_player_pos", {
116
+ x, feet_y: y, z,
117
+ flags: makeMovementFlag(onGround, horizontalCollision)
118
+ });
119
+ }
120
+
121
+ public sendPlayerPosRot(
122
+ position: BaseVec3,
123
+ angle: Angle,
124
+ onGround: boolean,
125
+ horizontalCollision: boolean
126
+ ) {
127
+ const { x, y, z } = position,
128
+ { yaw, pitch } = angle;
129
+ this.state.enqueuePacket("move_player_pos_rot", {
130
+ x, feet_y: y, z,
131
+ yaw, pitch,
132
+ flags: makeMovementFlag(onGround, horizontalCollision)
133
+ });
134
+ }
135
+
136
+ public sendPlayerRot(
137
+ angle: Angle,
138
+ onGround: boolean,
139
+ horizontalCollision: boolean
140
+ ) {
141
+ const { yaw, pitch } = angle;
142
+ this.state.enqueuePacket("move_player_rot", {
143
+ yaw, pitch,
144
+ flags: makeMovementFlag(onGround, horizontalCollision)
145
+ });
146
+ }
147
+
148
+ public sendPlayerStatus(
149
+ onGround: boolean,
150
+ horizontalCollision: boolean
151
+ ) {
152
+ this.state.enqueuePacket("move_player_status_only", {
153
+ flags: makeMovementFlag(onGround, horizontalCollision)
154
+ });
155
+ }
156
+
157
+ public sendMessage(
158
+ content: string
159
+ ) {
160
+ if (content.length > 256)
161
+ throw new MessageTooLong(content);
162
+ const bitset = new BitSet(20);
163
+ const timestamp = Date.now();
164
+ const salt = randomBytes(8).readBigInt64BE();
165
+ this.sendPacket("chat", {
166
+ message: content,
167
+ timestamp,
168
+ salt,
169
+ signature: null, // skip for now
170
+ message_count: this.state.messageCount,
171
+ acknowledged: bitset,
172
+ checksum: 0
173
+ });
174
+ this.state.messageCount = 0;
175
+ }
176
+ }
@@ -348,7 +348,7 @@ export class VoxelShape {
348
348
  mergeY.forMergedIndex((y1, y2, yr) => {
349
349
  mergeZ.forMergedIndex((z1, z2, zr) => {
350
350
  if (a.isFullWide(x1, y1, z1) || b.isFullWide(x2, y2, z2))
351
- storage.set(getCoords(xr, yr, zr), 1);
351
+ storage.set(getCoords(xr, yr, zr));
352
352
  });
353
353
  });
354
354
  });
@@ -377,12 +377,13 @@ export class VoxelShape {
377
377
  this.storage = cells;
378
378
  else {
379
379
  this.storage = new BitSet();
380
- this.storage.setRange(0, (((xs.length - 1) * ys.length) + (ys.length - 1)) * zs.length + (zs.length - 1), 0);
380
+ if ((((xs.length - 1) * ys.length) + (ys.length - 1)) * zs.length + (zs.length - 1) > 0)
381
+ this.storage.clearRange(0, (((xs.length - 1) * ys.length) + (ys.length - 1)) * zs.length + (zs.length - 1));
381
382
  for (let x = 0; x < cells.length; x++)
382
383
  for (let y = 0; y < cells[x]!.length; y++)
383
384
  for (let z = 0; z < cells[x]![y]!.length; z++)
384
385
  if (cells[x]![y]![z] === true)
385
- this.storage.set(this.getIndex(x, y, z), 1);
386
+ this.storage.set(this.getIndex(x, y, z));
386
387
  }
387
388
  }
388
389
 
@@ -432,7 +433,7 @@ export class VoxelShape {
432
433
  if (x < 0 || x >= this.xs.length - 1) return false;
433
434
  if (y < 0 || y >= this.ys.length - 1) return false;
434
435
  if (z < 0 || z >= this.zs.length - 1) return false;
435
- return this.storage.get(this.getIndex(x, y, z)) === 1;
436
+ return this.storage.get(this.getIndex(x, y, z));
436
437
  }
437
438
 
438
439
  /**
@@ -637,7 +638,7 @@ export class VoxelShape {
637
638
  return true;
638
639
  }
639
640
  private clearZStrip(startZ: number, endZ: number, x: number, y: number) {
640
- this.storage.clear(this.getIndex(x, y, startZ), this.getIndex(x, y, endZ));
641
+ this.storage.clearRange(this.getIndex(x, y, startZ), this.getIndex(x, y, endZ));
641
642
  }
642
643
  }
643
644
 
@@ -679,10 +680,10 @@ class NoneOverlappingMerger extends IndexMerger {
679
680
  }
680
681
 
681
682
  private forMergedIndexNotSwapped(consumer: IndexMergerConsumer) {
682
- for (const i of this.lower)
683
+ for (let i = 0; i < this.lower.length; i++)
683
684
  consumer(i, -1, i);
684
685
 
685
- for (const i of this.upper)
686
+ for (let i = 0; i < this.upper.length; i++)
686
687
  consumer(this.lower.length - 1, i, this.lower.length + i);
687
688
  }
688
689
 
@@ -702,7 +703,7 @@ class IdenticalMerger extends IndexMerger {
702
703
  }
703
704
 
704
705
  public forMergedIndex(consumer: IndexMergerConsumer): void {
705
- for (const i of this.coords)
706
+ for (let i = 0; i < this.coords.length; i++)
706
707
  consumer(i, i, i);
707
708
  }
708
709