@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.
- package/README.md +12 -4
- package/assets/minecraft/26.2/effects.json +42 -0
- package/assets/minecraft/26.2/packets.json +1 -1
- package/dist/base/bitset.d.ts +43 -4
- package/dist/base/bitset.d.ts.map +1 -1
- package/dist/base/bitset.js +251 -30
- package/dist/base/bitset.js.map +1 -1
- package/dist/base/buffer.d.ts +1 -0
- package/dist/base/buffer.d.ts.map +1 -1
- package/dist/base/buffer.js +1 -0
- package/dist/base/buffer.js.map +1 -1
- package/dist/base/cache.d.ts +24 -0
- package/dist/base/cache.d.ts.map +1 -0
- package/dist/base/cache.js +58 -0
- package/dist/base/cache.js.map +1 -0
- package/dist/base/error.d.ts +7 -0
- package/dist/base/error.d.ts.map +1 -1
- package/dist/base/error.js +12 -1
- package/dist/base/error.js.map +1 -1
- package/dist/base/http.d.ts +1 -0
- package/dist/base/http.d.ts.map +1 -1
- package/dist/base/http.js +1 -0
- package/dist/base/http.js.map +1 -1
- package/dist/base/math.d.ts +14 -0
- package/dist/base/math.d.ts.map +1 -1
- package/dist/base/math.js +41 -0
- package/dist/base/math.js.map +1 -1
- package/dist/base/typing.d.ts +12 -0
- package/dist/base/typing.d.ts.map +1 -1
- package/dist/{packet → binary}/decoder.d.ts +4 -0
- package/dist/binary/decoder.d.ts.map +1 -0
- package/dist/{packet → binary}/decoder.js +4 -0
- package/dist/binary/decoder.js.map +1 -0
- package/dist/{packet → binary}/encoder.d.ts +6 -2
- package/dist/binary/encoder.d.ts.map +1 -0
- package/dist/{packet → binary}/encoder.js +10 -2
- package/dist/binary/encoder.js.map +1 -0
- package/dist/{packet → binary}/static.d.ts.map +1 -1
- package/dist/{packet → binary}/static.js.map +1 -1
- package/dist/client/client.d.ts +23 -2
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +32 -15
- package/dist/client/client.js.map +1 -1
- package/dist/index.d.ts +12 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -4
- package/dist/index.js.map +1 -1
- package/dist/message/link.d.ts +3 -0
- package/dist/message/link.d.ts.map +1 -1
- package/dist/message/link.js +3 -0
- package/dist/message/link.js.map +1 -1
- package/dist/message/sigCache.d.ts +5 -0
- package/dist/message/sigCache.d.ts.map +1 -1
- package/dist/message/sigCache.js +5 -0
- package/dist/message/sigCache.js.map +1 -1
- package/dist/{client → net}/tcp.d.ts +3 -3
- package/dist/net/tcp.d.ts.map +1 -0
- package/dist/{client → net}/tcp.js +3 -3
- package/dist/net/tcp.js.map +1 -0
- package/dist/packet/{dispatcher.d.ts → listener.d.ts} +10 -18
- package/dist/packet/listener.d.ts.map +1 -0
- package/dist/packet/{dispatcher.js → listener.js} +74 -137
- package/dist/packet/listener.js.map +1 -0
- package/dist/packet/sender.d.ts +28 -0
- package/dist/packet/sender.d.ts.map +1 -0
- package/dist/packet/sender.js +147 -0
- package/dist/packet/sender.js.map +1 -0
- package/dist/physics/aabb.d.ts +3 -0
- package/dist/physics/aabb.d.ts.map +1 -1
- package/dist/physics/aabb.js +12 -8
- package/dist/physics/aabb.js.map +1 -1
- package/dist/physics/direction.d.ts +3 -0
- package/dist/physics/direction.d.ts.map +1 -1
- package/dist/physics/direction.js +3 -0
- package/dist/physics/direction.js.map +1 -1
- package/dist/physics/player.d.ts +4 -0
- package/dist/physics/player.d.ts.map +1 -1
- package/dist/physics/player.js +24 -3
- package/dist/physics/player.js.map +1 -1
- package/dist/version/codec.d.ts +5 -1
- package/dist/version/codec.d.ts.map +1 -1
- package/dist/version/codec.js +25 -5
- package/dist/version/codec.js.map +1 -1
- package/dist/version/registry.d.ts +25 -2
- package/dist/version/registry.d.ts.map +1 -1
- package/dist/version/registry.js +43 -6
- package/dist/version/registry.js.map +1 -1
- package/dist/world/block.d.ts +5 -0
- package/dist/world/block.d.ts.map +1 -1
- package/dist/world/block.js +56 -0
- package/dist/world/block.js.map +1 -1
- package/dist/world/state.d.ts +22 -0
- package/dist/world/state.d.ts.map +1 -1
- package/dist/world/state.js +19 -0
- package/dist/world/state.js.map +1 -1
- package/package.json +8 -10
- package/src/base/bitset.ts +311 -31
- package/src/base/buffer.ts +1 -0
- package/src/base/cache.ts +62 -0
- package/src/base/error.ts +9 -0
- package/src/base/http.ts +1 -0
- package/src/base/math.ts +45 -1
- package/src/base/typing.ts +11 -0
- package/src/{packet → binary}/decoder.ts +4 -0
- package/src/{packet → binary}/encoder.ts +10 -2
- package/src/client/client.ts +54 -19
- package/src/index.ts +12 -4
- package/src/message/link.ts +3 -0
- package/src/message/sigCache.ts +5 -0
- package/src/{client → net}/tcp.ts +4 -8
- package/src/packet/{dispatcher.ts → listener.ts} +93 -175
- package/src/packet/sender.ts +179 -0
- package/src/physics/aabb.ts +12 -8
- package/src/physics/direction.ts +3 -0
- package/src/physics/player.ts +22 -3
- package/src/version/codec.ts +27 -6
- package/src/version/registry.ts +59 -3
- package/src/world/block.ts +72 -2
- package/src/world/state.ts +42 -2
- package/test/bitset/index.ts +3 -8
- package/test/client/index.ts +12 -2
- package/test/state/index.ts +7 -0
- package/dist/client/tcp.d.ts.map +0 -1
- package/dist/client/tcp.js.map +0 -1
- package/dist/packet/decoder.d.ts.map +0 -1
- package/dist/packet/decoder.js.map +0 -1
- package/dist/packet/dispatcher.d.ts.map +0 -1
- package/dist/packet/dispatcher.js.map +0 -1
- package/dist/packet/encoder.d.ts.map +0 -1
- package/dist/packet/encoder.js.map +0 -1
- /package/dist/{packet → binary}/static.d.ts +0 -0
- /package/dist/{packet → binary}/static.js +0 -0
- /package/src/{packet → binary}/static.ts +0 -0
|
@@ -1,61 +1,70 @@
|
|
|
1
1
|
import zod from "zod";
|
|
2
|
-
import { createCipheriv, createDecipheriv,
|
|
3
|
-
import { BlockEntity, ChunkSection, ClientPlayer, ClientStatus,
|
|
4
|
-
import { BinaryDecoder, getTextFromTextComponent } from "
|
|
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 {
|
|
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 "
|
|
9
|
+
import { makeMovementFlag } from "../binary/encoder";
|
|
11
10
|
import { TextComponent } from "../base/typing";
|
|
12
|
-
import { AuthRelatedNotFound, HaveSignatureButNotIndex, MessageLinkNotFound,
|
|
13
|
-
import {
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
52
|
-
"play:
|
|
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
|
+
}
|
package/src/physics/aabb.ts
CHANGED
|
@@ -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)
|
|
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
|
-
|
|
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)
|
|
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))
|
|
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.
|
|
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 (
|
|
686
|
+
for (let i = 0; i < this.lower.length; i++)
|
|
683
687
|
consumer(i, -1, i);
|
|
684
688
|
|
|
685
|
-
for (
|
|
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 (
|
|
709
|
+
for (let i = 0; i < this.coords.length; i++)
|
|
706
710
|
consumer(i, i, i);
|
|
707
711
|
}
|
|
708
712
|
|
package/src/physics/direction.ts
CHANGED