@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.
- 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/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/math.d.ts +12 -0
- package/dist/base/math.d.ts.map +1 -1
- package/dist/base/math.js +39 -0
- package/dist/base/math.js.map +1 -1
- package/dist/base/typing.d.ts +7 -0
- package/dist/base/typing.d.ts.map +1 -1
- package/dist/{packet → binary}/decoder.d.ts.map +1 -1
- package/dist/{packet → binary}/decoder.js.map +1 -1
- package/dist/{packet → binary}/encoder.d.ts +2 -2
- package/dist/binary/encoder.d.ts.map +1 -0
- package/dist/{packet → binary}/encoder.js +6 -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/{client → net}/tcp.d.ts +2 -2
- package/dist/net/tcp.d.ts.map +1 -0
- package/dist/{client → net}/tcp.js +2 -2
- package/dist/net/tcp.js.map +1 -0
- package/dist/packet/{dispatcher.d.ts → listener.d.ts} +7 -18
- package/dist/packet/listener.d.ts.map +1 -0
- package/dist/packet/{dispatcher.js → listener.js} +71 -137
- package/dist/packet/listener.js.map +1 -0
- package/dist/packet/sender.d.ts +25 -0
- package/dist/packet/sender.d.ts.map +1 -0
- package/dist/packet/sender.js +144 -0
- package/dist/packet/sender.js.map +1 -0
- package/dist/physics/aabb.d.ts.map +1 -1
- package/dist/physics/aabb.js +9 -8
- package/dist/physics/aabb.js.map +1 -1
- package/dist/physics/player.d.ts +1 -0
- package/dist/physics/player.d.ts.map +1 -1
- package/dist/physics/player.js +21 -3
- package/dist/physics/player.js.map +1 -1
- package/dist/version/codec.d.ts +1 -1
- package/dist/version/codec.d.ts.map +1 -1
- package/dist/version/codec.js +21 -5
- package/dist/version/codec.js.map +1 -1
- package/dist/version/registry.d.ts +16 -1
- package/dist/version/registry.d.ts.map +1 -1
- package/dist/version/registry.js +31 -2
- 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 +19 -0
- package/dist/world/state.d.ts.map +1 -1
- package/dist/world/state.js +16 -0
- package/dist/world/state.js.map +1 -1
- package/package.json +8 -10
- package/src/base/bitset.ts +312 -31
- package/src/base/cache.ts +62 -0
- package/src/base/error.ts +9 -0
- package/src/base/math.ts +43 -1
- package/src/base/typing.ts +5 -0
- package/src/{packet → binary}/encoder.ts +6 -2
- package/src/client/client.ts +54 -19
- package/src/index.ts +12 -4
- package/src/{client → net}/tcp.ts +3 -3
- package/src/packet/{dispatcher.ts → listener.ts} +90 -175
- package/src/packet/sender.ts +176 -0
- package/src/physics/aabb.ts +9 -8
- package/src/physics/player.ts +19 -3
- package/src/version/codec.ts +22 -6
- package/src/version/registry.ts +49 -2
- package/src/world/block.ts +72 -2
- package/src/world/state.ts +39 -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/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}/decoder.d.ts +0 -0
- /package/dist/{packet → binary}/decoder.js +0 -0
- /package/dist/{packet → binary}/static.d.ts +0 -0
- /package/dist/{packet → binary}/static.js +0 -0
- /package/src/{packet → binary}/decoder.ts +0 -0
- /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/
|
|
9
|
-
export * from "./
|
|
10
|
-
export * from "./
|
|
11
|
-
export * from "./
|
|
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 "../
|
|
7
|
-
import { BinaryEncoder } from "../
|
|
8
|
-
import { AuthOption } from "
|
|
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,
|
|
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
|
-
export class
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
52
|
-
"play:
|
|
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
|
+
}
|
package/src/physics/aabb.ts
CHANGED
|
@@ -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)
|
|
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
|
-
|
|
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)
|
|
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))
|
|
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.
|
|
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 (
|
|
683
|
+
for (let i = 0; i < this.lower.length; i++)
|
|
683
684
|
consumer(i, -1, i);
|
|
684
685
|
|
|
685
|
-
for (
|
|
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 (
|
|
706
|
+
for (let i = 0; i < this.coords.length; i++)
|
|
706
707
|
consumer(i, i, i);
|
|
707
708
|
}
|
|
708
709
|
|