specprotocol 1.4.4 → 1.4.5
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 +66 -174
- package/dist/bot.d.ts +13 -2
- package/dist/bot.d.ts.map +1 -1
- package/dist/bot.js +281 -113
- package/dist/bot.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/protocol/states/handshake.d.ts +2 -2
- package/dist/protocol/states/handshake.d.ts.map +1 -1
- package/dist/protocol/states/handshake.js +3 -2
- package/dist/protocol/states/handshake.js.map +1 -1
- package/dist/protocol/states/login.d.ts +3 -3
- package/dist/protocol/states/login.d.ts.map +1 -1
- package/dist/protocol/states/login.js +27 -9
- package/dist/protocol/states/login.js.map +1 -1
- package/dist/protocol/states/play.d.ts +14 -14
- package/dist/protocol/states/play.d.ts.map +1 -1
- package/dist/protocol/states/play.js +244 -54
- package/dist/protocol/states/play.js.map +1 -1
- package/dist/protocol/version.d.ts +23 -0
- package/dist/protocol/version.d.ts.map +1 -0
- package/dist/protocol/version.js +137 -0
- package/dist/protocol/version.js.map +1 -0
- package/docs/README.md +1 -1
- package/docs/api/protocol.md +1 -1
- package/docs/getting-started.md +1 -1
- package/docs/guides/architecture.md +1 -1
- package/package.json +7 -7
package/dist/bot.js
CHANGED
|
@@ -27,6 +27,7 @@ const encryption_js_1 = require("./protocol/encryption.js");
|
|
|
27
27
|
const handshake_js_1 = require("./protocol/states/handshake.js");
|
|
28
28
|
const login_js_1 = require("./protocol/states/login.js");
|
|
29
29
|
const play_js_1 = require("./protocol/states/play.js");
|
|
30
|
+
const version_js_1 = require("./protocol/version.js");
|
|
30
31
|
// World & Entity
|
|
31
32
|
const world_js_1 = require("./world/world.js");
|
|
32
33
|
const entity_js_1 = require("./entity/entity.js");
|
|
@@ -42,6 +43,7 @@ const block_finder_js_1 = require("./block-finder.js");
|
|
|
42
43
|
const plugin_manager_js_1 = require("./plugins/plugin-manager.js");
|
|
43
44
|
const chat_js_2 = require("./plugins/built-in/chat.js");
|
|
44
45
|
const combat_js_1 = require("./plugins/built-in/combat.js");
|
|
46
|
+
const MISSING_PACKET_ID = -1;
|
|
45
47
|
// ─── Bot Class ──────────────────────────────────────────
|
|
46
48
|
class Bot extends events_js_1.TypedEventEmitter {
|
|
47
49
|
// Connection
|
|
@@ -85,6 +87,13 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
85
87
|
weather;
|
|
86
88
|
// Config
|
|
87
89
|
options;
|
|
90
|
+
protocolInfo;
|
|
91
|
+
loginClientIds;
|
|
92
|
+
loginServerIds;
|
|
93
|
+
configurationClientIds;
|
|
94
|
+
configurationServerIds;
|
|
95
|
+
playClientIds;
|
|
96
|
+
playServerIds;
|
|
88
97
|
// Packet handlers for play state
|
|
89
98
|
packetHandlers = new Map();
|
|
90
99
|
playPacketListener = null;
|
|
@@ -97,15 +106,111 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
97
106
|
};
|
|
98
107
|
constructor(options) {
|
|
99
108
|
super();
|
|
109
|
+
this.protocolInfo = (0, version_js_1.resolveProtocolInfo)(options.version ?? handshake_js_1.PROTOCOL_VERSION);
|
|
100
110
|
this.options = {
|
|
101
111
|
host: options.host,
|
|
102
112
|
port: options.port ?? 25565,
|
|
103
|
-
version:
|
|
113
|
+
version: this.protocolInfo.protocolVersion,
|
|
104
114
|
viewDistance: options.viewDistance ?? 10,
|
|
105
115
|
};
|
|
106
116
|
this.authMode = options.auth ?? 'offline';
|
|
107
117
|
this._username = options.username;
|
|
108
118
|
this.logger = new logger_js_1.Logger('Bot', options.logLevel ?? logger_js_1.LogLevel.INFO);
|
|
119
|
+
this.logger.info(`Using protocol ${this.protocolInfo.protocolVersion} (${this.protocolInfo.minecraftVersion})`);
|
|
120
|
+
const missing = MISSING_PACKET_ID;
|
|
121
|
+
const loginToClient = this.protocolInfo.packetMappings.login.toClient;
|
|
122
|
+
const loginToServer = this.protocolInfo.packetMappings.login.toServer;
|
|
123
|
+
const configToClient = this.protocolInfo.packetMappings.configuration?.toClient ?? {};
|
|
124
|
+
const configToServer = this.protocolInfo.packetMappings.configuration?.toServer ?? {};
|
|
125
|
+
const playToClient = this.protocolInfo.packetMappings.play.toClient;
|
|
126
|
+
const playToServer = this.protocolInfo.packetMappings.play.toServer;
|
|
127
|
+
this.loginClientIds = {
|
|
128
|
+
disconnect: (0, version_js_1.resolvePacketId)(loginToClient, ['disconnect']) ?? missing,
|
|
129
|
+
encryptionBegin: (0, version_js_1.resolvePacketId)(loginToClient, ['encryption_begin']) ?? missing,
|
|
130
|
+
success: (0, version_js_1.resolvePacketId)(loginToClient, ['success']) ?? missing,
|
|
131
|
+
compress: (0, version_js_1.resolvePacketId)(loginToClient, ['compress']) ?? missing,
|
|
132
|
+
loginPluginRequest: (0, version_js_1.resolvePacketId)(loginToClient, ['login_plugin_request']) ?? missing,
|
|
133
|
+
};
|
|
134
|
+
this.loginServerIds = {
|
|
135
|
+
loginStart: (0, version_js_1.resolvePacketId)(loginToServer, ['login_start']) ?? missing,
|
|
136
|
+
encryptionBegin: (0, version_js_1.resolvePacketId)(loginToServer, ['encryption_begin']) ?? missing,
|
|
137
|
+
loginPluginResponse: (0, version_js_1.resolvePacketId)(loginToServer, ['login_plugin_response']) ?? missing,
|
|
138
|
+
loginAcknowledged: (0, version_js_1.resolvePacketId)(loginToServer, ['login_acknowledged']) ?? missing,
|
|
139
|
+
};
|
|
140
|
+
this.configurationClientIds = {
|
|
141
|
+
disconnect: (0, version_js_1.resolvePacketId)(configToClient, ['disconnect']) ?? missing,
|
|
142
|
+
finishConfiguration: (0, version_js_1.resolvePacketId)(configToClient, ['finish_configuration']) ?? missing,
|
|
143
|
+
keepAlive: (0, version_js_1.resolvePacketId)(configToClient, ['keep_alive']) ?? missing,
|
|
144
|
+
ping: (0, version_js_1.resolvePacketId)(configToClient, ['ping']) ?? missing,
|
|
145
|
+
customPayload: (0, version_js_1.resolvePacketId)(configToClient, ['custom_payload']) ?? missing,
|
|
146
|
+
registryData: (0, version_js_1.resolvePacketId)(configToClient, ['registry_data']) ?? missing,
|
|
147
|
+
featureFlags: (0, version_js_1.resolvePacketId)(configToClient, ['feature_flags']) ?? missing,
|
|
148
|
+
tags: (0, version_js_1.resolvePacketId)(configToClient, ['tags']) ?? missing,
|
|
149
|
+
selectKnownPacks: (0, version_js_1.resolvePacketId)(configToClient, ['select_known_packs']) ?? missing,
|
|
150
|
+
cookieRequest: (0, version_js_1.resolvePacketId)(configToClient, ['cookie_request']) ?? missing,
|
|
151
|
+
addResourcePack: (0, version_js_1.resolvePacketId)(configToClient, ['add_resource_pack', 'resource_pack_send']) ?? missing,
|
|
152
|
+
serverLinks: (0, version_js_1.resolvePacketId)(configToClient, ['server_links']) ?? missing,
|
|
153
|
+
};
|
|
154
|
+
this.configurationServerIds = {
|
|
155
|
+
finishConfiguration: (0, version_js_1.resolvePacketId)(configToServer, ['finish_configuration']) ?? missing,
|
|
156
|
+
keepAlive: (0, version_js_1.resolvePacketId)(configToServer, ['keep_alive']) ?? missing,
|
|
157
|
+
pong: (0, version_js_1.resolvePacketId)(configToServer, ['pong']) ?? missing,
|
|
158
|
+
selectKnownPacks: (0, version_js_1.resolvePacketId)(configToServer, ['select_known_packs']) ?? missing,
|
|
159
|
+
};
|
|
160
|
+
this.playClientIds = {
|
|
161
|
+
keepAlive: (0, version_js_1.resolvePacketId)(playToClient, ['keep_alive']) ?? missing,
|
|
162
|
+
chunkBatchFinished: (0, version_js_1.resolvePacketId)(playToClient, ['chunk_batch_finished']) ?? missing,
|
|
163
|
+
login: (0, version_js_1.resolvePacketId)(playToClient, ['login']) ?? missing,
|
|
164
|
+
position: (0, version_js_1.resolvePacketId)(playToClient, ['position']) ?? missing,
|
|
165
|
+
updateHealth: (0, version_js_1.resolvePacketId)(playToClient, ['update_health']) ?? missing,
|
|
166
|
+
blockChange: (0, version_js_1.resolvePacketId)(playToClient, ['block_change']) ?? missing,
|
|
167
|
+
bossBar: (0, version_js_1.resolvePacketId)(playToClient, ['boss_bar']) ?? missing,
|
|
168
|
+
spawnEntity: (0, version_js_1.resolvePacketId)(playToClient, ['spawn_entity']) ?? missing,
|
|
169
|
+
entityDestroy: (0, version_js_1.resolvePacketId)(playToClient, ['entity_destroy']) ?? missing,
|
|
170
|
+
relEntityMove: (0, version_js_1.resolvePacketId)(playToClient, ['rel_entity_move']) ?? missing,
|
|
171
|
+
entityMoveLook: (0, version_js_1.resolvePacketId)(playToClient, ['entity_move_look']) ?? missing,
|
|
172
|
+
entityVelocity: (0, version_js_1.resolvePacketId)(playToClient, ['entity_velocity']) ?? missing,
|
|
173
|
+
entityHeadRotation: (0, version_js_1.resolvePacketId)(playToClient, ['entity_head_rotation']) ?? missing,
|
|
174
|
+
gameStateChange: (0, version_js_1.resolvePacketId)(playToClient, ['game_state_change']) ?? missing,
|
|
175
|
+
respawn: (0, version_js_1.resolvePacketId)(playToClient, ['respawn']) ?? missing,
|
|
176
|
+
experience: (0, version_js_1.resolvePacketId)(playToClient, ['experience']) ?? missing,
|
|
177
|
+
updateTime: (0, version_js_1.resolvePacketId)(playToClient, ['update_time']) ?? missing,
|
|
178
|
+
spawnPosition: (0, version_js_1.resolvePacketId)(playToClient, ['spawn_position']) ?? missing,
|
|
179
|
+
openWindow: (0, version_js_1.resolvePacketId)(playToClient, ['open_window']) ?? missing,
|
|
180
|
+
windowItems: (0, version_js_1.resolvePacketId)(playToClient, ['window_items']) ?? missing,
|
|
181
|
+
setSlot: (0, version_js_1.resolvePacketId)(playToClient, ['set_slot']) ?? missing,
|
|
182
|
+
closeWindow: (0, version_js_1.resolvePacketId)(playToClient, ['close_window']) ?? missing,
|
|
183
|
+
ping: (0, version_js_1.resolvePacketId)(playToClient, ['ping']) ?? missing,
|
|
184
|
+
acknowledgePlayerDigging: (0, version_js_1.resolvePacketId)(playToClient, ['acknowledge_player_digging']) ?? missing,
|
|
185
|
+
disconnect: (0, version_js_1.resolvePacketId)(playToClient, ['kick_disconnect']) ?? missing,
|
|
186
|
+
abilities: (0, version_js_1.resolvePacketId)(playToClient, ['abilities']) ?? missing,
|
|
187
|
+
systemChat: (0, version_js_1.resolvePacketId)(playToClient, ['system_chat']) ?? missing,
|
|
188
|
+
profilelessChat: (0, version_js_1.resolvePacketId)(playToClient, ['profileless_chat']) ?? missing,
|
|
189
|
+
legacyChat: (0, version_js_1.resolvePacketId)(playToClient, ['chat']) ?? missing,
|
|
190
|
+
};
|
|
191
|
+
this.playServerIds = {
|
|
192
|
+
keepAlive: (0, version_js_1.resolvePacketId)(playToServer, ['keep_alive']) ?? missing,
|
|
193
|
+
chunkBatchReceived: (0, version_js_1.resolvePacketId)(playToServer, ['chunk_batch_received']) ?? missing,
|
|
194
|
+
teleportConfirm: (0, version_js_1.resolvePacketId)(playToServer, ['teleport_confirm']) ?? missing,
|
|
195
|
+
position: (0, version_js_1.resolvePacketId)(playToServer, ['position']) ?? missing,
|
|
196
|
+
positionLook: (0, version_js_1.resolvePacketId)(playToServer, ['position_look']) ?? missing,
|
|
197
|
+
look: (0, version_js_1.resolvePacketId)(playToServer, ['look']) ?? missing,
|
|
198
|
+
flying: (0, version_js_1.resolvePacketId)(playToServer, ['flying']) ?? missing,
|
|
199
|
+
chat: (0, version_js_1.resolvePacketId)(playToServer, ['chat']) ?? missing,
|
|
200
|
+
chatMessage: (0, version_js_1.resolvePacketId)(playToServer, ['chat_message']) ?? missing,
|
|
201
|
+
chatCommand: (0, version_js_1.resolvePacketId)(playToServer, ['chat_command']) ?? missing,
|
|
202
|
+
useEntity: (0, version_js_1.resolvePacketId)(playToServer, ['use_entity']) ?? missing,
|
|
203
|
+
armAnimation: (0, version_js_1.resolvePacketId)(playToServer, ['arm_animation']) ?? missing,
|
|
204
|
+
entityAction: (0, version_js_1.resolvePacketId)(playToServer, ['entity_action']) ?? missing,
|
|
205
|
+
blockDig: (0, version_js_1.resolvePacketId)(playToServer, ['block_dig']) ?? missing,
|
|
206
|
+
blockPlace: (0, version_js_1.resolvePacketId)(playToServer, ['block_place']) ?? missing,
|
|
207
|
+
useItem: (0, version_js_1.resolvePacketId)(playToServer, ['use_item']) ?? missing,
|
|
208
|
+
heldItemSlot: (0, version_js_1.resolvePacketId)(playToServer, ['held_item_slot']) ?? missing,
|
|
209
|
+
abilities: (0, version_js_1.resolvePacketId)(playToServer, ['abilities']) ?? missing,
|
|
210
|
+
clientCommand: (0, version_js_1.resolvePacketId)(playToServer, ['client_command']) ?? missing,
|
|
211
|
+
closeWindow: (0, version_js_1.resolvePacketId)(playToServer, ['close_window']) ?? missing,
|
|
212
|
+
pong: (0, version_js_1.resolvePacketId)(playToServer, ['pong']) ?? missing,
|
|
213
|
+
};
|
|
109
214
|
// Initialize subsystems
|
|
110
215
|
this.world = new world_js_1.World();
|
|
111
216
|
this.entities = new entity_js_1.EntityManager();
|
|
@@ -151,6 +256,20 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
151
256
|
get gameMode() { return this._gameMode; }
|
|
152
257
|
get isAlive() { return this._isAlive; }
|
|
153
258
|
get position() { return this.entity.position; }
|
|
259
|
+
requirePacketId(packetId, packetName) {
|
|
260
|
+
if (packetId === MISSING_PACKET_ID) {
|
|
261
|
+
throw new Error(`Packet '${packetName}' is unavailable for protocol ${this.options.version} (${this.protocolInfo.minecraftVersion})`);
|
|
262
|
+
}
|
|
263
|
+
return packetId;
|
|
264
|
+
}
|
|
265
|
+
sendPlayPacket(packetId, data, packetName) {
|
|
266
|
+
this.connection.sendPacket(this.requirePacketId(packetId, packetName), data);
|
|
267
|
+
}
|
|
268
|
+
emitChatFromComponent(rawContent, isOverlay) {
|
|
269
|
+
const message = chat_js_1.ChatMessage.parse(rawContent);
|
|
270
|
+
this.emit('chatMessage', message, isOverlay);
|
|
271
|
+
this.emit('chat', message.toString(), isOverlay);
|
|
272
|
+
}
|
|
154
273
|
// ─── Connect & Login ────────────────────────────────
|
|
155
274
|
/**
|
|
156
275
|
* Connect to the server and begin the login process.
|
|
@@ -191,7 +310,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
191
310
|
}
|
|
192
311
|
// Step 3: Send Login Start
|
|
193
312
|
this.logger.info(`Logging in as ${this._username} (${uuid})...`);
|
|
194
|
-
this.connection.sendPacket(
|
|
313
|
+
this.connection.sendPacket(this.requirePacketId(this.loginServerIds.loginStart, 'login_start'), (0, login_js_1.buildLoginStartPacket)(this._username, uuid, this.options.version));
|
|
195
314
|
// Step 4: Handle login response packets
|
|
196
315
|
await this.handleLoginSequence();
|
|
197
316
|
}
|
|
@@ -232,54 +351,64 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
232
351
|
}
|
|
233
352
|
async handleLoginPacket(packet, onComplete) {
|
|
234
353
|
switch (packet.id) {
|
|
235
|
-
case
|
|
354
|
+
case this.loginClientIds.encryptionBegin: {
|
|
236
355
|
await this.handleEncryptionRequest(packet.data);
|
|
237
356
|
break;
|
|
238
357
|
}
|
|
239
|
-
case
|
|
358
|
+
case this.loginClientIds.compress: {
|
|
240
359
|
const { threshold } = (0, login_js_1.parseSetCompressionPacket)(packet.data);
|
|
241
360
|
this.connection.enableCompression(threshold);
|
|
242
361
|
this.logger.info(`Compression enabled (threshold: ${threshold})`);
|
|
243
362
|
break;
|
|
244
363
|
}
|
|
245
|
-
case
|
|
246
|
-
const success = (0, login_js_1.parseLoginSuccessPacket)(packet.data);
|
|
364
|
+
case this.loginClientIds.success: {
|
|
365
|
+
const success = (0, login_js_1.parseLoginSuccessPacket)(packet.data, this.options.version);
|
|
247
366
|
this._username = success.username;
|
|
248
367
|
this._uuid = success.uuid;
|
|
249
368
|
this.logger.info(`Login successful! ${success.username} (${success.uuid})`);
|
|
250
369
|
// Send Login Acknowledged
|
|
251
|
-
this.
|
|
370
|
+
if (this.loginServerIds.loginAcknowledged !== MISSING_PACKET_ID) {
|
|
371
|
+
this.connection.sendPacket(this.loginServerIds.loginAcknowledged, (0, login_js_1.buildLoginAcknowledgedPacket)());
|
|
372
|
+
}
|
|
252
373
|
// Remove login handler FIRST, then enter Configuration state
|
|
253
374
|
onComplete();
|
|
254
375
|
// Enter Configuration state — handle config packets before Play
|
|
255
|
-
this.
|
|
376
|
+
if (this.protocolInfo.supportsConfigurationState) {
|
|
377
|
+
this.handleConfigurationState().then(() => {
|
|
378
|
+
this.setupPlayStateHandlers();
|
|
379
|
+
this.emit('login');
|
|
380
|
+
}).catch((err) => {
|
|
381
|
+
this.logger.error('Configuration state failed:', err);
|
|
382
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
383
|
+
this.emit('error', error);
|
|
384
|
+
this.disconnect();
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
256
388
|
this.setupPlayStateHandlers();
|
|
257
389
|
this.emit('login');
|
|
258
|
-
}
|
|
259
|
-
this.logger.error('Configuration state failed:', err);
|
|
260
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
261
|
-
this.emit('error', error);
|
|
262
|
-
this.disconnect();
|
|
263
|
-
});
|
|
390
|
+
}
|
|
264
391
|
break;
|
|
265
392
|
}
|
|
266
|
-
case
|
|
393
|
+
case this.loginClientIds.disconnect: {
|
|
267
394
|
const { reason } = (0, login_js_1.parseDisconnectPacket)(packet.data);
|
|
268
395
|
this.logger.error(`Disconnected during login: ${reason}`);
|
|
269
396
|
this.emit('kicked', reason);
|
|
270
397
|
throw new Error(`Disconnected during login: ${reason}`);
|
|
271
398
|
}
|
|
272
|
-
case
|
|
399
|
+
case this.loginClientIds.loginPluginRequest: {
|
|
273
400
|
const pluginReq = (0, login_js_1.parseLoginPluginRequestPacket)(packet.data);
|
|
274
401
|
this.logger.debug(`Login plugin request: ${pluginReq.channel}`);
|
|
275
402
|
// Respond with "not understood"
|
|
276
|
-
this.
|
|
403
|
+
if (this.loginServerIds.loginPluginResponse !== MISSING_PACKET_ID) {
|
|
404
|
+
this.connection.sendPacket(this.loginServerIds.loginPluginResponse, (0, login_js_1.buildLoginPluginResponsePacket)(pluginReq.messageId));
|
|
405
|
+
}
|
|
277
406
|
break;
|
|
278
407
|
}
|
|
279
408
|
}
|
|
280
409
|
}
|
|
281
410
|
async handleEncryptionRequest(data) {
|
|
282
|
-
const request = (0, login_js_1.parseEncryptionRequestPacket)(data);
|
|
411
|
+
const request = (0, login_js_1.parseEncryptionRequestPacket)(data, this.options.version);
|
|
283
412
|
this.logger.info('Handling encryption...');
|
|
284
413
|
// Generate shared secret
|
|
285
414
|
const sharedSecret = (0, encryption_js_1.generateSharedSecret)();
|
|
@@ -294,7 +423,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
294
423
|
const serverHash = (0, encryption_js_1.computeServerHash)(request.serverId, sharedSecret, request.publicKey);
|
|
295
424
|
await (0, microsoft_js_1.joinServer)(this.accessToken, this._uuid, serverHash);
|
|
296
425
|
}
|
|
297
|
-
this.connection.sendPacket(
|
|
426
|
+
this.connection.sendPacket(this.requirePacketId(this.loginServerIds.encryptionBegin, 'encryption_begin'), (0, login_js_1.buildEncryptionResponsePacket)(encryptedSecret, encryptedToken));
|
|
298
427
|
this.connection.enableEncryption(sharedSecret);
|
|
299
428
|
}
|
|
300
429
|
// ─── Configuration State ────────────────────────────
|
|
@@ -303,7 +432,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
303
432
|
* In 1.20.2+, the server sends registry data, feature flags, etc. before Play.
|
|
304
433
|
* When the server sends Finish Configuration (0x03), we transition to Play.
|
|
305
434
|
*
|
|
306
|
-
*
|
|
435
|
+
* Example configuration clientbound packet IDs (latest protocol):
|
|
307
436
|
* 0x00 = Cookie Request
|
|
308
437
|
* 0x01 = Plugin Message
|
|
309
438
|
* 0x02 = Disconnect
|
|
@@ -341,76 +470,76 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
341
470
|
};
|
|
342
471
|
const configHandler = (packet) => {
|
|
343
472
|
switch (packet.id) {
|
|
344
|
-
case
|
|
473
|
+
case this.configurationClientIds.finishConfiguration: {
|
|
345
474
|
// Finish Configuration (clientbound)
|
|
346
475
|
this.logger.info('Configuration complete, entering Play state...');
|
|
347
|
-
// Send Acknowledge Finish Configuration (serverbound
|
|
348
|
-
this.connection.sendPacket(
|
|
476
|
+
// Send Acknowledge Finish Configuration (serverbound)
|
|
477
|
+
this.connection.sendPacket(this.requirePacketId(this.configurationServerIds.finishConfiguration, 'finish_configuration'), Buffer.alloc(0));
|
|
349
478
|
finish(resolve);
|
|
350
479
|
break;
|
|
351
480
|
}
|
|
352
|
-
case
|
|
481
|
+
case this.configurationClientIds.keepAlive: {
|
|
353
482
|
// Keep Alive (clientbound) — must respond or get kicked
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
// Respond with same keep alive ID (serverbound 0x04)
|
|
358
|
-
const kaWriter = new types_js_1.BufferWriter();
|
|
359
|
-
kaWriter.writeLong(keepAliveId);
|
|
360
|
-
this.connection.sendPacket(0x04, kaWriter.toBuffer());
|
|
483
|
+
if (this.configurationServerIds.keepAlive !== MISSING_PACKET_ID) {
|
|
484
|
+
this.connection.sendPacket(this.configurationServerIds.keepAlive, packet.data);
|
|
485
|
+
}
|
|
361
486
|
break;
|
|
362
487
|
}
|
|
363
|
-
case
|
|
488
|
+
case this.configurationClientIds.customPayload: {
|
|
364
489
|
// Plugin Message (clientbound) — ignore
|
|
365
490
|
this.logger.debug('Config: Plugin message received');
|
|
366
491
|
break;
|
|
367
492
|
}
|
|
368
|
-
case
|
|
493
|
+
case this.configurationClientIds.registryData: {
|
|
369
494
|
// Registry Data — ignore (we don't track registry data yet)
|
|
370
495
|
this.logger.debug('Config: Registry data received');
|
|
371
496
|
break;
|
|
372
497
|
}
|
|
373
|
-
case
|
|
498
|
+
case this.configurationClientIds.featureFlags: {
|
|
374
499
|
// Feature Flags — ignore
|
|
375
500
|
this.logger.debug('Config: Feature flags received');
|
|
376
501
|
break;
|
|
377
502
|
}
|
|
378
|
-
case
|
|
503
|
+
case this.configurationClientIds.tags: {
|
|
379
504
|
// Update Tags — ignore
|
|
380
505
|
this.logger.debug('Config: Tags update received');
|
|
381
506
|
break;
|
|
382
507
|
}
|
|
383
|
-
case
|
|
508
|
+
case this.configurationClientIds.selectKnownPacks: {
|
|
384
509
|
// Known Packs (clientbound) — respond with empty known packs
|
|
385
510
|
this.logger.debug('Config: Known packs request');
|
|
386
511
|
// Send Known Packs response (serverbound 0x07) — empty
|
|
387
512
|
const knownPacksWriter = new types_js_1.BufferWriter();
|
|
388
513
|
knownPacksWriter.writeVarInt(0); // 0 known packs
|
|
389
|
-
this.
|
|
514
|
+
if (this.configurationServerIds.selectKnownPacks !== MISSING_PACKET_ID) {
|
|
515
|
+
this.connection.sendPacket(this.configurationServerIds.selectKnownPacks, knownPacksWriter.toBuffer());
|
|
516
|
+
}
|
|
390
517
|
break;
|
|
391
518
|
}
|
|
392
|
-
case
|
|
519
|
+
case this.configurationClientIds.ping: {
|
|
393
520
|
// Ping — respond with pong
|
|
394
521
|
this.logger.debug('Config: Ping received');
|
|
395
|
-
this.
|
|
522
|
+
if (this.configurationServerIds.pong !== MISSING_PACKET_ID) {
|
|
523
|
+
this.connection.sendPacket(this.configurationServerIds.pong, packet.data);
|
|
524
|
+
}
|
|
396
525
|
break;
|
|
397
526
|
}
|
|
398
|
-
case
|
|
527
|
+
case this.configurationClientIds.cookieRequest: {
|
|
399
528
|
// Cookie Request — ignore
|
|
400
529
|
this.logger.debug('Config: Cookie request');
|
|
401
530
|
break;
|
|
402
531
|
}
|
|
403
|
-
case
|
|
532
|
+
case this.configurationClientIds.addResourcePack: {
|
|
404
533
|
// Add Resource Pack — respond with accepted (status 3 = accepted)
|
|
405
534
|
this.logger.debug('Config: Resource pack request');
|
|
406
535
|
break;
|
|
407
536
|
}
|
|
408
|
-
case
|
|
537
|
+
case this.configurationClientIds.serverLinks: {
|
|
409
538
|
// Server Links — ignore
|
|
410
539
|
this.logger.debug('Config: Server links received');
|
|
411
540
|
break;
|
|
412
541
|
}
|
|
413
|
-
case
|
|
542
|
+
case this.configurationClientIds.disconnect: {
|
|
414
543
|
// Disconnect
|
|
415
544
|
const reader = new types_js_1.BufferReader(packet.data);
|
|
416
545
|
const reason = reader.readString();
|
|
@@ -453,21 +582,25 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
453
582
|
}
|
|
454
583
|
handlePlayPacket(packet) {
|
|
455
584
|
switch (packet.id) {
|
|
456
|
-
case
|
|
457
|
-
|
|
458
|
-
|
|
585
|
+
case this.playClientIds.keepAlive: {
|
|
586
|
+
if (this.playServerIds.keepAlive !== MISSING_PACKET_ID) {
|
|
587
|
+
// Keep alive payload type changes by protocol; echo raw payload safely.
|
|
588
|
+
this.connection.sendPacket(this.playServerIds.keepAlive, packet.data);
|
|
589
|
+
}
|
|
459
590
|
break;
|
|
460
591
|
}
|
|
461
|
-
case
|
|
592
|
+
case this.playClientIds.chunkBatchFinished: {
|
|
462
593
|
// Must respond with chunk_batch_received or server kicks
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
594
|
+
if (this.playServerIds.chunkBatchReceived !== MISSING_PACKET_ID) {
|
|
595
|
+
const writer = new types_js_1.BufferWriter();
|
|
596
|
+
writer.writeFloat(20.0); // chunks per tick
|
|
597
|
+
this.connection.sendPacket(this.playServerIds.chunkBatchReceived, writer.toBuffer());
|
|
598
|
+
}
|
|
466
599
|
break;
|
|
467
600
|
}
|
|
468
|
-
case
|
|
601
|
+
case this.playClientIds.login: {
|
|
469
602
|
try {
|
|
470
|
-
const login = (0, play_js_1.parseLoginPlay)(packet.data);
|
|
603
|
+
const login = (0, play_js_1.parseLoginPlay)(packet.data, this.options.version);
|
|
471
604
|
this._entityId = login.entityId;
|
|
472
605
|
this._gameMode = login.gameMode;
|
|
473
606
|
this.entity.id = login.entityId;
|
|
@@ -483,9 +616,9 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
483
616
|
}
|
|
484
617
|
break;
|
|
485
618
|
}
|
|
486
|
-
case
|
|
619
|
+
case this.playClientIds.position: {
|
|
487
620
|
try {
|
|
488
|
-
const pos = (0, play_js_1.parsePlayerPosition)(packet.data);
|
|
621
|
+
const pos = (0, play_js_1.parsePlayerPosition)(packet.data, this.options.version);
|
|
489
622
|
// Apply relative/absolute position based on flags
|
|
490
623
|
const flags = pos.flags;
|
|
491
624
|
const x = (flags & 0x01) ? this.entity.position.x + pos.x : pos.x;
|
|
@@ -495,7 +628,10 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
495
628
|
this.entity.yaw = pos.yaw;
|
|
496
629
|
this.entity.pitch = pos.pitch;
|
|
497
630
|
// Must confirm teleportation
|
|
498
|
-
this.
|
|
631
|
+
if (this.playServerIds.teleportConfirm !== MISSING_PACKET_ID &&
|
|
632
|
+
pos.teleportId >= 0) {
|
|
633
|
+
this.connection.sendPacket(this.playServerIds.teleportConfirm, (0, play_js_1.buildConfirmTeleportationPacket)(pos.teleportId));
|
|
634
|
+
}
|
|
499
635
|
this.emit('position', this.entity.position);
|
|
500
636
|
}
|
|
501
637
|
catch (err) {
|
|
@@ -503,7 +639,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
503
639
|
}
|
|
504
640
|
break;
|
|
505
641
|
}
|
|
506
|
-
case
|
|
642
|
+
case this.playClientIds.updateHealth: {
|
|
507
643
|
const { health, food, saturation } = (0, play_js_1.parseSetHealth)(packet.data);
|
|
508
644
|
this._health = health;
|
|
509
645
|
this._food = food;
|
|
@@ -524,7 +660,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
524
660
|
}
|
|
525
661
|
break;
|
|
526
662
|
}
|
|
527
|
-
case
|
|
663
|
+
case this.playClientIds.blockChange: {
|
|
528
664
|
try {
|
|
529
665
|
const update = (0, play_js_1.parseBlockUpdate)(packet.data);
|
|
530
666
|
this.world.setBlock(update.x, update.y, update.z, update.blockId);
|
|
@@ -535,7 +671,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
535
671
|
}
|
|
536
672
|
break;
|
|
537
673
|
}
|
|
538
|
-
case
|
|
674
|
+
case this.playClientIds.bossBar: {
|
|
539
675
|
try {
|
|
540
676
|
const boss = (0, play_js_1.parseBossBar)(packet.data);
|
|
541
677
|
this.bossBars.handleBossBar(boss.uuid, boss.action, boss.data);
|
|
@@ -545,7 +681,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
545
681
|
}
|
|
546
682
|
break;
|
|
547
683
|
}
|
|
548
|
-
case
|
|
684
|
+
case this.playClientIds.spawnEntity: {
|
|
549
685
|
try {
|
|
550
686
|
const spawn = (0, play_js_1.parseSpawnEntity)(packet.data);
|
|
551
687
|
const entity = new entity_js_1.Entity(spawn.entityId, spawn.entityUUID, spawn.type, new vec3_js_1.Vec3(spawn.x, spawn.y, spawn.z));
|
|
@@ -559,7 +695,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
559
695
|
}
|
|
560
696
|
break;
|
|
561
697
|
}
|
|
562
|
-
case
|
|
698
|
+
case this.playClientIds.entityDestroy: {
|
|
563
699
|
try {
|
|
564
700
|
const { entityIds } = (0, play_js_1.parseRemoveEntities)(packet.data);
|
|
565
701
|
for (const entityId of entityIds) {
|
|
@@ -572,7 +708,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
572
708
|
}
|
|
573
709
|
break;
|
|
574
710
|
}
|
|
575
|
-
case
|
|
711
|
+
case this.playClientIds.relEntityMove: {
|
|
576
712
|
try {
|
|
577
713
|
const pos = (0, play_js_1.parseEntityPosition)(packet.data);
|
|
578
714
|
const entity = this.entities.get(pos.entityId);
|
|
@@ -584,7 +720,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
584
720
|
catch (_) { /* ignore */ }
|
|
585
721
|
break;
|
|
586
722
|
}
|
|
587
|
-
case
|
|
723
|
+
case this.playClientIds.entityMoveLook: {
|
|
588
724
|
try {
|
|
589
725
|
const pos = (0, play_js_1.parseEntityPositionAndRotation)(packet.data);
|
|
590
726
|
const entity = this.entities.get(pos.entityId);
|
|
@@ -598,7 +734,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
598
734
|
catch (_) { /* ignore */ }
|
|
599
735
|
break;
|
|
600
736
|
}
|
|
601
|
-
case
|
|
737
|
+
case this.playClientIds.entityVelocity: {
|
|
602
738
|
try {
|
|
603
739
|
const vel = (0, play_js_1.parseEntityVelocity)(packet.data);
|
|
604
740
|
this.emit('entityVelocity', vel.entityId, new vec3_js_1.Vec3(vel.velocityX, vel.velocityY, vel.velocityZ));
|
|
@@ -606,7 +742,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
606
742
|
catch (_) { /* ignore */ }
|
|
607
743
|
break;
|
|
608
744
|
}
|
|
609
|
-
case
|
|
745
|
+
case this.playClientIds.entityHeadRotation: {
|
|
610
746
|
try {
|
|
611
747
|
const rot = (0, play_js_1.parseEntityHeadRotation)(packet.data);
|
|
612
748
|
const entity = this.entities.get(rot.entityId);
|
|
@@ -617,7 +753,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
617
753
|
catch (_) { /* ignore */ }
|
|
618
754
|
break;
|
|
619
755
|
}
|
|
620
|
-
case
|
|
756
|
+
case this.playClientIds.gameStateChange: {
|
|
621
757
|
try {
|
|
622
758
|
const ev = (0, play_js_1.parseGameEvent)(packet.data);
|
|
623
759
|
if (ev.event === play_js_1.GameEventType.CHANGE_GAME_MODE) {
|
|
@@ -626,14 +762,16 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
626
762
|
this.weather.handleGameEvent(ev.event, ev.value);
|
|
627
763
|
if (ev.event === play_js_1.GameEventType.START_WAITING_FOR_LEVEL_CHUNKS) {
|
|
628
764
|
// Send position confirmation after chunks start loading
|
|
629
|
-
|
|
765
|
+
if (this.playServerIds.positionLook !== MISSING_PACKET_ID) {
|
|
766
|
+
this.connection.sendPacket(this.playServerIds.positionLook, (0, play_js_1.buildSetPlayerPositionAndRotationPacket)(this.entity.position.x, this.entity.position.y, this.entity.position.z, this.entity.yaw, this.entity.pitch, true, this.options.version));
|
|
767
|
+
}
|
|
630
768
|
}
|
|
631
769
|
this.emit('gameEvent', ev.event, ev.value);
|
|
632
770
|
}
|
|
633
771
|
catch (_) { /* ignore */ }
|
|
634
772
|
break;
|
|
635
773
|
}
|
|
636
|
-
case
|
|
774
|
+
case this.playClientIds.respawn: {
|
|
637
775
|
try {
|
|
638
776
|
const resp = (0, play_js_1.parseRespawn)(packet.data);
|
|
639
777
|
this._gameMode = resp.gameMode;
|
|
@@ -647,7 +785,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
647
785
|
}
|
|
648
786
|
break;
|
|
649
787
|
}
|
|
650
|
-
case
|
|
788
|
+
case this.playClientIds.experience: {
|
|
651
789
|
try {
|
|
652
790
|
const exp = (0, play_js_1.parseSetExperience)(packet.data);
|
|
653
791
|
this._experience = exp.totalExperience;
|
|
@@ -657,7 +795,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
657
795
|
catch (_) { /* ignore */ }
|
|
658
796
|
break;
|
|
659
797
|
}
|
|
660
|
-
case
|
|
798
|
+
case this.playClientIds.updateTime: {
|
|
661
799
|
try {
|
|
662
800
|
const time = (0, play_js_1.parseUpdateTime)(packet.data);
|
|
663
801
|
this._worldAge = time.worldAge;
|
|
@@ -667,7 +805,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
667
805
|
catch (_) { /* ignore */ }
|
|
668
806
|
break;
|
|
669
807
|
}
|
|
670
|
-
case
|
|
808
|
+
case this.playClientIds.spawnPosition: {
|
|
671
809
|
try {
|
|
672
810
|
const sp = (0, play_js_1.parseSetDefaultSpawnPosition)(packet.data);
|
|
673
811
|
this._spawnPosition = new vec3_js_1.Vec3(sp.x, sp.y, sp.z);
|
|
@@ -676,7 +814,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
676
814
|
catch (_) { /* ignore */ }
|
|
677
815
|
break;
|
|
678
816
|
}
|
|
679
|
-
case
|
|
817
|
+
case this.playClientIds.openWindow: {
|
|
680
818
|
try {
|
|
681
819
|
const open = (0, play_js_1.parseOpenScreen)(packet.data);
|
|
682
820
|
this.inventory.openWindow(open.windowId, 0);
|
|
@@ -686,7 +824,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
686
824
|
}
|
|
687
825
|
break;
|
|
688
826
|
}
|
|
689
|
-
case
|
|
827
|
+
case this.playClientIds.windowItems: {
|
|
690
828
|
try {
|
|
691
829
|
const reader = new types_js_1.BufferReader(packet.data);
|
|
692
830
|
const windowId = reader.readUByte();
|
|
@@ -701,7 +839,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
701
839
|
}
|
|
702
840
|
break;
|
|
703
841
|
}
|
|
704
|
-
case
|
|
842
|
+
case this.playClientIds.setSlot: {
|
|
705
843
|
try {
|
|
706
844
|
const slot = (0, play_js_1.parseSetContainerSlot)(packet.data);
|
|
707
845
|
const item = inventory_js_1.Inventory.parseItem(new types_js_1.BufferReader(slot.slotData));
|
|
@@ -713,34 +851,36 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
713
851
|
}
|
|
714
852
|
break;
|
|
715
853
|
}
|
|
716
|
-
case
|
|
854
|
+
case this.playClientIds.closeWindow: {
|
|
717
855
|
this.inventory.closeWindow();
|
|
718
856
|
break;
|
|
719
857
|
}
|
|
720
|
-
case
|
|
858
|
+
case this.playClientIds.ping: {
|
|
721
859
|
try {
|
|
722
860
|
const reader = new types_js_1.BufferReader(packet.data);
|
|
723
861
|
const pingId = reader.readInt();
|
|
724
|
-
this.
|
|
862
|
+
if (this.playServerIds.pong !== MISSING_PACKET_ID) {
|
|
863
|
+
this.connection.sendPacket(this.playServerIds.pong, (0, play_js_1.buildPongPacket)(pingId));
|
|
864
|
+
}
|
|
725
865
|
}
|
|
726
866
|
catch (_) { /* ignore */ }
|
|
727
867
|
break;
|
|
728
868
|
}
|
|
729
|
-
case
|
|
869
|
+
case this.playClientIds.acknowledgePlayerDigging: {
|
|
730
870
|
try {
|
|
731
871
|
(0, play_js_1.parseAcknowledgeBlockChange)(packet.data);
|
|
732
872
|
}
|
|
733
873
|
catch (_) { /* ignore */ }
|
|
734
874
|
break;
|
|
735
875
|
}
|
|
736
|
-
case
|
|
876
|
+
case this.playClientIds.disconnect: {
|
|
737
877
|
const { reason } = (0, play_js_1.parseDisconnectPlay)(packet.data);
|
|
738
878
|
this.logger.warn(`Kicked: ${reason}`);
|
|
739
879
|
this.stopPhysicsTick();
|
|
740
880
|
this.emit('kicked', reason);
|
|
741
881
|
break;
|
|
742
882
|
}
|
|
743
|
-
case
|
|
883
|
+
case this.playClientIds.abilities: {
|
|
744
884
|
try {
|
|
745
885
|
const abilities = (0, play_js_1.parsePlayerAbilities)(packet.data);
|
|
746
886
|
this.logger.debug(`Abilities: flags=${abilities.flags} fly=${abilities.flyingSpeed} walk=${abilities.walkingSpeed}`);
|
|
@@ -750,12 +890,29 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
750
890
|
}
|
|
751
891
|
break;
|
|
752
892
|
}
|
|
753
|
-
case
|
|
893
|
+
case this.playClientIds.systemChat: {
|
|
754
894
|
try {
|
|
755
895
|
const chat = (0, play_js_1.parseSystemChat)(packet.data);
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
896
|
+
this.emitChatFromComponent(chat.content, chat.isOverlay);
|
|
897
|
+
}
|
|
898
|
+
catch (_) { /* ignore */ }
|
|
899
|
+
break;
|
|
900
|
+
}
|
|
901
|
+
case this.playClientIds.profilelessChat: {
|
|
902
|
+
try {
|
|
903
|
+
const reader = new types_js_1.BufferReader(packet.data);
|
|
904
|
+
const content = reader.readString();
|
|
905
|
+
this.emitChatFromComponent(content, false);
|
|
906
|
+
}
|
|
907
|
+
catch (_) { /* ignore */ }
|
|
908
|
+
break;
|
|
909
|
+
}
|
|
910
|
+
case this.playClientIds.legacyChat: {
|
|
911
|
+
try {
|
|
912
|
+
const reader = new types_js_1.BufferReader(packet.data);
|
|
913
|
+
const content = reader.readString();
|
|
914
|
+
const position = reader.remaining > 0 ? reader.readByte() : 0;
|
|
915
|
+
this.emitChatFromComponent(content, position === 2);
|
|
759
916
|
}
|
|
760
917
|
catch (_) { /* ignore */ }
|
|
761
918
|
break;
|
|
@@ -771,7 +928,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
771
928
|
return;
|
|
772
929
|
// Send position to server every tick to stay "alive"
|
|
773
930
|
try {
|
|
774
|
-
this.
|
|
931
|
+
this.sendPlayPacket(this.playServerIds.positionLook, (0, play_js_1.buildSetPlayerPositionAndRotationPacket)(this.entity.position.x, this.entity.position.y, this.entity.position.z, this.entity.yaw, this.entity.pitch, true, this.options.version), 'position_look');
|
|
775
932
|
}
|
|
776
933
|
catch (_) {
|
|
777
934
|
this.stopPhysicsTick();
|
|
@@ -813,38 +970,49 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
813
970
|
* Send a chat message.
|
|
814
971
|
*/
|
|
815
972
|
chat(message) {
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
973
|
+
if (this.playServerIds.chatMessage !== MISSING_PACKET_ID) {
|
|
974
|
+
this.sendPlayPacket(this.playServerIds.chatMessage, (0, play_js_1.buildChatMessagePacket)(message, this.options.version), 'chat_message');
|
|
975
|
+
return;
|
|
819
976
|
}
|
|
977
|
+
if (this.playServerIds.chat !== MISSING_PACKET_ID) {
|
|
978
|
+
this.sendPlayPacket(this.playServerIds.chat, (0, play_js_1.buildChatMessagePacket)(message, this.options.version), 'chat');
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
throw new Error(`Chat is not supported for protocol ${this.options.version}`);
|
|
820
982
|
}
|
|
821
983
|
/**
|
|
822
984
|
* Send a / command (e.g. bot.command('gamemode creative')).
|
|
823
985
|
*/
|
|
824
986
|
command(cmd) {
|
|
825
|
-
this.
|
|
987
|
+
if (this.playServerIds.chatCommand !== MISSING_PACKET_ID) {
|
|
988
|
+
try {
|
|
989
|
+
this.sendPlayPacket(this.playServerIds.chatCommand, (0, play_js_1.buildChatCommandPacket)(cmd, this.options.version), 'chat_command');
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
992
|
+
catch (_) {
|
|
993
|
+
// Fallback to plain chat command below.
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
this.chat(`/${cmd}`);
|
|
826
997
|
}
|
|
827
998
|
/**
|
|
828
999
|
* Attack an entity.
|
|
829
1000
|
*/
|
|
830
1001
|
attack(entity) {
|
|
831
|
-
|
|
832
|
-
if (combatPlugin) {
|
|
833
|
-
combatPlugin.attack(entity);
|
|
834
|
-
}
|
|
1002
|
+
this.attackEntity(entity.id);
|
|
835
1003
|
}
|
|
836
1004
|
/**
|
|
837
1005
|
* Attack entity by ID (raw packet).
|
|
838
1006
|
*/
|
|
839
1007
|
attackEntity(entityId) {
|
|
840
|
-
this.
|
|
841
|
-
this.
|
|
1008
|
+
this.sendPlayPacket(this.playServerIds.useEntity, (0, play_js_1.buildInteractEntityPacket)(entityId, play_js_1.InteractEntityType.ATTACK, this._isSneaking, undefined, undefined, undefined, undefined, this.options.version), 'use_entity');
|
|
1009
|
+
this.sendPlayPacket(this.playServerIds.armAnimation, (0, play_js_1.buildSwingArmPacket)(0, this.options.version), 'arm_animation');
|
|
842
1010
|
}
|
|
843
1011
|
/**
|
|
844
1012
|
* Right-click / use an entity (villager trade, mount, etc.).
|
|
845
1013
|
*/
|
|
846
1014
|
useEntity(entityId, hand = 0) {
|
|
847
|
-
this.
|
|
1015
|
+
this.sendPlayPacket(this.playServerIds.useEntity, (0, play_js_1.buildInteractEntityPacket)(entityId, play_js_1.InteractEntityType.INTERACT, this._isSneaking, undefined, undefined, undefined, hand, this.options.version), 'use_entity');
|
|
848
1016
|
}
|
|
849
1017
|
/**
|
|
850
1018
|
* Set the bot's position (sends position packet to server).
|
|
@@ -852,7 +1020,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
852
1020
|
setPosition(x, y, z, onGround = true) {
|
|
853
1021
|
this.entity.position = new vec3_js_1.Vec3(x, y, z);
|
|
854
1022
|
this.entity.onGround = onGround;
|
|
855
|
-
this.
|
|
1023
|
+
this.sendPlayPacket(this.playServerIds.position, (0, play_js_1.buildSetPlayerPositionPacket)(x, y, z, onGround, this.options.version), 'position');
|
|
856
1024
|
}
|
|
857
1025
|
/**
|
|
858
1026
|
* Set position and rotation.
|
|
@@ -862,7 +1030,7 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
862
1030
|
this.entity.yaw = yaw;
|
|
863
1031
|
this.entity.pitch = pitch;
|
|
864
1032
|
this.entity.onGround = onGround;
|
|
865
|
-
this.
|
|
1033
|
+
this.sendPlayPacket(this.playServerIds.positionLook, (0, play_js_1.buildSetPlayerPositionAndRotationPacket)(x, y, z, yaw, pitch, onGround, this.options.version), 'position_look');
|
|
866
1034
|
}
|
|
867
1035
|
/**
|
|
868
1036
|
* Look at a position.
|
|
@@ -874,21 +1042,21 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
874
1042
|
const pitch = -Math.atan2(delta.y, distance) * (180 / Math.PI);
|
|
875
1043
|
this.entity.yaw = yaw;
|
|
876
1044
|
this.entity.pitch = pitch;
|
|
877
|
-
this.
|
|
1045
|
+
this.sendPlayPacket(this.playServerIds.positionLook, (0, play_js_1.buildSetPlayerPositionAndRotationPacket)(this.entity.position.x, this.entity.position.y, this.entity.position.z, yaw, pitch, this.entity.onGround, this.options.version), 'position_look');
|
|
878
1046
|
}
|
|
879
1047
|
/**
|
|
880
1048
|
* Start/stop sprinting.
|
|
881
1049
|
*/
|
|
882
1050
|
sprint(enabled) {
|
|
883
1051
|
this._isSprinting = enabled;
|
|
884
|
-
this.
|
|
1052
|
+
this.sendPlayPacket(this.playServerIds.entityAction, (0, play_js_1.buildPlayerCommandPacket)(this._entityId, enabled ? play_js_1.PlayerCommandAction.START_SPRINTING : play_js_1.PlayerCommandAction.STOP_SPRINTING), 'entity_action');
|
|
885
1053
|
}
|
|
886
1054
|
/**
|
|
887
1055
|
* Start/stop sneaking.
|
|
888
1056
|
*/
|
|
889
1057
|
sneak(enabled) {
|
|
890
1058
|
this._isSneaking = enabled;
|
|
891
|
-
this.
|
|
1059
|
+
this.sendPlayPacket(this.playServerIds.entityAction, (0, play_js_1.buildPlayerCommandPacket)(this._entityId, enabled ? play_js_1.PlayerCommandAction.START_SNEAKING : play_js_1.PlayerCommandAction.STOP_SNEAKING), 'entity_action');
|
|
892
1060
|
}
|
|
893
1061
|
/**
|
|
894
1062
|
* Start digging a block.
|
|
@@ -896,13 +1064,13 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
896
1064
|
dig(x, y, z, face = 1) {
|
|
897
1065
|
this._actionSequence++;
|
|
898
1066
|
// Start digging
|
|
899
|
-
this.
|
|
1067
|
+
this.sendPlayPacket(this.playServerIds.blockDig, (0, play_js_1.buildPlayerActionPacket)(play_js_1.PlayerActionStatus.STARTED_DIGGING, x, y, z, face, this._actionSequence, this.options.version), 'block_dig');
|
|
900
1068
|
// Swing arm animation
|
|
901
|
-
this.
|
|
1069
|
+
this.sendPlayPacket(this.playServerIds.armAnimation, (0, play_js_1.buildSwingArmPacket)(0, this.options.version), 'arm_animation');
|
|
902
1070
|
// For creative mode, finish immediately
|
|
903
1071
|
if (this._gameMode === 1) {
|
|
904
1072
|
this._actionSequence++;
|
|
905
|
-
this.
|
|
1073
|
+
this.sendPlayPacket(this.playServerIds.blockDig, (0, play_js_1.buildPlayerActionPacket)(play_js_1.PlayerActionStatus.FINISHED_DIGGING, x, y, z, face, this._actionSequence, this.options.version), 'block_dig');
|
|
906
1074
|
}
|
|
907
1075
|
}
|
|
908
1076
|
/**
|
|
@@ -910,15 +1078,15 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
910
1078
|
*/
|
|
911
1079
|
placeBlock(x, y, z, face = 1, hand = 0) {
|
|
912
1080
|
this._actionSequence++;
|
|
913
|
-
this.
|
|
914
|
-
this.
|
|
1081
|
+
this.sendPlayPacket(this.playServerIds.blockPlace, (0, play_js_1.buildUseItemOnPacket)(hand, x, y, z, face, 0.5, 0.5, 0.5, false, false, this._actionSequence, this.options.version), 'block_place');
|
|
1082
|
+
this.sendPlayPacket(this.playServerIds.armAnimation, (0, play_js_1.buildSwingArmPacket)(hand, this.options.version), 'arm_animation');
|
|
915
1083
|
}
|
|
916
1084
|
/**
|
|
917
1085
|
* Use the item in hand (eat, throw, shoot bow, etc.).
|
|
918
1086
|
*/
|
|
919
1087
|
useItem(hand = 0) {
|
|
920
1088
|
this._actionSequence++;
|
|
921
|
-
this.
|
|
1089
|
+
this.sendPlayPacket(this.playServerIds.useItem, (0, play_js_1.buildUseItemPacket)(hand, this._actionSequence, this.entity.yaw, this.entity.pitch, this.options.version), 'use_item');
|
|
922
1090
|
}
|
|
923
1091
|
/**
|
|
924
1092
|
* Select a hotbar slot (0-8).
|
|
@@ -926,46 +1094,46 @@ class Bot extends events_js_1.TypedEventEmitter {
|
|
|
926
1094
|
setHeldItem(slot) {
|
|
927
1095
|
if (slot < 0 || slot > 8)
|
|
928
1096
|
throw new Error('Slot must be 0-8');
|
|
929
|
-
this.
|
|
1097
|
+
this.sendPlayPacket(this.playServerIds.heldItemSlot, (0, play_js_1.buildSetHeldItemPacket)(slot), 'held_item_slot');
|
|
930
1098
|
}
|
|
931
1099
|
/**
|
|
932
1100
|
* Swing arm animation.
|
|
933
1101
|
*/
|
|
934
1102
|
swingArm(hand = 0) {
|
|
935
|
-
this.
|
|
1103
|
+
this.sendPlayPacket(this.playServerIds.armAnimation, (0, play_js_1.buildSwingArmPacket)(hand, this.options.version), 'arm_animation');
|
|
936
1104
|
}
|
|
937
1105
|
/**
|
|
938
1106
|
* Drop the held item.
|
|
939
1107
|
*/
|
|
940
1108
|
dropItem(dropStack = false) {
|
|
941
1109
|
this._actionSequence++;
|
|
942
|
-
this.
|
|
1110
|
+
this.sendPlayPacket(this.playServerIds.blockDig, (0, play_js_1.buildPlayerActionPacket)(dropStack ? play_js_1.PlayerActionStatus.DROP_ITEM_STACK : play_js_1.PlayerActionStatus.DROP_ITEM, 0, 0, 0, 0, this._actionSequence, this.options.version), 'block_dig');
|
|
943
1111
|
}
|
|
944
1112
|
/**
|
|
945
1113
|
* Swap items between main and off hand.
|
|
946
1114
|
*/
|
|
947
1115
|
swapHands() {
|
|
948
1116
|
this._actionSequence++;
|
|
949
|
-
this.
|
|
1117
|
+
this.sendPlayPacket(this.playServerIds.blockDig, (0, play_js_1.buildPlayerActionPacket)(play_js_1.PlayerActionStatus.SWAP_ITEM_IN_HAND, 0, 0, 0, 0, this._actionSequence, this.options.version), 'block_dig');
|
|
950
1118
|
}
|
|
951
1119
|
/**
|
|
952
1120
|
* Toggle flying (creative/spectator mode).
|
|
953
1121
|
*/
|
|
954
1122
|
fly(enabled) {
|
|
955
|
-
this.
|
|
1123
|
+
this.sendPlayPacket(this.playServerIds.abilities, (0, play_js_1.buildPlayerAbilitiesServerboundPacket)(enabled, this.options.version), 'abilities');
|
|
956
1124
|
}
|
|
957
1125
|
/**
|
|
958
1126
|
* Respawn after death.
|
|
959
1127
|
*/
|
|
960
1128
|
respawn() {
|
|
961
|
-
this.
|
|
1129
|
+
this.sendPlayPacket(this.playServerIds.clientCommand, (0, play_js_1.buildClientStatusPacket)(play_js_1.ClientStatusAction.PERFORM_RESPAWN), 'client_command');
|
|
962
1130
|
this._isAlive = true;
|
|
963
1131
|
}
|
|
964
1132
|
/**
|
|
965
1133
|
* Close the currently open container.
|
|
966
1134
|
*/
|
|
967
1135
|
closeContainer(windowId = 0) {
|
|
968
|
-
this.
|
|
1136
|
+
this.sendPlayPacket(this.playServerIds.closeWindow, (0, play_js_1.buildCloseContainerPacket)(windowId), 'close_window');
|
|
969
1137
|
}
|
|
970
1138
|
/**
|
|
971
1139
|
* Disconnect from the server.
|