mineflayer 4.6.0 → 4.8.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.
@@ -31,6 +31,10 @@ jobs:
31
31
  mcVersion: '1.18.2'
32
32
  - javaVersion: 17
33
33
  mcVersion: '1.19'
34
+ - javaVersion: 17
35
+ mcVersion: '1.19.2'
36
+ - javaVersion: 17
37
+ mcVersion: '1.19.3'
34
38
  fail-fast: false
35
39
 
36
40
  steps:
package/README.md CHANGED
@@ -189,8 +189,9 @@ The most updated and useful are :
189
189
  * [Auto Crystal](https://github.com/link-discord/mineflayer-autocrystal) - Automatic placing & breaking of end crystals.
190
190
  * [Tool](https://github.com/TheDudeFromCI/mineflayer-tool) - A utility for automatic tool/weapon selection with a high level API.
191
191
  * [Hawkeye](https://github.com/sefirosweb/minecraftHawkEye) - A utility for using auto-aim with bows.
192
- * [GUI](https://github.com/firejoust/mineflayer-GUI) - Eased navigation & management of nested chest-GUI windows
193
- * [Projectile](https://github.com/firejoust/mineflayer-projectile) - Configurable tool for projectile based combat
192
+ * [GUI](https://github.com/firejoust/mineflayer-GUI) - Interact with nested GUI windows using async/await
193
+ * [Projectile](https://github.com/firejoust/mineflayer-projectile) - Get the required launch angle for projectiles
194
+ * [Movement](https://github.com/firejoust/mineflayer-movement) - Smooth and realistic player movement, best suited for PvP
194
195
 
195
196
 
196
197
  But also check out :
package/docs/README.md CHANGED
@@ -189,8 +189,9 @@ The most updated and useful are :
189
189
  * [Auto Crystal](https://github.com/link-discord/mineflayer-autocrystal) - Automatic placing & breaking of end crystals.
190
190
  * [Tool](https://github.com/TheDudeFromCI/mineflayer-tool) - A utility for automatic tool/weapon selection with a high level API.
191
191
  * [Hawkeye](https://github.com/sefirosweb/minecraftHawkEye) - A utility for using auto-aim with bows.
192
- * [GUI](https://github.com/firejoust/mineflayer-GUI) - Eased navigation & management of nested chest-GUI windows
193
- * [Projectile](https://github.com/firejoust/mineflayer-projectile) - Configurable tool for projectile based combat
192
+ * [GUI](https://github.com/firejoust/mineflayer-GUI) - Interact with nested GUI windows using async/await
193
+ * [Projectile](https://github.com/firejoust/mineflayer-projectile) - Get the required launch angle for projectiles
194
+ * [Movement](https://github.com/firejoust/mineflayer-movement) - Smooth and realistic player movement, best suited for PvP
194
195
 
195
196
 
196
197
  But also check out :
package/docs/api.md CHANGED
@@ -1156,7 +1156,8 @@ Emitted for every server message which appears on the Action Bar.
1156
1156
 
1157
1157
  Emitted for every server message, including chats.
1158
1158
 
1159
- * `jsonMsg` - unmodified JSON message from the server
1159
+ * `jsonMsg` - [ChatMessage](https://github.com/PrismarineJS/prismarine-chat) object containing the formatted chat message. Might additionally have the following properties:
1160
+ * unsigned - Unsigned ChatMessage object. Only present in 1.19.2+, and only when the server allows insecure chat and the server modified the chat message without the user's signature
1160
1161
 
1161
1162
  * `position` - (>= 1.8.1): position of Chat message can be
1162
1163
  * chat
@@ -1169,7 +1170,7 @@ Emitted for every server message, including chats.
1169
1170
 
1170
1171
  #### "messagestr" (message, messagePosition, jsonMsg, sender, verified)
1171
1172
 
1172
- Alias for the "message" event but it calls .toString() on the message object to get a string for the message before emitting.
1173
+ Alias for the "message" event but it calls .toString() on the prismarine-message object to get a string for the message before emitting.
1173
1174
 
1174
1175
  * `sender` - UUID of sender if known (1.16+), else null
1175
1176
 
package/docs/history.md CHANGED
@@ -1,4 +1,14 @@
1
- 4.6.0
1
+ ## 4.8.0
2
+
3
+ * Update chat parsing (@frej4189)
4
+ * Fix message event not including chat position (@frej4189)
5
+ * 1.19.3 (@frej4189)
6
+
7
+ ## 4.7.0
8
+
9
+ * 1.19.2 support (@frej4189)
10
+
11
+ ## 4.6.0
2
12
 
3
13
  * Fix unhandled promise rejection in onceWithCleanup (@IceTank) [#2833](https://github.com/PrismarineJS/mineflayer/pull/2833)
4
14
  * Extend every window that is opened with mineflayer specific window functions (@IceTank) [#2768][https://github.com/PrismarineJS/mineflayer/pull/2768]
@@ -12,9 +12,9 @@
12
12
  | <sub>EN</sub> [English](../README.md) | <sub>RU</sub> [русский](../ru/README_RU.md) | <sub>ES</sub> [Español](../es/README_ES.md) | <sub>FR</sub> [Français](../fr/README_FR.md) | <sub>TR</sub> [Türkçe](../tr/README_TR.md) | <sub>ZH</sub> [中文](../zh/README_ZH_CN.md) |
13
13
  |-------------------------|----------------------------|----------------------------|----------------------------|----------------------------|----------------------------|
14
14
 
15
- Создавайте ботов Minecraft с помощью мощного, стабильного и высокоуровневого JavaScript [API](api.md).
15
+ Создавайте ботов Minecraft с помощью мощного, стабильного и высокоуровневого JavaScript [API](api.md), также можете использовать Python
16
16
 
17
- Первый раз используете Node.js? Начните с [этого](tutorial.md).
17
+ Первый раз используете Node.js? Начните с [этого](tutorial.md). Любите гонять змею? Зацените [Python примеры](https://github.com/PrismarineJS/mineflayer/tree/master/examples/python) и попробуйте колабнуться в [Mineflayer Google коллабе](https://colab.research.google.com/github/PrismarineJS/mineflayer/blob/master/docs/mineflayer.ipynb).
18
18
 
19
19
  ## Возможности
20
20
 
@@ -1,57 +1,64 @@
1
1
  /*
2
2
  * This example is a very simple way how to connect a discord bot with a mineflayer bot.
3
3
  * For this example you will need discord.js installed. You can install with: npm install discord.js
4
- * This example uses discord.js v13
4
+ * This example uses discord.js v14
5
5
  * You need to do this before running this example:
6
- * - You need to get a discord token
6
+ * - You need to get a discord bot token
7
7
  * - You need to get the id of the channel you want to use
8
- */
8
+ *
9
+ * Original credit to U9G, updated by Jovan04 12/19/2022
10
+ */
9
11
 
10
12
  if (process.argv.length < 6 || process.argv.length > 8) {
11
- console.log('Usage : node discord.js <discord bot token> <channel id> <host> <port> [<name>] [<password>]')
13
+ console.log('Usage : node discord.js <discord bot token> <channel id> <host> <port> [<name>] [<auth>]')
12
14
  process.exit(1)
13
15
  }
14
16
 
15
- // Load discord.js
16
- const {
17
- Client,
18
- Intents
19
- } = require('discord.js')
20
- // Create Discord intentions, required in v13
21
- const intents = new Intents(['GUILDS', 'GUILD_MESSAGES'])
22
- // Create Discord client
23
- const client = new Client({
24
- intents
25
- })
17
+ // load discord.js
18
+ const { Client, GatewayIntentBits } = require('discord.js')
19
+ const { MessageContent, GuildMessages, Guilds } = GatewayIntentBits
26
20
 
27
21
  let channel = process.argv[3]
22
+ const token = process.argv[2]
23
+
24
+ // create new discord client that can see what servers the bot is in, as well as the messages in those servers
25
+ const client = new Client({ intents: [Guilds, GuildMessages, MessageContent] })
26
+ client.login(token)
28
27
 
29
- // Load mineflayer
28
+ // load mineflayer
30
29
  const mineflayer = require('mineflayer')
31
- const bot = mineflayer.createBot({
30
+
31
+ // bot options
32
+ const options = {
32
33
  host: process.argv[4],
33
34
  port: parseInt(process.argv[5]),
34
35
  username: process.argv[6] || 'discord',
35
- password: process.argv[7]
36
+ auth: process.argv[7] || 'offline'
37
+ }
38
+
39
+ // join server
40
+ const bot = mineflayer.createBot(options)
41
+ bot.on('spawn', () => {
42
+ console.log(`Mineflayer bot logged in as ${bot.username}`)
36
43
  })
37
44
 
38
- client.on('ready', () => {
39
- console.log(`The discord bot logged in! Username: ${client.user.username}!`)
40
- // Find the Discord channel messages will be sent to
45
+ // when discord client is ready, send login message
46
+ client.once('ready', (c) => {
47
+ console.log(`Discord bot logged in as ${c.user.tag}`)
41
48
  channel = client.channels.cache.get(channel)
42
49
  if (!channel) {
43
- console.log(`I could not find the channel (${process.argv[3]})!\nUsage : node discord.js <discord bot token> <channel id> <host> <port> [<name>] [<password>]`)
50
+ console.log(`I could not find the channel (${process.argv[3]})!`)
51
+ console.log('Usage : node discord.js <discord bot token> <channel id> <host> <port> [<name>] [<auth>]')
44
52
  process.exit(1)
45
53
  }
46
54
  })
47
55
 
48
- // Redirect Discord messages to in-game chat
49
- client.on('messageCreate', message => {
56
+ client.on('messageCreate', (message) => {
50
57
  // Only handle messages in specified channel
51
58
  if (message.channel.id !== channel.id) return
52
59
  // Ignore messages from the bot itself
53
60
  if (message.author.id === client.user.id) return
54
-
61
+ // console.log(message)
55
62
  bot.chat(`${message.author.username}: ${message.content}`)
56
63
  })
57
64
 
@@ -62,6 +69,3 @@ bot.on('chat', (username, message) => {
62
69
 
63
70
  channel.send(`${username}: ${message}`)
64
71
  })
65
-
66
- // Login Discord bot
67
- client.login(process.argv[2])
@@ -0,0 +1,43 @@
1
+ /*
2
+ * This example is a very simple way of connecting to a telegram group
3
+ * For this example you'll need Telegraf installed. This can be done with `npm install telegraf`
4
+ * You need to do this before running this example:
5
+ * - You need to get a telegram bot token from @botfather
6
+ * - You need to get the id of the group you want to use
7
+ */
8
+
9
+ if (process.argv.length < 6 || process.argv.length > 8) {
10
+ console.log('Usage : node telegram.js <telegram bot token> <group id> <host> <port> [<name>] [<password>]')
11
+ process.exit(1)
12
+ }
13
+
14
+ // Load Telegraf
15
+ const { Telegraf } = require('telegraf')
16
+ const telegram = new Telegraf(process.argv[2])
17
+
18
+ // Load mineflayer
19
+ const mineflayer = require('mineflayer')
20
+ const bot = mineflayer.createBot({
21
+ host: process.argv[4],
22
+ port: parseInt(process.argv[5]),
23
+ username: process.argv[6] || 'telegram',
24
+ password: process.argv[7]
25
+ })
26
+
27
+ telegram.on('text', async (ctx) => {
28
+ // check if message was reveived from chosen group
29
+ if (ctx.update.message.chat.id.toString() === process.argv[3]) {
30
+ // send message to mc server
31
+ bot.chat(`${ctx.update.message.from.first_name} ${ctx.update.message.from.last_name}: ${ctx.update.message.text}`)
32
+ }
33
+ })
34
+
35
+ // Redirect in-game messages to telegram group
36
+ bot.on('chat', (username, message) => {
37
+ // Ignore messages from the bot itself
38
+ if (username === bot.username) return
39
+ telegram.telegram.sendMessage(process.argv[3], username + ': ' + message)
40
+ })
41
+
42
+ // Login telegram bot
43
+ telegram.launch()
package/index.d.ts CHANGED
@@ -8,6 +8,7 @@ import { Recipe } from 'prismarine-recipe'
8
8
  import { Block } from 'prismarine-block'
9
9
  import { Entity } from 'prismarine-entity'
10
10
  import { ChatMessage } from 'prismarine-chat'
11
+ import { Registry } from 'prismarine-registry'
11
12
 
12
13
  export function createBot (options: { client: Client } & Partial<BotOptions>): Bot
13
14
  export function createBot (options: BotOptions): Bot
@@ -192,6 +193,7 @@ export interface Bot extends TypedEmitter<BotEvents> {
192
193
  currentWindow: Window | null
193
194
  simpleClick: simpleClick
194
195
  tablist: Tablist
196
+ registry: Registry
195
197
 
196
198
  connect: (options: BotOptions) => void
197
199
 
@@ -565,6 +567,7 @@ export interface TransferOptions {
565
567
  window: Window
566
568
  itemType: number
567
569
  metadata: number | null
570
+ count?: number,
568
571
  sourceStart: number
569
572
  sourceEnd: number
570
573
  destStart: number
@@ -20,7 +20,7 @@ const dimensionNames = {
20
20
  1: 'minecraft:end'
21
21
  }
22
22
 
23
- function inject (bot, { version, storageBuilder }) {
23
+ function inject (bot, { version, storageBuilder, hideErrors }) {
24
24
  const Block = require('prismarine-block')(bot.registry)
25
25
  const Chunk = require('prismarine-chunk')(bot.registry)
26
26
  const World = require('prismarine-world')(bot.registry)
@@ -289,6 +289,10 @@ function inject (bot, { version, storageBuilder }) {
289
289
 
290
290
  if (typeof packet.blockEntities !== 'undefined') {
291
291
  const column = bot.world.getColumn(packet.x, packet.z)
292
+ if (!column) {
293
+ if (!hideErrors) console.warn('Ignoring block entities as chunk failed to load at', packet.x, packet.z)
294
+ return
295
+ }
292
296
  for (const blockEntity of packet.blockEntities) {
293
297
  if (blockEntity.x !== undefined) { // 1.17+
294
298
  column.setBlockEntity(blockEntity, blockEntity.nbtData)
@@ -108,43 +108,37 @@ function inject (bot, options) {
108
108
 
109
109
  addDefaultPatterns()
110
110
 
111
- // Pre 1.19
112
- bot._client.on('chat', (packet) => {
113
- const msg = ChatMessage.fromNotch(packet.message)
114
- const chatPositions = {
115
- 0: 'chat',
116
- 1: 'system',
117
- 2: 'game_info'
118
- }
119
- bot.emit('message', msg, chatPositions[packet.position], packet.sender, /* verified */ null)
120
- bot.emit('messagestr', msg.toString(), chatPositions[packet.position], msg, packet.sender, /* verified */ null)
121
- // Position 2 is the action bar
122
- if (packet.position === 2) bot.emit('actionBar', msg, null)
123
- })
111
+ bot._client.on('playerChat', (data) => {
112
+ const message = data.formattedMessage
113
+ const verified = data.verified
114
+ let msg
115
+ if (bot.supportFeature('clientsideChatFormatting')) {
116
+ const parameters = {
117
+ sender: data.senderName ? JSON.parse(data.senderName) : undefined,
118
+ target: data.targetName ? JSON.parse(data.targetName) : undefined,
119
+ content: message ? JSON.parse(message) : { text: data.plainMessage }
120
+ }
121
+ msg = ChatMessage.fromNetwork(data.type, parameters)
124
122
 
125
- // 1.19+
126
- bot._client.on('player_chat', (packet) => {
127
- const message = packet.unsignedChatContent || packet.signedChatContent
128
- let verified = false
129
- const sender = bot.uuidToUsername[packet.senderUuid]
130
- if (sender) {
131
- const { profileKeys } = bot.players[sender]
132
- if (profileKeys) verified = bot._client.verifyMessage(profileKeys.publicKey, packet)
133
- }
134
- const parameters = {
135
- sender: JSON.parse(packet.senderName),
136
- content: JSON.parse(message)
123
+ if (data.unsignedContent) {
124
+ msg.unsigned = ChatMessage.fromNetwork(data.type, { sender: parameters.sender, target: parameters.target, content: JSON.parse(data.unsignedContent) })
125
+ }
126
+ } else {
127
+ msg = ChatMessage.fromNotch(message)
137
128
  }
138
- const msg = ChatMessage.fromNetwork(packet.type, parameters)
139
- Object.assign(msg, parameters)
140
- bot.emit('message', msg, 'chat', packet.senderUuid, verified)
141
- bot.emit('messagestr', msg.toString(), 'chat', msg, packet.senderUuid, verified)
129
+ bot.emit('message', msg, 'chat', data.sender, verified)
130
+ bot.emit('messagestr', msg.toString(), 'chat', msg, data.sender, verified)
142
131
  })
143
132
 
144
- bot._client.on('system_chat', (packet) => {
145
- const msg = ChatMessage.fromNotch(packet.content)
146
- bot.emit('message', msg, 'system', null)
147
- bot.emit('messagestr', msg.toString(), 'system', msg, null)
133
+ bot._client.on('systemChat', (data) => {
134
+ const msg = ChatMessage.fromNotch(data.formattedMessage)
135
+ const chatPositions = {
136
+ 1: 'system',
137
+ 2: 'game_info'
138
+ }
139
+ bot.emit('message', msg, chatPositions[data.positionId], null)
140
+ bot.emit('messagestr', msg.toString(), chatPositions[data.positionId], msg, null)
141
+ if (data.positionId === 2) bot.emit('actionBar', msg, null)
148
142
  })
149
143
 
150
144
  function chatWithHeader (header, message) {
@@ -163,7 +157,11 @@ function inject (bot, options) {
163
157
  timestamp,
164
158
  salt: 0n,
165
159
  argumentSignatures: [],
166
- signedPreview: false
160
+ signedPreview: false,
161
+ messageCount: 0,
162
+ acknowledged: Buffer.alloc(3),
163
+ // 1.19.2 Chat Command packet also includes an array of last seen messages
164
+ previousMessages: []
167
165
  })
168
166
  return
169
167
  }
@@ -176,17 +174,7 @@ function inject (bot, options) {
176
174
  let smallMsg
177
175
  for (i = 0; i < subMessage.length; i += lengthLimit) {
178
176
  smallMsg = header + subMessage.substring(i, i + lengthLimit)
179
- if (bot.supportFeature('signedChat')) {
180
- const timestamp = BigInt(Date.now())
181
- bot._client.write('chat_message', {
182
- message: smallMsg,
183
- timestamp,
184
- salt: 0,
185
- signature: bot._client.profileKeys ? bot._client.signMessage(smallMsg, timestamp) : Buffer.alloc(0)
186
- })
187
- } else {
188
- bot._client.write('chat', { message: smallMsg })
189
- }
177
+ bot._client.chat(smallMsg)
190
178
  }
191
179
  })
192
180
  }
@@ -361,13 +361,14 @@ function inject (bot) {
361
361
  entity.metadata = metadata
362
362
  bot.emit('entityUpdate', entity)
363
363
 
364
- const typeSlot = bot.supportFeature('itemsAreAlsoBlocks') ? 5 : 6
364
+ const typeSlot = (bot.supportFeature('itemsAreAlsoBlocks') ? 5 : 6) + (bot.supportFeature('entityMetadataHasLong') ? 1 : 0)
365
365
  const slot = packet.metadata.find(e => e.type === typeSlot)
366
366
  if (entity.name && (entity.name.toLowerCase() === 'item' || entity.name === 'item_stack') && slot) {
367
367
  bot.emit('itemDrop', entity)
368
368
  }
369
369
 
370
- const pose = packet.metadata.find(e => e.type === 18)
370
+ const typePose = bot.supportFeature('entityMetadataHasLong') ? 19 : 18
371
+ const pose = packet.metadata.find(e => e.type === typePose)
371
372
  if (pose && pose.value === 2) {
372
373
  bot.emit('entitySleep', entity)
373
374
  }
@@ -444,81 +445,149 @@ function inject (bot) {
444
445
 
445
446
  bot._client.on('player_info', (packet) => {
446
447
  // player list item(s)
447
- for (const item of packet.data) {
448
- let player = bot.uuidToUsername[item.UUID] ? bot.players[bot.uuidToUsername[item.UUID]] : null
449
- if (packet.action === 0) {
448
+
449
+ if (bot.supportFeature('playerInfoActionIsBitfield')) {
450
+ for (const item of packet.data) {
451
+ let player = bot.uuidToUsername[item.uuid] ? bot.players[bot.uuidToUsername[item.uuid]] : null
450
452
  let newPlayer = false
451
453
 
452
- // New Player
453
- if (!player) {
454
- player = bot.players[item.name] = {
455
- username: item.name,
456
- ping: item.ping,
457
- uuid: item.UUID,
458
- displayName: new ChatMessage({ text: '', extra: [{ text: item.name }] }),
459
- profileKeys: item.crypto
460
- ? {
461
- publicKey: item.crypto.publicKey, // DER-encoded public key
462
- signature: item.crypto.signature // Signature
463
- }
464
- : null
465
- }
454
+ const obj = {
455
+ uuid: item.uuid
456
+ }
466
457
 
467
- bot.uuidToUsername[item.UUID] = item.name
468
- bot.emit('playerJoined', player)
469
- newPlayer = true
470
- } else {
471
- // Just an Update
472
- player.gamemode = item.gamemode
473
- player.ping = item.ping
474
- if (item.crypto) {
475
- player.profileKeys = {
476
- publicKey: item.crypto.publicKey,
477
- signature: item.crypto.signature
478
- }
479
- }
458
+ if (!player) newPlayer = true
459
+
460
+ player = player || obj
461
+
462
+ if (packet.action & 1) {
463
+ obj.username = item.player.name
464
+ obj.displayName = player.displayName || new ChatMessage({ text: '', extra: [{ text: item.player.name }] })
465
+ }
466
+
467
+ if (packet.action & 4) {
468
+ obj.gamemode = item.gamemode
469
+ }
470
+
471
+ if (packet.action & 16) {
472
+ obj.ping = item.latency
480
473
  }
481
474
 
482
475
  if (item.displayName) {
483
- player.displayName = new ChatMessage(JSON.parse(item.displayName))
476
+ obj.displayName = new ChatMessage(JSON.parse(item.displayName))
477
+ } else if (packet.action & 32) obj.displayName = new ChatMessage({ text: '', extra: [{ text: player.username || obj.username }] })
478
+
479
+ if (newPlayer) {
480
+ if (!obj.username) continue // Should be unreachable
481
+ player = bot.players[obj.username] = obj
482
+ bot.uuidToUsername[obj.uuid] = obj.username
483
+ } else {
484
+ Object.assign(player, obj)
484
485
  }
485
486
 
486
- const playerEntity = Object.values(bot.entities).find(e => e.type === 'player' && e.username === item.name)
487
+ const playerEntity = Object.values(bot.entities).find(e => e.type === 'player' && e.username === obj.username)
487
488
  player.entity = playerEntity
488
489
 
489
490
  if (playerEntity === bot.entity) {
490
491
  bot.player = player
491
492
  }
492
493
 
493
- if (!newPlayer) {
494
- bot.emit('playerUpdated', player)
495
- }
496
- } else if (player) {
497
- if (packet.action === 1) {
498
- player.gamemode = item.gamemode
499
- } else if (packet.action === 2) {
500
- player.ping = item.ping
501
- } else if (packet.action === 3 && !item.displayName) {
502
- player.displayName = new ChatMessage({ text: '', extra: [{ text: player.username }] })
503
- } else if (packet.action === 3 && item.displayName) {
504
- player.displayName = new ChatMessage(JSON.parse(item.displayName))
505
- } else if (packet.action === 4) {
506
- if (player.entity === bot.entity) continue
507
-
508
- player.entity = null
509
- delete bot.players[player.username]
510
- delete bot.uuidToUsername[item.UUID]
511
- bot.emit('playerLeft', player)
512
- continue
494
+ if (newPlayer) {
495
+ bot.emit('playerJoined', player)
513
496
  } else {
514
- continue
497
+ bot.emit('playerUpdated', player)
515
498
  }
499
+ }
500
+ } else {
501
+ for (const item of packet.data) {
502
+ let player = bot.uuidToUsername[item.UUID] ? bot.players[bot.uuidToUsername[item.UUID]] : null
503
+ if (packet.action === 0) {
504
+ let newPlayer = false
505
+
506
+ // New Player
507
+ if (!player) {
508
+ player = bot.players[item.name] = {
509
+ username: item.name,
510
+ ping: item.ping,
511
+ uuid: item.UUID,
512
+ displayName: new ChatMessage({ text: '', extra: [{ text: item.name }] }),
513
+ profileKeys: item.crypto
514
+ ? {
515
+ publicKey: item.crypto.publicKey, // DER-encoded public key
516
+ signature: item.crypto.signature // Signature
517
+ }
518
+ : null
519
+ }
520
+
521
+ bot.uuidToUsername[item.UUID] = item.name
522
+ bot.emit('playerJoined', player)
523
+ newPlayer = true
524
+ } else {
525
+ // Just an Update
526
+ player.gamemode = item.gamemode
527
+ player.ping = item.ping
528
+ if (item.crypto) {
529
+ player.profileKeys = {
530
+ publicKey: item.crypto.publicKey,
531
+ signature: item.crypto.signature
532
+ }
533
+ }
534
+ }
535
+
536
+ if (item.displayName) {
537
+ player.displayName = new ChatMessage(JSON.parse(item.displayName))
538
+ }
539
+
540
+ const playerEntity = Object.values(bot.entities).find(e => e.type === 'player' && e.username === item.name)
541
+ player.entity = playerEntity
542
+
543
+ if (playerEntity === bot.entity) {
544
+ bot.player = player
545
+ }
516
546
 
517
- bot.emit('playerUpdated', player)
547
+ if (!newPlayer) {
548
+ bot.emit('playerUpdated', player)
549
+ }
550
+ } else if (player) {
551
+ if (packet.action === 1) {
552
+ player.gamemode = item.gamemode
553
+ } else if (packet.action === 2) {
554
+ player.ping = item.ping
555
+ } else if (packet.action === 3 && !item.displayName) {
556
+ player.displayName = new ChatMessage({ text: '', extra: [{ text: player.username }] })
557
+ } else if (packet.action === 3 && item.displayName) {
558
+ player.displayName = new ChatMessage(JSON.parse(item.displayName))
559
+ } else if (packet.action === 4) {
560
+ if (player.entity === bot.entity) continue
561
+
562
+ player.entity = null
563
+ delete bot.players[player.username]
564
+ delete bot.uuidToUsername[item.UUID]
565
+ bot.emit('playerLeft', player)
566
+ continue
567
+ } else {
568
+ continue
569
+ }
570
+
571
+ bot.emit('playerUpdated', player)
572
+ }
518
573
  }
519
574
  }
520
575
  })
521
576
 
577
+ // (1.19.3) player(s) leave the game
578
+ bot._client.on('player_remove', (packet) => {
579
+ for (const uuid of packet.players) {
580
+ const player = bot.uuidToUsername[uuid] ? bot.players[bot.uuidToUsername[uuid]] : null
581
+
582
+ if (player.entity === bot.entity) continue
583
+
584
+ player.entity = null
585
+ delete bot.players[player.username]
586
+ delete bot.uuidToUsername[uuid]
587
+ bot.emit('playerLeft', player)
588
+ }
589
+ })
590
+
522
591
  // attaching to a vehicle
523
592
  bot._client.on('attach_entity', (packet) => {
524
593
  if (packet.entityId !== bot.entity.id) return
package/lib/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  module.exports = {
2
2
  supportedVersions: ['1.8', '1.9', '1.10', '1.11', '1.12', '1.13', '1.14', '1.15', '1.16', '1.17', '1.18', '1.19'],
3
- testedVersions: ['1.8.8', '1.9.4', '1.10.2', '1.11.2', '1.12.2', '1.13.2', '1.14.4', '1.15.2', '1.16.5', '1.17.1', '1.18.2', '1.19']
3
+ testedVersions: ['1.8.8', '1.9.4', '1.10.2', '1.11.2', '1.12.2', '1.13.2', '1.14.4', '1.15.2', '1.16.5', '1.17.1', '1.18.2', '1.19', '1.19.2', '1.19.3']
4
4
  } // when updating testedVersions, make sure to update CI.yml
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mineflayer",
3
- "version": "4.6.0",
3
+ "version": "4.8.0",
4
4
  "description": "create minecraft bots with a stable, high level API",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -21,8 +21,8 @@
21
21
  },
22
22
  "license": "MIT",
23
23
  "dependencies": {
24
- "minecraft-data": "^3.15.2",
25
- "minecraft-protocol": "^1.36.0",
24
+ "minecraft-data": "^3.26.0",
25
+ "minecraft-protocol": "^1.40.3",
26
26
  "prismarine-biome": "^1.1.1",
27
27
  "prismarine-block": "^1.13.1",
28
28
  "prismarine-chat": "^1.7.1",