@vaitosoi/minejs 0.5.1 → 0.6.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 +4 -0
- package/assets/minecraft/26.2/components.json +113 -0
- package/assets/minecraft/26.2/packets.json +8 -16
- package/assets/minecraft/26.3/packets.json +4767 -0
- package/assets/minecraft/versionMapping.json +16 -0
- package/dist/binary/decoder.d.ts +35 -0
- package/dist/binary/decoder.d.ts.map +1 -1
- package/dist/binary/decoder.js +665 -2
- package/dist/binary/decoder.js.map +1 -1
- package/dist/binary/encoder.d.ts +3 -3
- package/dist/binary/encoder.d.ts.map +1 -1
- package/dist/binary/encoder.js.map +1 -1
- package/dist/client/client.d.ts +58 -1
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +38 -0
- package/dist/client/client.js.map +1 -1
- package/dist/net/tcp.d.ts +6 -2
- package/dist/net/tcp.d.ts.map +1 -1
- package/dist/net/tcp.js +5 -2
- package/dist/net/tcp.js.map +1 -1
- package/dist/packet/listener.d.ts +5 -0
- package/dist/packet/listener.d.ts.map +1 -1
- package/dist/packet/listener.js +78 -5
- package/dist/packet/listener.js.map +1 -1
- package/dist/packet/sender.d.ts +3 -1
- package/dist/packet/sender.d.ts.map +1 -1
- package/dist/packet/sender.js +15 -0
- package/dist/packet/sender.js.map +1 -1
- package/dist/physics/aabb.js +7 -7
- package/dist/physics/aabb.js.map +1 -1
- package/dist/physics/player.js +1 -5
- package/dist/physics/player.js.map +1 -1
- package/dist/version/codec.d.ts.map +1 -1
- package/dist/version/codec.js +25 -14
- package/dist/version/codec.js.map +1 -1
- package/dist/version/registry.d.ts +21 -5
- package/dist/version/registry.d.ts.map +1 -1
- package/dist/version/registry.js +55 -18
- package/dist/version/registry.js.map +1 -1
- package/dist/world/block.d.ts +10 -8
- package/dist/world/block.d.ts.map +1 -1
- package/dist/world/block.js +17 -11
- package/dist/world/block.js.map +1 -1
- package/dist/world/container.d.ts +106 -0
- package/dist/world/container.d.ts.map +1 -0
- package/dist/world/container.js +240 -0
- package/dist/world/container.js.map +1 -0
- package/dist/world/state.d.ts +8 -5
- package/dist/world/state.d.ts.map +1 -1
- package/dist/world/state.js +2 -0
- package/dist/world/state.js.map +1 -1
- package/package.json +2 -2
- package/src/binary/decoder.ts +691 -2
- package/src/binary/encoder.ts +3 -3
- package/src/client/client.ts +81 -4
- package/src/net/tcp.ts +16 -5
- package/src/packet/listener.ts +103 -6
- package/src/packet/sender.ts +26 -2
- package/src/physics/aabb.ts +7 -7
- package/src/physics/player.ts +5 -5
- package/src/version/codec.ts +24 -14
- package/src/version/registry.ts +61 -17
- package/src/world/block.ts +19 -17
- package/src/world/container.ts +180 -0
- package/src/world/state.ts +11 -6
- package/test/client/index.ts +49 -21
- package/test/client/registry.json +1735 -0
package/src/binary/encoder.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BaseVec3 } from "../physics/direction";
|
|
2
2
|
import { CONTINUATION_FLAG, CONTINUE_BIT, isFixedSizeTag, isTag, MAX_QUANTIZED_VALUE, SCALE_BITS, SEGMENT_BITS } from "./static";
|
|
3
3
|
import { InvalidValue, NumberTooBig, UnexpectedValue } from "../base/error";
|
|
4
4
|
import { FixedSizeTag, Tag } from "./static";
|
|
@@ -163,7 +163,7 @@ export class BinaryEncoder {
|
|
|
163
163
|
*
|
|
164
164
|
* @returns a Position
|
|
165
165
|
*/
|
|
166
|
-
public writePosition(position:
|
|
166
|
+
public writePosition(position: BaseVec3) {
|
|
167
167
|
const val = BigInt(
|
|
168
168
|
((position.x & 0x3FFFFFF) << 38) |
|
|
169
169
|
((position.z & 0x3FFFFFF) << 12) |
|
|
@@ -219,7 +219,7 @@ export class BinaryEncoder {
|
|
|
219
219
|
*
|
|
220
220
|
* Read this article for more information: https://minecraft.wiki/w/Java_Edition_protocol/Data_types#LpVec3
|
|
221
221
|
*/
|
|
222
|
-
public writeLpVec3(vec3:
|
|
222
|
+
public writeLpVec3(vec3: BaseVec3) {
|
|
223
223
|
const maxCoordinate = Math.max(Math.abs(vec3.x), Math.max(Math.abs(vec3.y), Math.abs(vec3.z)));
|
|
224
224
|
|
|
225
225
|
// Checking for NaN values in our maxCoordinate
|
package/src/client/client.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EventEmitter } from "node:events";
|
|
2
|
-
import { BlockManager, BlockState } from "../world/block";
|
|
2
|
+
import { BlockGetter, BlockManager, BlockState } from "../world/block";
|
|
3
3
|
import { EntitiesManager } from "../world/entity";
|
|
4
4
|
import { Input, Player } from "../physics/player";
|
|
5
5
|
import { TickLoop } from "../world/tick";
|
|
@@ -16,6 +16,7 @@ import { computeUUID } from "../base/math";
|
|
|
16
16
|
import { HaveSignatureButNotIndex } from "../base/error";
|
|
17
17
|
import { Sender } from "../packet/sender";
|
|
18
18
|
import { CacheImplementation } from "../base/cache";
|
|
19
|
+
import { Container, Slot } from "../world/container";
|
|
19
20
|
|
|
20
21
|
export type ClientOption = Omit<TCPClientOption, "protocolVersion"> & {
|
|
21
22
|
version: string,
|
|
@@ -103,12 +104,29 @@ export interface ClientEvents {
|
|
|
103
104
|
actionBar: [message: string],
|
|
104
105
|
/** The raw action bar */
|
|
105
106
|
actionBarRaw: [textComponent: TextComponent],
|
|
107
|
+
|
|
108
|
+
// Container
|
|
109
|
+
/** When a container is opened */
|
|
110
|
+
openContainer: [container: Container],
|
|
111
|
+
/** When the opening container is closed */
|
|
112
|
+
closeContainer: [],
|
|
113
|
+
/** When the packet contain the content of the container is received */
|
|
114
|
+
containerContent: [container: Container, carryingItem: Slot],
|
|
115
|
+
/** When the packet contain the property of the container is received */
|
|
116
|
+
containerProperty: [container: Container],
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* When tab list is updated
|
|
120
|
+
*
|
|
121
|
+
* `{"text":""}` mean remove header or footer.
|
|
122
|
+
*/
|
|
123
|
+
tablist: [newTablist: { header: { text: string, raw: TextComponent }, footer: { text: string, raw: TextComponent } }]
|
|
106
124
|
}
|
|
107
125
|
|
|
108
126
|
/**
|
|
109
127
|
* High-level client.
|
|
110
128
|
*/
|
|
111
|
-
export class Client
|
|
129
|
+
export class Client extends (EventEmitter as new () => TypedEmitter<ClientEvents>) {
|
|
112
130
|
private static loadRegistry: boolean = false;
|
|
113
131
|
|
|
114
132
|
private tickLoop: TickLoop;
|
|
@@ -118,7 +136,7 @@ export class Client<IsReady extends boolean = boolean> extends (EventEmitter as
|
|
|
118
136
|
private player: Player;
|
|
119
137
|
|
|
120
138
|
private tcp: TCPClient;
|
|
121
|
-
private state: SharedState
|
|
139
|
+
private state: SharedState;
|
|
122
140
|
private packetListener: Listener;
|
|
123
141
|
private packetSender: Sender;
|
|
124
142
|
|
|
@@ -182,7 +200,7 @@ export class Client<IsReady extends boolean = boolean> extends (EventEmitter as
|
|
|
182
200
|
this.tcp.on("destroy", () => this.emit("destroy"));
|
|
183
201
|
this.on("loadChunk", (sx, sy, sz) => this.blocks.deleteChunkCache(sx, sy, sz));
|
|
184
202
|
this.on("unloadChunk", (sx, sz) => {
|
|
185
|
-
for (let sy = 0; sy < 16; sy++)
|
|
203
|
+
for (let sy = 0; sy < 16; sy++)
|
|
186
204
|
this.blocks.deleteChunkCache(sx, sy, sz);
|
|
187
205
|
});
|
|
188
206
|
}
|
|
@@ -287,10 +305,69 @@ export class Client<IsReady extends boolean = boolean> extends (EventEmitter as
|
|
|
287
305
|
|
|
288
306
|
/**
|
|
289
307
|
* Rotate your face
|
|
308
|
+
*
|
|
309
|
+
* @see https://minecraft.wiki/w/Java_Edition_protocol/Packets#Synchronize_Player_Position For Yaw and Pitch definition:
|
|
310
|
+
*
|
|
311
|
+
* "Yaw is measured in degrees and does not follow classical trigonometry rules.
|
|
312
|
+
* The unit circle of yaw on the XZ-plane starts at (0, 1) and turns counterclockwise, with 90 at (-1, 0), 180 at (0, -1) and 270 at (1, 0).
|
|
313
|
+
*
|
|
314
|
+
* Pitch is measured in degrees, where 0 is looking straight ahead, -90 is looking straight up, and 90 is looking straight down."
|
|
315
|
+
*
|
|
290
316
|
* @param yaw In degree
|
|
291
317
|
* @param pitch In degree
|
|
292
318
|
*/
|
|
293
319
|
public lookAt(yaw: number, pitch: number) {
|
|
294
320
|
this.player.setAngle(yaw, pitch);
|
|
295
321
|
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Get opening container.
|
|
325
|
+
*
|
|
326
|
+
* Return `undefined` if not any is opening
|
|
327
|
+
*/
|
|
328
|
+
public getOpeningContainer() { return this.state.openingContainer; }
|
|
329
|
+
/**
|
|
330
|
+
* Get carrying item.
|
|
331
|
+
*
|
|
332
|
+
* Return `undefined` if not any is carried
|
|
333
|
+
*/
|
|
334
|
+
public getCarryingItem() { return this.state.player?.carryingItem; }
|
|
335
|
+
/**
|
|
336
|
+
* Get player's inventory
|
|
337
|
+
*/
|
|
338
|
+
public getInventory() { return this.state.player?.inventory; }
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Open a block.
|
|
342
|
+
*
|
|
343
|
+
* **NOTE** Not working for now
|
|
344
|
+
*
|
|
345
|
+
* @returns `true` if the target block is a solid block, or else, return `false`
|
|
346
|
+
*/
|
|
347
|
+
public openBlock(x: number, y: number, z: number): boolean;
|
|
348
|
+
public openBlock(position: BaseVec3): boolean;
|
|
349
|
+
public openBlock(a: BaseVec3 | number, b?: number, c?: number): boolean {
|
|
350
|
+
this.state.checkReady();
|
|
351
|
+
const vec3 = Vec3.loadArgs(a, b, c);
|
|
352
|
+
const clipResult = BlockGetter.clip(
|
|
353
|
+
new Vec3(this.state.player!.position),
|
|
354
|
+
new Vec3(vec3),
|
|
355
|
+
(pos) => this.blocks.at(pos)!.shape
|
|
356
|
+
)!;
|
|
357
|
+
console.log(clipResult);
|
|
358
|
+
if (clipResult.miss) return false;
|
|
359
|
+
this.packetSender.sendUseItemOn(
|
|
360
|
+
"main",
|
|
361
|
+
vec3,
|
|
362
|
+
clipResult.direction,
|
|
363
|
+
{
|
|
364
|
+
x: Math.abs(clipResult.location.x - vec3.x),
|
|
365
|
+
y: Math.abs(clipResult.location.y - vec3.y),
|
|
366
|
+
z: Math.abs(clipResult.location.z - vec3.z),
|
|
367
|
+
},
|
|
368
|
+
false,
|
|
369
|
+
false
|
|
370
|
+
);
|
|
371
|
+
return true;
|
|
372
|
+
}
|
|
296
373
|
}
|
package/src/net/tcp.ts
CHANGED
|
@@ -34,7 +34,11 @@ export interface TCPClientOption {
|
|
|
34
34
|
|
|
35
35
|
debug?: {
|
|
36
36
|
/** Log the incoming packet */
|
|
37
|
-
packetLogger: boolean
|
|
37
|
+
packetLogger: boolean,
|
|
38
|
+
/** Packet to ignore */
|
|
39
|
+
ignorePackets?: string[],
|
|
40
|
+
/** Ignore logs from TCP client (`packet X length Y`) */
|
|
41
|
+
ignoreTCPPacketLogs?: number[] | true
|
|
38
42
|
},
|
|
39
43
|
|
|
40
44
|
// For premium account
|
|
@@ -52,8 +56,8 @@ export interface Message {
|
|
|
52
56
|
target: string | undefined,
|
|
53
57
|
content: string,
|
|
54
58
|
raw: {
|
|
55
|
-
sender: TextComponent,
|
|
56
|
-
target: TextComponent | undefined,
|
|
59
|
+
sender: string | TextComponent,
|
|
60
|
+
target: string | TextComponent | undefined,
|
|
57
61
|
content: TextComponent | undefined
|
|
58
62
|
}
|
|
59
63
|
}
|
|
@@ -159,7 +163,7 @@ export class TCPClient extends (EventEmitter as new () => TypedEmmiter<TCPClient
|
|
|
159
163
|
if (dataLength === 0) {
|
|
160
164
|
packetID = decoder.readVarInt();
|
|
161
165
|
} else {
|
|
162
|
-
const dataBuffer =
|
|
166
|
+
const dataBuffer = decoder.buffer.subarray(decoder.offset, expectedPacketEnd);
|
|
163
167
|
const decompressed = inflateSync(dataBuffer);
|
|
164
168
|
if (decompressed.length !== dataLength)
|
|
165
169
|
throw new UnexpectedValue("decompressed packet data", decompressed.length.toString(), dataLength.toString());
|
|
@@ -167,7 +171,14 @@ export class TCPClient extends (EventEmitter as new () => TypedEmmiter<TCPClient
|
|
|
167
171
|
packetID = decoder.readVarInt();
|
|
168
172
|
}
|
|
169
173
|
}
|
|
170
|
-
if (
|
|
174
|
+
if (
|
|
175
|
+
this.state.clientOptions.debug &&
|
|
176
|
+
this.state.clientOptions.debug.packetLogger &&
|
|
177
|
+
(
|
|
178
|
+
(Array.isArray(this.state.clientOptions.debug.ignoreTCPPacketLogs) && !this.state.clientOptions.debug.ignoreTCPPacketLogs.includes(packetID)) ||
|
|
179
|
+
(!this.state.clientOptions.debug.ignoreTCPPacketLogs)
|
|
180
|
+
)
|
|
181
|
+
)
|
|
171
182
|
console.log("packet", packetID, "length", decoder.buffer.length);
|
|
172
183
|
this.forwardPacket(packetID, decoder);
|
|
173
184
|
|
package/src/packet/listener.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { AuthRelatedNotFound, HaveSignatureButNotIndex, MessageLinkNotFound, Not
|
|
|
12
12
|
import { uuidToBuffer } from "../base/math";
|
|
13
13
|
import { MessageLink } from "../message/link";
|
|
14
14
|
import { Sender } from "./sender";
|
|
15
|
+
import { Container, Slot } from "../world/container";
|
|
15
16
|
|
|
16
17
|
function zodParse<Type extends zod.ZodType>(data: object, zod: Type): zod.infer<Type> {
|
|
17
18
|
return zod.parse(data);
|
|
@@ -62,6 +63,13 @@ export class Listener {
|
|
|
62
63
|
"play:remove_mob_effect": this.handleRemoveMobEffect,
|
|
63
64
|
// "play:rotate_head": ,
|
|
64
65
|
"play:set_entity_motion": this.handleSetEntityVelocity,
|
|
66
|
+
|
|
67
|
+
"play:open_screen": this.handleOpenScreen,
|
|
68
|
+
"play:container_close": this.handleCloseContainer,
|
|
69
|
+
"play:container_set_content": this.handleContainerContent,
|
|
70
|
+
"play:container_set_data": this.handleContainerProperty,
|
|
71
|
+
|
|
72
|
+
"play:tab_list": this.handleSetTablist
|
|
65
73
|
};
|
|
66
74
|
}
|
|
67
75
|
|
|
@@ -76,7 +84,11 @@ export class Listener {
|
|
|
76
84
|
// Login
|
|
77
85
|
|
|
78
86
|
private handleLoginDisconnect(data: object) {
|
|
79
|
-
const { reason } = zodParse(data, zod.object({ reason: zod.record(zod.string(), zod.any()) }));
|
|
87
|
+
const { reason } = zodParse(data, zod.object({ reason: zod.record(zod.string(), zod.any()).or(zod.string()) }));
|
|
88
|
+
|
|
89
|
+
if (typeof reason === "string")
|
|
90
|
+
return this.disconnect(reason);
|
|
91
|
+
|
|
80
92
|
const text = getTextFromTextComponent(reason);
|
|
81
93
|
|
|
82
94
|
this.disconnect(text, reason);
|
|
@@ -146,7 +158,9 @@ export class Listener {
|
|
|
146
158
|
yaw: 0,
|
|
147
159
|
pitch: 0,
|
|
148
160
|
},
|
|
149
|
-
effects: {}
|
|
161
|
+
effects: {},
|
|
162
|
+
inventory: new Container(0, -1, {}),
|
|
163
|
+
carryingItem: undefined
|
|
150
164
|
} satisfies ClientPlayer as any;
|
|
151
165
|
this.sender.sendLoginAck();
|
|
152
166
|
}
|
|
@@ -693,12 +707,16 @@ export class Listener {
|
|
|
693
707
|
filter_type: zod.int(),
|
|
694
708
|
filter_type_bits: zod.array(zod.bigint()).nullable(),
|
|
695
709
|
chat_type: zod.int().or(zod.record(zod.string(), zod.any())),
|
|
696
|
-
sender_name: zod.record(zod.string(), zod.any()),
|
|
697
|
-
target_name: zod.record(zod.string(), zod.any()).nullable()
|
|
710
|
+
sender_name: zod.record(zod.string(), zod.any()).or(zod.string()),
|
|
711
|
+
target_name: zod.record(zod.string(), zod.any()).or(zod.string()).nullable()
|
|
698
712
|
}));
|
|
699
713
|
|
|
700
|
-
const senderNameText = getTextFromTextComponent(sender_name).toString(),
|
|
701
|
-
targetNameText = target_name
|
|
714
|
+
const senderNameText = typeof sender_name === "string" ? sender_name : getTextFromTextComponent(sender_name).toString(),
|
|
715
|
+
targetNameText = target_name
|
|
716
|
+
? typeof target_name === "string"
|
|
717
|
+
? target_name
|
|
718
|
+
: getTextFromTextComponent(target_name).toString()
|
|
719
|
+
: undefined;
|
|
702
720
|
|
|
703
721
|
const emitObject = {
|
|
704
722
|
sender: senderNameText,
|
|
@@ -834,4 +852,83 @@ export class Listener {
|
|
|
834
852
|
}
|
|
835
853
|
});
|
|
836
854
|
}
|
|
855
|
+
|
|
856
|
+
// Container
|
|
857
|
+
private handleOpenScreen(data: object) {
|
|
858
|
+
const {
|
|
859
|
+
window_id,
|
|
860
|
+
window_type,
|
|
861
|
+
window_title
|
|
862
|
+
} = zodParse(data, zod.object({
|
|
863
|
+
window_id: zod.int(),
|
|
864
|
+
window_type: zod.int(),
|
|
865
|
+
window_title: zod.record(zod.string(), zod.any())
|
|
866
|
+
}));
|
|
867
|
+
this.state.enqueueMutation(state => {
|
|
868
|
+
state.openingContainer = new Container(window_id, window_type, window_title);
|
|
869
|
+
this.emit("openContainer", this.state.openingContainer!);
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
private handleCloseContainer(data: object) {
|
|
874
|
+
// Not used by vanilla client
|
|
875
|
+
const { window_id } = zodParse(data, zod.object({ window_id: zod.int() }));
|
|
876
|
+
|
|
877
|
+
this.state.enqueueMutation(state => {
|
|
878
|
+
state.openingContainer = undefined;
|
|
879
|
+
this.emit("closeContainer");
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
private handleContainerContent(data: object) {
|
|
884
|
+
const {
|
|
885
|
+
window_id,
|
|
886
|
+
state_id,
|
|
887
|
+
slot_data,
|
|
888
|
+
carried_item
|
|
889
|
+
} = zodParse(data, zod.object({
|
|
890
|
+
window_id: zod.int(),
|
|
891
|
+
state_id: zod.int(),
|
|
892
|
+
slot_data: zod.array(zod.any() as zod.ZodType<Slot>),
|
|
893
|
+
carried_item: zod.any() as zod.ZodType<Slot>,
|
|
894
|
+
}));
|
|
895
|
+
this.state.enqueueMutation(state => {
|
|
896
|
+
if (!state.openingContainer) return;
|
|
897
|
+
state.openingContainer.stateId = state_id;
|
|
898
|
+
state.openingContainer.slots = slot_data;
|
|
899
|
+
state.player!.carryingItem = carried_item;
|
|
900
|
+
this.emit("containerContent", state.openingContainer, state.player!.carryingItem);
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
private handleContainerProperty(data: object) {
|
|
905
|
+
const {
|
|
906
|
+
window_id,
|
|
907
|
+
property,
|
|
908
|
+
value
|
|
909
|
+
} = zodParse(data, zod.object({
|
|
910
|
+
window_id: zod.number(),
|
|
911
|
+
property: zod.number(),
|
|
912
|
+
value: zod.number(),
|
|
913
|
+
}));
|
|
914
|
+
this.state.enqueueMutation(state => {
|
|
915
|
+
if (!state.openingContainer) return;
|
|
916
|
+
state.openingContainer.setProperty(property, value);
|
|
917
|
+
this.emit("containerProperty", state.openingContainer);
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
private handleSetTablist(data: object) {
|
|
922
|
+
const { header, footer } = zodParse(data, zod.object({
|
|
923
|
+
header: zod.record(zod.string(), zod.any()),
|
|
924
|
+
footer: zod.record(zod.string(), zod.any()),
|
|
925
|
+
}));
|
|
926
|
+
this.emit(
|
|
927
|
+
"tablist",
|
|
928
|
+
{
|
|
929
|
+
header: { text: getTextFromTextComponent(header), raw: header },
|
|
930
|
+
footer: { text: getTextFromTextComponent(footer), raw: footer },
|
|
931
|
+
}
|
|
932
|
+
);
|
|
933
|
+
}
|
|
837
934
|
}
|
package/src/packet/sender.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { createPublicKey, publicEncrypt, constants as crypto_constants, randomBytes } from "node:crypto";
|
|
1
|
+
import { createPublicKey, publicEncrypt, constants as crypto_constants, randomBytes, randomInt } from "node:crypto";
|
|
2
2
|
import { TypedEmmiter } from "../base/event";
|
|
3
3
|
import { ClientEvents } from "../client/client";
|
|
4
4
|
import { ProtocolVersionMapping } from "../version/registry";
|
|
5
5
|
import { ClientStatus, ConnectionState, ServerKnownPack, SharedState } from "../world/state";
|
|
6
6
|
import { sliceBuffer } from "../base/buffer";
|
|
7
7
|
import { randomUUIDBytes } from "../base/math";
|
|
8
|
-
import { Angle, BaseVec3 } from "../physics/direction";
|
|
8
|
+
import { Angle, BaseVec3, Direction } from "../physics/direction";
|
|
9
9
|
import { MessageTooLong, NotImplemented } from "../base/error";
|
|
10
10
|
import BitSet from "../base/bitset";
|
|
11
11
|
import { makeMovementFlag } from "../binary/encoder";
|
|
12
|
+
import { BlockFace } from "../world/block";
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Packet sender
|
|
@@ -176,4 +177,27 @@ export class Sender {
|
|
|
176
177
|
});
|
|
177
178
|
this.state.messageCount = 0;
|
|
178
179
|
}
|
|
180
|
+
|
|
181
|
+
public sendUseItemOn(
|
|
182
|
+
hand: "main" | "off",
|
|
183
|
+
position: BaseVec3,
|
|
184
|
+
face: BlockFace | Direction,
|
|
185
|
+
cursorPositionOnBlock: BaseVec3,
|
|
186
|
+
isInsideBlock: boolean,
|
|
187
|
+
worldBorderHit: boolean,
|
|
188
|
+
sequence: number = randomInt(1024),
|
|
189
|
+
) {
|
|
190
|
+
const face_ = (face instanceof Direction ? face.index3D : face) as number;
|
|
191
|
+
this.sendPacket("use_item_on", {
|
|
192
|
+
hand: hand === "off" ? 1 : 0,
|
|
193
|
+
location: position,
|
|
194
|
+
face: face_,
|
|
195
|
+
cursor_position_x: cursorPositionOnBlock.x,
|
|
196
|
+
cursor_position_y: cursorPositionOnBlock.y,
|
|
197
|
+
cursor_position_z: cursorPositionOnBlock.z,
|
|
198
|
+
inside_block: isInsideBlock,
|
|
199
|
+
world_border_hit: worldBorderHit,
|
|
200
|
+
sequence
|
|
201
|
+
});
|
|
202
|
+
}
|
|
179
203
|
}
|
package/src/physics/aabb.ts
CHANGED
|
@@ -209,7 +209,7 @@ export class AABB implements BaseAABB {
|
|
|
209
209
|
* Cliping math. Find smallest distance to reach a face of this AABB.
|
|
210
210
|
*/
|
|
211
211
|
public static getDirection(aabb: BaseAABB, from: BaseVec3, delta: BaseVec3, direction_: Direction | null, scaleRef: [number]) {
|
|
212
|
-
let direction =
|
|
212
|
+
let direction = direction_;
|
|
213
213
|
const { minX, maxX, minY, maxY, minZ, maxZ } = aabb;
|
|
214
214
|
if (delta.x > Epsilon)
|
|
215
215
|
direction = this.clipPoint(
|
|
@@ -217,7 +217,7 @@ export class AABB implements BaseAABB {
|
|
|
217
217
|
scaleRef,
|
|
218
218
|
{ a: delta.x, b: delta.y, c: delta.z },
|
|
219
219
|
minX,
|
|
220
|
-
minY,
|
|
220
|
+
minY, maxY,
|
|
221
221
|
minZ, maxZ,
|
|
222
222
|
from.x, from.y, from.z
|
|
223
223
|
);
|
|
@@ -227,7 +227,7 @@ export class AABB implements BaseAABB {
|
|
|
227
227
|
scaleRef,
|
|
228
228
|
{ a: delta.x, b: delta.y, c: delta.z },
|
|
229
229
|
maxX,
|
|
230
|
-
minY,
|
|
230
|
+
minY, maxY,
|
|
231
231
|
minZ, maxZ,
|
|
232
232
|
from.x, from.y, from.z
|
|
233
233
|
);
|
|
@@ -292,7 +292,7 @@ export class AABB implements BaseAABB {
|
|
|
292
292
|
/**
|
|
293
293
|
* `s` come from this equation:
|
|
294
294
|
* ```
|
|
295
|
-
* fromA + s * deltaA = minA (or point here)
|
|
295
|
+
* fromA + s * deltaA = minA (or `point` here)
|
|
296
296
|
* ```
|
|
297
297
|
* Which find "how far the ray travels to reach a face of this bounding box".
|
|
298
298
|
*
|
|
@@ -305,7 +305,7 @@ export class AABB implements BaseAABB {
|
|
|
305
305
|
pb = fromB + s * delta.b,
|
|
306
306
|
pc = fromC + s * delta.c;
|
|
307
307
|
if (
|
|
308
|
-
0 < s && s < scaleRef[0] &&
|
|
308
|
+
0 < s && s < scaleRef[0] + Epsilon &&
|
|
309
309
|
minB - Epsilon < pb && pb < maxB + Epsilon &&
|
|
310
310
|
minC - Epsilon < pc && pc < maxC + Epsilon
|
|
311
311
|
) {
|
|
@@ -599,9 +599,9 @@ export class VoxelShape {
|
|
|
599
599
|
minZ: z,
|
|
600
600
|
maxZ: z + 1
|
|
601
601
|
});
|
|
602
|
-
else if (lastStartZ
|
|
602
|
+
else if (lastStartZ === -1)
|
|
603
603
|
lastStartZ = z;
|
|
604
|
-
} else if (lastStartZ
|
|
604
|
+
} else if (lastStartZ !== -1) {
|
|
605
605
|
let endX = x,
|
|
606
606
|
endY = y;
|
|
607
607
|
shape.clearZStrip(lastStartZ, z, endX, endY);
|
package/src/physics/player.ts
CHANGED
|
@@ -473,11 +473,11 @@ export class Player {
|
|
|
473
473
|
if (this.fallDistance != 0 && movement.length() >= 1) {
|
|
474
474
|
const checkDistance = Math.min(movement.length(), 8);
|
|
475
475
|
const checkTo = this.getPos().add(movement.normalize().scale(checkDistance));
|
|
476
|
-
const hitResult = BlockGetter.clip(
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
476
|
+
const hitResult = BlockGetter.clip(
|
|
477
|
+
this.getPos(),
|
|
478
|
+
checkTo,
|
|
479
|
+
(position) => this.blocks.at(position)!.shape
|
|
480
|
+
);
|
|
481
481
|
if (hitResult?.miss !== false)
|
|
482
482
|
this.fallDistance = 0;
|
|
483
483
|
}
|
package/src/version/codec.ts
CHANGED
|
@@ -49,11 +49,14 @@ export class VersionCodec {
|
|
|
49
49
|
if (err instanceof NotImplemented) return;
|
|
50
50
|
throw err;
|
|
51
51
|
}
|
|
52
|
-
if (this.state.clientOptions.debug
|
|
52
|
+
if (this.state.clientOptions.debug &&
|
|
53
|
+
this.state.clientOptions.debug.packetLogger &&
|
|
54
|
+
(this.state.clientOptions.debug.ignorePackets &&
|
|
55
|
+
!this.state.clientOptions.debug.ignorePackets.includes(packet.name)))
|
|
53
56
|
console.dir({
|
|
54
57
|
dir: "to client",
|
|
55
58
|
state: mappedState,
|
|
56
|
-
name,
|
|
59
|
+
name: packet.name,
|
|
57
60
|
data: resolvedObject,
|
|
58
61
|
});
|
|
59
62
|
|
|
@@ -66,11 +69,15 @@ export class VersionCodec {
|
|
|
66
69
|
const packet = PacketRegistry.getPacket(mappedState, "serverbound", packetId);
|
|
67
70
|
if (!packet) throw new UnexpectedValue("valid serverbound packet id", packetId.toString());
|
|
68
71
|
|
|
69
|
-
if (this.state.clientOptions.debug
|
|
72
|
+
if (this.state.clientOptions.debug &&
|
|
73
|
+
this.state.clientOptions.debug.packetLogger &&
|
|
74
|
+
(this.state.clientOptions.debug.ignorePackets &&
|
|
75
|
+
!this.state.clientOptions.debug.ignorePackets.includes(packet.name)))
|
|
70
76
|
console.dir({
|
|
71
77
|
dir: "to server",
|
|
72
78
|
state: mappedState,
|
|
73
|
-
id:
|
|
79
|
+
id: packet.id,
|
|
80
|
+
name: packet.name,
|
|
74
81
|
data,
|
|
75
82
|
});
|
|
76
83
|
|
|
@@ -144,7 +151,17 @@ export class VersionCodec {
|
|
|
144
151
|
case "chat_type_decoration": return decoder.readChatTypeDecoration();
|
|
145
152
|
case "chat_type": return decoder.readChatType();
|
|
146
153
|
case "enum": return this.readField(packetId, readObject, fieldName, field.subType, decoder);
|
|
147
|
-
case "json_text":
|
|
154
|
+
case "json_text": {
|
|
155
|
+
const str = decoder.readString();
|
|
156
|
+
try {
|
|
157
|
+
return JSON.parse(str);
|
|
158
|
+
} catch (err) {
|
|
159
|
+
if (err instanceof SyntaxError)
|
|
160
|
+
return str;
|
|
161
|
+
else
|
|
162
|
+
throw err;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
148
165
|
case "object": {
|
|
149
166
|
const obj: Record<string, any> = {};
|
|
150
167
|
for (const [key, type] of Object.entries(field.fields))
|
|
@@ -152,15 +169,7 @@ export class VersionCodec {
|
|
|
152
169
|
return obj;
|
|
153
170
|
}
|
|
154
171
|
case "game_profile": {
|
|
155
|
-
return
|
|
156
|
-
uuid: decoder.readUUID(),
|
|
157
|
-
username: decoder.readString(),
|
|
158
|
-
pproperties: decoder.readPrefixedArray((decoder) => ({
|
|
159
|
-
name: decoder.readString(),
|
|
160
|
-
value: decoder.readString(),
|
|
161
|
-
signature: decoder.readPrefixedOptional((decoder) => decoder.readString())
|
|
162
|
-
}))
|
|
163
|
-
};
|
|
172
|
+
return decoder.readProfile();
|
|
164
173
|
}
|
|
165
174
|
case "heightmap": {
|
|
166
175
|
return {
|
|
@@ -170,6 +179,7 @@ export class VersionCodec {
|
|
|
170
179
|
}
|
|
171
180
|
case "bitset": return decoder.readPrefixedArray((decoder) => decoder.readLong());
|
|
172
181
|
case "teleport_flags": return decoder.readTeleportFlag();
|
|
182
|
+
case "slot": return decoder.readSlot();
|
|
173
183
|
case "null": return null;
|
|
174
184
|
case "not_implemented": {
|
|
175
185
|
if (field.skip_able === true)
|