@vaitosoi/minejs 0.5.1 → 0.6.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 +25 -9
- package/assets/minecraft/26.2/components.json +113 -0
- package/assets/minecraft/26.2/packets.json +8 -28
- package/assets/minecraft/26.3/packets.json +4957 -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 +4 -4
- package/dist/binary/encoder.js.map +1 -1
- package/dist/client/client.d.ts +178 -22
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +132 -13
- package/dist/client/client.js.map +1 -1
- package/dist/net/tcp.d.ts +6 -9
- package/dist/net/tcp.d.ts.map +1 -1
- package/dist/net/tcp.js +16 -19
- package/dist/net/tcp.js.map +1 -1
- package/dist/packet/listener.d.ts +6 -1
- package/dist/packet/listener.d.ts.map +1 -1
- package/dist/packet/listener.js +220 -60
- package/dist/packet/listener.js.map +1 -1
- package/dist/packet/sender.d.ts +4 -1
- package/dist/packet/sender.d.ts.map +1 -1
- package/dist/packet/sender.js +30 -4
- package/dist/packet/sender.js.map +1 -1
- package/dist/physics/aabb.d.ts.map +1 -1
- package/dist/physics/aabb.js +17 -9
- package/dist/physics/aabb.js.map +1 -1
- package/dist/physics/direction.js +2 -2
- package/dist/physics/direction.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 +63 -14
- package/dist/version/codec.js.map +1 -1
- package/dist/version/registry.d.ts +26 -5
- package/dist/version/registry.d.ts.map +1 -1
- package/dist/version/registry.js +78 -18
- package/dist/version/registry.js.map +1 -1
- package/dist/world/block.d.ts +54 -10
- package/dist/world/block.d.ts.map +1 -1
- package/dist/world/block.js +78 -32
- 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/entity.d.ts +3 -0
- package/dist/world/entity.d.ts.map +1 -1
- package/dist/world/entity.js +3 -0
- package/dist/world/entity.js.map +1 -1
- package/dist/world/state.d.ts +11 -5
- package/dist/world/state.d.ts.map +1 -1
- package/dist/world/state.js +11 -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 +8 -9
- package/src/client/client.ts +234 -34
- package/src/net/tcp.ts +27 -22
- package/src/packet/listener.ts +275 -76
- package/src/packet/sender.ts +42 -7
- package/src/physics/aabb.ts +18 -9
- package/src/physics/direction.ts +2 -2
- package/src/physics/player.ts +5 -5
- package/src/version/codec.ts +56 -14
- package/src/version/registry.ts +92 -18
- package/src/world/block.ts +83 -39
- package/src/world/container.ts +180 -0
- package/src/world/entity.ts +3 -0
- package/src/world/state.ts +21 -6
- package/test/client/index.ts +56 -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";
|
|
@@ -71,7 +71,7 @@ export class BinaryEncoder {
|
|
|
71
71
|
public writeLong(val: bigint | number) {
|
|
72
72
|
// Cast to BigInt
|
|
73
73
|
const v = typeof val === "bigint" ? val : BigInt(val);
|
|
74
|
-
return this.write(8, v, (buf) => buf.writeBigInt64BE);
|
|
74
|
+
return this.write(8, BigInt.asIntN(64, v), (buf) => buf.writeBigInt64BE);
|
|
75
75
|
}
|
|
76
76
|
/**
|
|
77
77
|
* Write 4 bytes float
|
|
@@ -163,12 +163,11 @@ export class BinaryEncoder {
|
|
|
163
163
|
*
|
|
164
164
|
* @returns a Position
|
|
165
165
|
*/
|
|
166
|
-
public writePosition(position:
|
|
167
|
-
const val =
|
|
168
|
-
((position.x & 0x3FFFFFF) <<
|
|
169
|
-
((position.z & 0x3FFFFFF) <<
|
|
170
|
-
(position.y & 0xFFF)
|
|
171
|
-
);
|
|
166
|
+
public writePosition(position: BaseVec3) {
|
|
167
|
+
const val =
|
|
168
|
+
(BigInt(position.x & 0x3FFFFFF) << 38n) |
|
|
169
|
+
(BigInt(position.z & 0x3FFFFFF) << 12n) |
|
|
170
|
+
BigInt(position.y & 0xFFF);
|
|
172
171
|
this.writeLong(val);
|
|
173
172
|
return this;
|
|
174
173
|
}
|
|
@@ -219,7 +218,7 @@ export class BinaryEncoder {
|
|
|
219
218
|
*
|
|
220
219
|
* Read this article for more information: https://minecraft.wiki/w/Java_Edition_protocol/Data_types#LpVec3
|
|
221
220
|
*/
|
|
222
|
-
public writeLpVec3(vec3:
|
|
221
|
+
public writeLpVec3(vec3: BaseVec3) {
|
|
223
222
|
const maxCoordinate = Math.max(Math.abs(vec3.x), Math.max(Math.abs(vec3.y), Math.abs(vec3.z)));
|
|
224
223
|
|
|
225
224
|
// 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,14 +16,18 @@ 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"> & {
|
|
22
|
+
/**
|
|
23
|
+
* The client version. Supports 26.2 and 26.3
|
|
24
|
+
*/
|
|
21
25
|
version: string,
|
|
22
26
|
|
|
23
27
|
/**
|
|
24
|
-
* Whenever should the client verify the message against the signature, if any
|
|
28
|
+
* Whenever should the client verify the message against the signature, if any.
|
|
25
29
|
*
|
|
26
|
-
*
|
|
30
|
+
* In order to set this option to true, you HAVE TO set `shouldVerifyMessageOrder` to true
|
|
27
31
|
*/
|
|
28
32
|
shouldVerifyMessageSignature?: boolean,
|
|
29
33
|
|
|
@@ -57,28 +61,50 @@ export interface ClientEvents {
|
|
|
57
61
|
/**
|
|
58
62
|
* When the client is ready.
|
|
59
63
|
*
|
|
60
|
-
* Specifically, when the packet `Login (play)` is received
|
|
64
|
+
* Specifically, when the packet `Login (play)` is received.
|
|
65
|
+
*
|
|
66
|
+
* Most of the client method require this event to be fired in order to work.
|
|
61
67
|
*/
|
|
62
68
|
ready: [],
|
|
63
69
|
/**
|
|
64
|
-
* When the client got disconnected from
|
|
70
|
+
* When the client got disconnected from server.
|
|
71
|
+
*
|
|
72
|
+
* This event only provide the parsed string. To get the unparsed, or the raw one with decoration, use `disconnectRaw`.
|
|
73
|
+
* But, the `disconnectRaw` is only fired when the disconnection come from the server, or the server disconnect the client.
|
|
74
|
+
* Sometime, the disconnect will be fired within the client, meaning that there will be no `disconnectRaw`
|
|
65
75
|
*/
|
|
66
76
|
disconnect: [reason: string],
|
|
67
77
|
/**
|
|
68
|
-
* When the
|
|
78
|
+
* When the disconnection come with the raw Text Component.
|
|
69
79
|
*/
|
|
70
80
|
disconnectRaw: [textComponent: TextComponent],
|
|
71
81
|
|
|
82
|
+
/** The registry_data packet */
|
|
83
|
+
registryData: [data: RegistryData],
|
|
84
|
+
|
|
72
85
|
/**
|
|
73
|
-
* When server send `Player Position Synchronization` packet
|
|
86
|
+
* When server send `Player Position Synchronization` packet.
|
|
87
|
+
*
|
|
88
|
+
* **Note:** this event is not fired when the client is moved by holding the input.
|
|
74
89
|
*
|
|
75
|
-
*
|
|
90
|
+
* To get the player current position, use `getPosition` method
|
|
76
91
|
*/
|
|
77
92
|
playerPosition: [position: BaseVec3],
|
|
78
93
|
|
|
79
|
-
/**
|
|
94
|
+
/**
|
|
95
|
+
* When the chunk is loaded
|
|
96
|
+
*
|
|
97
|
+
* Explaining the `chunkX`, `sectionY`, `chunkZ`: A chunk in Minecraft is a region which length and width is 16 and the height extends to the limit.
|
|
98
|
+
* But when sending the packet, the chunk is divided into smaller section which volume is 16x16x16.
|
|
99
|
+
* So the `chunkX` and `chunkZ` is the chunk position and `sectionY` is the section within that chunk,
|
|
100
|
+
* counting from the bedrock up to the sky
|
|
101
|
+
*/
|
|
80
102
|
loadChunk: [chunkX: number, sectionY: number, chunkZ: number],
|
|
81
|
-
/**
|
|
103
|
+
/**
|
|
104
|
+
* When the chunk got deleted by the server
|
|
105
|
+
*
|
|
106
|
+
* See the `chunkX` and `chunkZ` explaination in `loadChunk` events
|
|
107
|
+
*/
|
|
82
108
|
unloadChunk: [chunkX: number, chunkZ: number],
|
|
83
109
|
|
|
84
110
|
/** When an entity is spawned or appeared in the client view distance */
|
|
@@ -87,28 +113,86 @@ export interface ClientEvents {
|
|
|
87
113
|
updateEntity: [entityId: number],
|
|
88
114
|
/** When an entity go out of client view distance or despawned */
|
|
89
115
|
removeEntity: [entityId: number],
|
|
90
|
-
|
|
91
|
-
registryData: [data: RegistryData],
|
|
92
|
-
|
|
116
|
+
|
|
93
117
|
// Chat
|
|
94
118
|
/** When a chat message got broadcasted */
|
|
95
119
|
message: [message: Message],
|
|
96
120
|
/** When a message is failed to be verified against the signature sent with it */
|
|
97
121
|
failedMessage: [message: Message],
|
|
98
|
-
/**
|
|
122
|
+
/**
|
|
123
|
+
* The system message
|
|
124
|
+
*
|
|
125
|
+
* This event only provide the parsed string. To get the unparsed, or the raw one with decoration, use `systemMessageRaw`
|
|
126
|
+
*/
|
|
99
127
|
systemMessage: [message: string],
|
|
100
|
-
/**
|
|
128
|
+
/**
|
|
129
|
+
* The system message with the Text Component for decorations
|
|
130
|
+
*/
|
|
101
131
|
systemMessageRaw: [textComponent: TextComponent],
|
|
102
|
-
/**
|
|
132
|
+
/**
|
|
133
|
+
* The action bar
|
|
134
|
+
*
|
|
135
|
+
* This event only provide the parsed string. To get the unparsed, or the raw one with decoration, use `actionBarRaw`
|
|
136
|
+
*/
|
|
103
137
|
actionBar: [message: string],
|
|
104
138
|
/** The raw action bar */
|
|
105
139
|
actionBarRaw: [textComponent: TextComponent],
|
|
140
|
+
|
|
141
|
+
// Container
|
|
142
|
+
/**
|
|
143
|
+
* When a container is opened
|
|
144
|
+
*
|
|
145
|
+
* This event will be fired when client click on a block (with `openBlock` method) that is a container
|
|
146
|
+
* or when server believe that you just open a container (with open_screen packet).
|
|
147
|
+
*/
|
|
148
|
+
openContainer: [container: Container],
|
|
149
|
+
/** When the opening container is closed */
|
|
150
|
+
closeContainer: [],
|
|
151
|
+
/** When the packet contain the content of the container is received */
|
|
152
|
+
containerContent: [container: Container, carryingItem: Slot],
|
|
153
|
+
/** When the packet contain the property of the container is received */
|
|
154
|
+
containerProperty: [container: Container],
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* When tab list is updated
|
|
158
|
+
*
|
|
159
|
+
* `{"text":""}` mean remove header or footer.
|
|
160
|
+
*/
|
|
161
|
+
tablist: [newTablist: { header: { text: string, raw: TextComponent }, footer: { text: string, raw: TextComponent } }]
|
|
106
162
|
}
|
|
107
163
|
|
|
108
164
|
/**
|
|
109
165
|
* High-level client.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```ts
|
|
169
|
+
* const client = new Client({
|
|
170
|
+
* playerName: "bot", // Put your name here
|
|
171
|
+
* host: "localhost", // Put the server address
|
|
172
|
+
* port: 25565, // 25565 is the default port, change to your server's port if needed
|
|
173
|
+
* version: "26.2", // The client version
|
|
174
|
+
* loadRegistry: false, //
|
|
175
|
+
* // auth: { // This things is not working yet
|
|
176
|
+
* // client_id: "d86254d8-edf7-4640-90eb-643c99af188e",
|
|
177
|
+
* // method: "loopback",
|
|
178
|
+
* // openBrowser: true,
|
|
179
|
+
* // port: 12345
|
|
180
|
+
* // },
|
|
181
|
+
* // shouldVerifyMessageOrder: true,
|
|
182
|
+
* // shouldVerifyMessageSignature: true
|
|
183
|
+
* });
|
|
184
|
+
*
|
|
185
|
+
* // MineJs is a event driven library, the same way DiscordJS work (if you know them).
|
|
186
|
+
* // One thing to note is most of method in this client require client to be ready,
|
|
187
|
+
* // meaning that unless the "ready" event is fired, you can't do, mostly, anything :D
|
|
188
|
+
* client.on("ready", () => console.log("Client is ready :yay:"));
|
|
189
|
+
*
|
|
190
|
+
* // The init step before is just init the data and does not create the connection yet.
|
|
191
|
+
* // This method will create that connection.
|
|
192
|
+
* client.connect();
|
|
193
|
+
* ```
|
|
110
194
|
*/
|
|
111
|
-
export class Client
|
|
195
|
+
export class Client extends (EventEmitter as new () => TypedEmitter<ClientEvents>) {
|
|
112
196
|
private static loadRegistry: boolean = false;
|
|
113
197
|
|
|
114
198
|
private tickLoop: TickLoop;
|
|
@@ -118,7 +202,7 @@ export class Client<IsReady extends boolean = boolean> extends (EventEmitter as
|
|
|
118
202
|
private player: Player;
|
|
119
203
|
|
|
120
204
|
private tcp: TCPClient;
|
|
121
|
-
private state: SharedState
|
|
205
|
+
private state: SharedState;
|
|
122
206
|
private packetListener: Listener;
|
|
123
207
|
private packetSender: Sender;
|
|
124
208
|
|
|
@@ -127,6 +211,7 @@ export class Client<IsReady extends boolean = boolean> extends (EventEmitter as
|
|
|
127
211
|
throw new HaveSignatureButNotIndex();
|
|
128
212
|
|
|
129
213
|
super();
|
|
214
|
+
this.loadRegistries();
|
|
130
215
|
|
|
131
216
|
// For managing shared data
|
|
132
217
|
this.state = new SharedState(options);
|
|
@@ -182,7 +267,7 @@ export class Client<IsReady extends boolean = boolean> extends (EventEmitter as
|
|
|
182
267
|
this.tcp.on("destroy", () => this.emit("destroy"));
|
|
183
268
|
this.on("loadChunk", (sx, sy, sz) => this.blocks.deleteChunkCache(sx, sy, sz));
|
|
184
269
|
this.on("unloadChunk", (sx, sz) => {
|
|
185
|
-
for (let sy = 0; sy < 16; sy++)
|
|
270
|
+
for (let sy = 0; sy < 16; sy++)
|
|
186
271
|
this.blocks.deleteChunkCache(sx, sy, sz);
|
|
187
272
|
});
|
|
188
273
|
}
|
|
@@ -191,14 +276,14 @@ export class Client<IsReady extends boolean = boolean> extends (EventEmitter as
|
|
|
191
276
|
this.emit(event.event, ...event.args);
|
|
192
277
|
}
|
|
193
278
|
|
|
194
|
-
private
|
|
279
|
+
private loadRegistries() {
|
|
195
280
|
if (Client.loadRegistry) return;
|
|
196
281
|
Client.loadRegistry = true;
|
|
197
282
|
const { version } = this.options;
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
283
|
+
BlockRegistry.load(version);
|
|
284
|
+
EntityRegistry.load(version);
|
|
285
|
+
PacketRegistry.load(version);
|
|
286
|
+
EffectRegistry.load(version);
|
|
202
287
|
}
|
|
203
288
|
|
|
204
289
|
// Start / stop
|
|
@@ -207,7 +292,6 @@ export class Client<IsReady extends boolean = boolean> extends (EventEmitter as
|
|
|
207
292
|
* Create a connection to the server
|
|
208
293
|
*/
|
|
209
294
|
public async connect() {
|
|
210
|
-
await this.loadRegistries();
|
|
211
295
|
if (!this.state.playerUUID) {
|
|
212
296
|
if (this.options.auth) {
|
|
213
297
|
this.state.authClient = new AuthClient(this.options.auth);
|
|
@@ -231,7 +315,9 @@ export class Client<IsReady extends boolean = boolean> extends (EventEmitter as
|
|
|
231
315
|
});
|
|
232
316
|
}
|
|
233
317
|
/**
|
|
234
|
-
* Destroy the connection
|
|
318
|
+
* Destroy the connection.
|
|
319
|
+
*
|
|
320
|
+
* Calling this method will also fire the "disconnect" event.
|
|
235
321
|
*/
|
|
236
322
|
public disconnect(reason: string = "Disconnect", raw?: TextComponent) {
|
|
237
323
|
this.state.state = ConnectionState.Disconnected;
|
|
@@ -249,48 +335,162 @@ export class Client<IsReady extends boolean = boolean> extends (EventEmitter as
|
|
|
249
335
|
|
|
250
336
|
// Inputs
|
|
251
337
|
/**
|
|
252
|
-
* Press and hold a key
|
|
338
|
+
* Press and hold a key.
|
|
339
|
+
*
|
|
340
|
+
* This is pretty the same idea as when you play Minecraft.
|
|
341
|
+
* When you need to go forward, you have to hold the key `W`, `S` for backward, etc...
|
|
342
|
+
*
|
|
343
|
+
* @throws {ClientNotReady} When the client is not ready
|
|
253
344
|
*/
|
|
254
|
-
public hold(
|
|
255
|
-
this.
|
|
345
|
+
public hold(input: Input) {
|
|
346
|
+
this.state.checkReady();
|
|
347
|
+
this.player.input(input);
|
|
256
348
|
}
|
|
257
349
|
/**
|
|
258
|
-
* Release a key
|
|
350
|
+
* Release a key.
|
|
351
|
+
*
|
|
352
|
+
* This is also pretty the same idea as when you play Minecraft.
|
|
353
|
+
* Need to stop, stop holding `W`, `S` key, etc...
|
|
354
|
+
*
|
|
355
|
+
* @throws {ClientNotReady} When the client is not ready
|
|
259
356
|
*/
|
|
260
357
|
public release(input: Input) {
|
|
358
|
+
this.state.checkReady();
|
|
261
359
|
this.player.releaseInput(input);
|
|
262
360
|
}
|
|
263
361
|
/**
|
|
264
|
-
* Release all key
|
|
362
|
+
* Release all key.
|
|
363
|
+
*
|
|
364
|
+
* This is the shortcut for release all keys.
|
|
365
|
+
* Instead of calling `release` method for each keys, just call this
|
|
366
|
+
*
|
|
367
|
+
* @throws {ClientNotReady} When the client is not ready
|
|
265
368
|
*/
|
|
266
369
|
public stopMoving() {
|
|
370
|
+
this.state.checkReady();
|
|
267
371
|
this.player.releaseAllInputs();
|
|
268
372
|
}
|
|
269
373
|
|
|
270
374
|
/**
|
|
271
375
|
* Send a message
|
|
376
|
+
*
|
|
377
|
+
* @throws {ClientNotReady} When the client is not ready
|
|
272
378
|
*/
|
|
273
379
|
public chat(message: string) {
|
|
380
|
+
this.state.checkReady();
|
|
274
381
|
this.packetSender.sendMessage(message);
|
|
275
382
|
}
|
|
276
383
|
|
|
277
384
|
// World
|
|
278
385
|
/**
|
|
279
386
|
* Get the block state at position
|
|
387
|
+
*
|
|
388
|
+
* @throws {ClientNotReady} When the client is not ready
|
|
280
389
|
*/
|
|
281
|
-
public
|
|
282
|
-
public
|
|
283
|
-
public
|
|
390
|
+
public getBlock(x: number, y: number, z: number): BlockState | null;
|
|
391
|
+
public getBlock(position: BaseVec3): BlockState | null;
|
|
392
|
+
public getBlock(a: BaseVec3 | number, b?: number, c?: number): BlockState | null {
|
|
284
393
|
const vec3 = Vec3.loadArgs(a, b, c);
|
|
285
394
|
return this.blocks.at(vec3);
|
|
286
395
|
}
|
|
287
396
|
|
|
397
|
+
/**
|
|
398
|
+
* Get player position
|
|
399
|
+
*
|
|
400
|
+
* @throws {ClientNotReady} When the client is not ready
|
|
401
|
+
*/
|
|
402
|
+
public getPosition() {
|
|
403
|
+
this.state.checkReady();
|
|
404
|
+
return structuredClone(this.state.player!.position);
|
|
405
|
+
}
|
|
406
|
+
|
|
288
407
|
/**
|
|
289
408
|
* Rotate your face
|
|
409
|
+
*
|
|
410
|
+
* "Yaw is measured in degrees and does not follow classical trigonometry rules.
|
|
411
|
+
* 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).
|
|
412
|
+
*
|
|
413
|
+
* Pitch is measured in degrees, where 0 is looking straight ahead, -90 is looking straight up, and 90 is looking straight down."
|
|
414
|
+
*
|
|
415
|
+
* @see https://minecraft.wiki/w/Java_Edition_protocol/Packets#Synchronize_Player_Position For Yaw and Pitch definition
|
|
416
|
+
*
|
|
290
417
|
* @param yaw In degree
|
|
291
418
|
* @param pitch In degree
|
|
419
|
+
*
|
|
420
|
+
* @throws {ClientNotReady} When the client is not ready
|
|
292
421
|
*/
|
|
293
422
|
public lookAt(yaw: number, pitch: number) {
|
|
423
|
+
this.state.checkReady();
|
|
294
424
|
this.player.setAngle(yaw, pitch);
|
|
295
425
|
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Get opening container.
|
|
429
|
+
*
|
|
430
|
+
* Return `undefined` if nothing is opening
|
|
431
|
+
*
|
|
432
|
+
* @throws {ClientNotReady} When the client is not ready
|
|
433
|
+
*/
|
|
434
|
+
public getOpeningContainer() {
|
|
435
|
+
this.state.checkReady();
|
|
436
|
+
return this.state.openingContainer;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Get carrying item.
|
|
440
|
+
*
|
|
441
|
+
* Return `undefined` if nothing is carried
|
|
442
|
+
*
|
|
443
|
+
* @throws {ClientNotReady} When the client is not ready
|
|
444
|
+
*/
|
|
445
|
+
public getCarryingItem() {
|
|
446
|
+
this.state.checkReady();
|
|
447
|
+
return this.state.player?.carryingItem;
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Get player's inventory
|
|
451
|
+
*
|
|
452
|
+
* @throws {ClientNotReady} When the client is not ready
|
|
453
|
+
*/
|
|
454
|
+
public getInventory() {
|
|
455
|
+
this.state.checkReady();
|
|
456
|
+
return this.state.player?.inventory;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Open a block.
|
|
461
|
+
*
|
|
462
|
+
* @throws {ClientNotReady} When the client is not ready
|
|
463
|
+
* @returns `true` if the target block is a solid block, or else, return `false`
|
|
464
|
+
*/
|
|
465
|
+
public openBlock(x: number, y: number, z: number): boolean;
|
|
466
|
+
public openBlock(position: BaseVec3): boolean;
|
|
467
|
+
public openBlock(a: BaseVec3 | number, b?: number, c?: number): boolean {
|
|
468
|
+
this.state.checkReady();
|
|
469
|
+
const vec3 = Vec3.loadArgs(a, b, c);
|
|
470
|
+
const eyePos = new Vec3(this.state.player!.position).add(0, 1.62, 0);
|
|
471
|
+
const target = new Vec3(vec3).add(0.5, 0.5, 0.5); // aim at block center, or use look direction
|
|
472
|
+
const reach = 4.5; // survival reach, adjust as needed
|
|
473
|
+
const dir = target.subtract(eyePos).normalize();
|
|
474
|
+
const to = eyePos.add(dir.scale(reach));
|
|
475
|
+
const clipResult = BlockGetter.clip(
|
|
476
|
+
eyePos,
|
|
477
|
+
to,
|
|
478
|
+
(pos) => this.blocks.at(pos)!.shape
|
|
479
|
+
)!;
|
|
480
|
+
if (clipResult.miss) return false;
|
|
481
|
+
const cursorX = Math.abs(clipResult.location.x - clipResult.pos.x),
|
|
482
|
+
cursorY = Math.abs(clipResult.location.y - clipResult.pos.y),
|
|
483
|
+
cursorZ = Math.abs(clipResult.location.z - clipResult.pos.z);
|
|
484
|
+
if (cursorX > 1 || cursorY > 1 || cursorZ > 1)
|
|
485
|
+
return false;
|
|
486
|
+
this.packetSender.sendUseItemOn(
|
|
487
|
+
"main",
|
|
488
|
+
vec3,
|
|
489
|
+
clipResult.direction,
|
|
490
|
+
{ x: cursorX, y: cursorY, z: cursorZ },
|
|
491
|
+
false,
|
|
492
|
+
false
|
|
493
|
+
);
|
|
494
|
+
return true;
|
|
495
|
+
}
|
|
296
496
|
}
|
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
|
}
|
|
@@ -74,13 +78,6 @@ export class TCPClient extends (EventEmitter as new () => TypedEmmiter<TCPClient
|
|
|
74
78
|
public readonly socket: Socket;
|
|
75
79
|
|
|
76
80
|
// Internal var
|
|
77
|
-
/**
|
|
78
|
-
* | Value | Meaning |
|
|
79
|
-
* |-------|---------|
|
|
80
|
-
* | 0 | not set yet |
|
|
81
|
-
* | -1 | dont compress |
|
|
82
|
-
* | > 0 | compression threshold |
|
|
83
|
-
*/
|
|
84
81
|
private bufferPool: Buffer = Buffer.alloc(0);
|
|
85
82
|
|
|
86
83
|
constructor(
|
|
@@ -137,7 +134,7 @@ export class TCPClient extends (EventEmitter as new () => TypedEmmiter<TCPClient
|
|
|
137
134
|
|
|
138
135
|
private handlePacket() {
|
|
139
136
|
while (this.bufferPool.length > 0) {
|
|
140
|
-
|
|
137
|
+
const decoder = new BinaryDecoder(this.bufferPool);
|
|
141
138
|
let packetLength: number;
|
|
142
139
|
try {
|
|
143
140
|
packetLength = decoder.readVarInt();
|
|
@@ -149,27 +146,35 @@ export class TCPClient extends (EventEmitter as new () => TypedEmmiter<TCPClient
|
|
|
149
146
|
const expectedPacketEnd = decoder.offset + packetLength;
|
|
150
147
|
|
|
151
148
|
let packetID: number;
|
|
149
|
+
let packetDecoder = new BinaryDecoder(decoder.buffer.subarray(decoder.offset, expectedPacketEnd));
|
|
152
150
|
if (this.state.compressionThreshold === 0)
|
|
153
|
-
packetID =
|
|
151
|
+
packetID = packetDecoder.readVarInt();
|
|
154
152
|
else if (this.state.compressionThreshold === -1) {
|
|
155
|
-
|
|
156
|
-
packetID =
|
|
153
|
+
packetDecoder.readVarInt();
|
|
154
|
+
packetID = packetDecoder.readVarInt();
|
|
157
155
|
} else {
|
|
158
|
-
const dataLength =
|
|
156
|
+
const dataLength = packetDecoder.readVarInt();
|
|
159
157
|
if (dataLength === 0) {
|
|
160
|
-
packetID =
|
|
158
|
+
packetID = packetDecoder.readVarInt();
|
|
161
159
|
} else {
|
|
162
|
-
const dataBuffer =
|
|
160
|
+
const dataBuffer = packetDecoder.buffer.subarray(packetDecoder.offset);
|
|
163
161
|
const decompressed = inflateSync(dataBuffer);
|
|
164
162
|
if (decompressed.length !== dataLength)
|
|
165
163
|
throw new UnexpectedValue("decompressed packet data", decompressed.length.toString(), dataLength.toString());
|
|
166
|
-
|
|
167
|
-
packetID =
|
|
164
|
+
packetDecoder = new BinaryDecoder(decompressed);
|
|
165
|
+
packetID = packetDecoder.readVarInt();
|
|
168
166
|
}
|
|
169
167
|
}
|
|
170
|
-
if (
|
|
171
|
-
|
|
172
|
-
|
|
168
|
+
if (
|
|
169
|
+
this.state.clientOptions.debug &&
|
|
170
|
+
this.state.clientOptions.debug.packetLogger &&
|
|
171
|
+
(
|
|
172
|
+
(Array.isArray(this.state.clientOptions.debug.ignoreTCPPacketLogs) && !this.state.clientOptions.debug.ignoreTCPPacketLogs.includes(packetID)) ||
|
|
173
|
+
(!this.state.clientOptions.debug.ignoreTCPPacketLogs)
|
|
174
|
+
)
|
|
175
|
+
)
|
|
176
|
+
console.log("packet", packetID, "length", packetDecoder.buffer.length);
|
|
177
|
+
this.forwardPacket(packetID, packetDecoder);
|
|
173
178
|
|
|
174
179
|
this.bufferPool = this.bufferPool.subarray(expectedPacketEnd);
|
|
175
180
|
}
|