mineflayer 4.5.1 → 4.7.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,8 @@ jobs:
31
31
  mcVersion: '1.18.2'
32
32
  - javaVersion: 17
33
33
  mcVersion: '1.19'
34
+ - javaVersion: 17
35
+ mcVersion: '1.19.2'
34
36
  fail-fast: false
35
37
 
36
38
  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
@@ -75,6 +75,14 @@
75
75
  - [BossBar.isDragonBar](#bossbarisdragonbar)
76
76
  - [BossBar.createFog](#bossbarcreatefog)
77
77
  - [BossBar.color](#bossbarcolor)
78
+ - [mineflayer.Particle](#mineflayerparticle)
79
+ - [Particle.id](#particleid)
80
+ - [Particle.name](#particlename)
81
+ - [Particle.position](#particleposition)
82
+ - [Particle.offset](#particleoffset)
83
+ - [Particle.longDistanceRender](#particlelongdistancerender)
84
+ - [Particle.count](#particlecount)
85
+ - [Particle.movementSpeed](#particlemovementspeed)
78
86
  - [Bot](#bot)
79
87
  - [mineflayer.createBot(options)](#mineflayercreatebotoptions)
80
88
  - [Properties](#properties)
@@ -239,6 +247,7 @@
239
247
  - ["heldItemChanged" (heldItem)](#helditemchanged-helditem)
240
248
  - ["physicsTick" ()](#physicstick-)
241
249
  - ["chat:name" (matches)](#chatname-matches)
250
+ - ["particle"](#particle)
242
251
  - [Functions](#functions)
243
252
  - [bot.blockAt(point, extraInfos=true)](#botblockatpoint-extrainfostrue)
244
253
  - [bot.waitForChunksToLoad()](#botwaitforchunkstoload)
@@ -725,6 +734,36 @@ Determines whether or not boss bar creates fog
725
734
 
726
735
  Determines what color the boss bar color is, one of `pink`, `blue`, `red`, `green`, `yellow`, `purple`, `white`
727
736
 
737
+ ### mineflayer.Particle
738
+
739
+ #### Particle.id
740
+
741
+ Particle ID, as defined in the [protocol](https://wiki.vg/Protocol#Particle)
742
+
743
+ #### Particle.name
744
+
745
+ Particle Name, as defined in the [protocol](https://wiki.vg/Protocol#Particle)
746
+
747
+ #### Particle.position
748
+
749
+ Vec3 instance of where the particle was created
750
+
751
+ #### Particle.offset
752
+
753
+ Vec3 instance of the particle's offset
754
+
755
+ #### Particle.longDistanceRender
756
+
757
+ Determines whether or not to force the rendering of a particle despite client particle settings and increases maximum view distance from 256 to 65536
758
+
759
+ #### Particle.count
760
+
761
+ Amount of particles created
762
+
763
+ #### Particle.movementSpeed
764
+
765
+ Particle speed in a random direction
766
+
728
767
  ## Bot
729
768
 
730
769
  ### mineflayer.createBot(options)
@@ -1117,7 +1156,8 @@ Emitted for every server message which appears on the Action Bar.
1117
1156
 
1118
1157
  Emitted for every server message, including chats.
1119
1158
 
1120
- * `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
1121
1161
 
1122
1162
  * `position` - (>= 1.8.1): position of Chat message can be
1123
1163
  * chat
@@ -1130,7 +1170,7 @@ Emitted for every server message, including chats.
1130
1170
 
1131
1171
  #### "messagestr" (message, messagePosition, jsonMsg, sender, verified)
1132
1172
 
1133
- 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.
1134
1174
 
1135
1175
  * `sender` - UUID of sender if known (1.16+), else null
1136
1176
 
@@ -1465,6 +1505,10 @@ Fires every tick if bot.physicsEnabled is set to true.
1465
1505
 
1466
1506
  Fires when the all of a chat pattern's regexs have matches
1467
1507
 
1508
+ #### "particle"
1509
+
1510
+ Fires when a particle is created
1511
+
1468
1512
  ### Functions
1469
1513
 
1470
1514
  #### bot.blockAt(point, extraInfos=true)
@@ -17,7 +17,7 @@ Crea bots para Minecraft con una API de JavaScript potente, estable y de alto ni
17
17
 
18
18
  ## Características
19
19
 
20
- * Soporta Minecraft 1.8, 1.9, 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17 y 1.18.
20
+ * Soporta Minecraft 1.8, 1.9, 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18 y 1.19.
21
21
  * Rastreo e información de entidades.
22
22
  * Información sobre bloques. Puedes solicitar información de todo lo que te rodea. Encuentra bloques en milisegundos
23
23
  * Físicas y movimientos básicos - maneja todos los cuadros de colisión
@@ -0,0 +1,182 @@
1
+ ## FAQ
2
+
3
+ Ce document de foire aux questions a pour but d'aider les gens pour les choses les plus courantes.
4
+
5
+ ### Je reçois une erreur lorsque j'essaie de me connecter avec un compte Microsoft.
6
+
7
+ Assurez-vous que l'email que vous avez entré dans l'option username de createBot peut être utilisé pour vous connecter à `minecraft.net` en utilisant le bouton 'Login with Microsoft'.
8
+ Assurez-vous que vous avez l'option `auth : 'microsoft'` dans vos options createBot.
9
+
10
+ Lorsque vous obtenez une erreur qui dit quelque chose au sujet des informations d'identification invalides ou "Ce compte possède Minecraft ?", essayez de supprimer le champ du mot de passe dans les options `createBot` et réessayez.
11
+
12
+ ### Comment masquer les erreurs ?
13
+
14
+ Utiliser `hideErrors : true` dans les options de createBot
15
+ Vous pouvez également choisir d'ajouter ces listeners :
16
+
17
+ ```js
18
+ client.on('error', () => {})
19
+ client.on('end', () => {})
20
+ ```
21
+
22
+ ### Je ne reçois pas d'événement de chat sur un serveur personnalisé, comment puis-je résoudre ce problème ?
23
+
24
+ Les serveurs Spigot, en particulier certains plugins, utilisent des formats de chat personnalisés, vous devez les analyser avec une expression rationnelle / un analyseur syntaxique personnalisé.
25
+ Lisez et adaptez [chat_parsing.js](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chat_parsing.js) pour qu'il fonctionne pour vos besoins particuliers.
26
+ plugin de chat. A lire également <http://mineflayer.prismarine.js.org/#/tutorial?id=custom-chat>
27
+
28
+ ### Comment puis-je collecter les informations d'un plugin personnalisé dans le chat ?
29
+
30
+ La plupart des serveurs Minecraft personnalisés ont le support des plugins, et beaucoup de ces plugins disent quelque chose dans le chat quand quelque chose se passe. Si c'est juste un message, il est préférable d'utiliser la solution discutée dans la solution ci-dessus, mais quand ces messages sont divisés en plusieurs petits messages, une autre option est d'utiliser l'événement `"messagestr"` car il permet d'analyser facilement les messages de plusieurs lignes.
31
+
32
+ **Exemple:**
33
+
34
+ Le message du chat dans le chat ressemble à ceci :
35
+
36
+ ```
37
+ (!) U9G has won the /jackpot and received
38
+ $26,418,402,450! They purchased 2,350,000 (76.32%) ticket(s) out of the
39
+ 3,079,185 ticket(s) sold!
40
+ ```
41
+
42
+ ```js
43
+ const regex = {
44
+ first: /\(!\) (.+) has won the \/jackpot and received +/,
45
+ second: /\$(.+)! They purchased (.+) \((.+)%\) ticket\(s\) out of the /,
46
+ third: /(.+) ticket\(s\) sold!/
47
+ }
48
+
49
+ let jackpot = {}
50
+ bot.on('messagestr', msg => {
51
+ if (regex.first.test(msg)) {
52
+ const username = msg.match(regex.first)[1]
53
+ jackpot.username = username
54
+ } else if (regex.second.test(msg)) {
55
+ const [, moneyWon, boughtTickets, winPercent] = msg.match(regex.second)
56
+ jackpot.moneyWon = parseInt(moneyWon.replace(/,/g, ''))
57
+ jackpot.boughtTickets = parseInt(boughtTickets.replace(/,/g, ''))
58
+ jackpot.winPercent = parseFloat(winPercent)
59
+ } else if (regex.third.test(msg)) {
60
+ const totalTickets = msg.match(regex.third)[1]
61
+ jackpot.totalTickets = parseInt(totalTickets.replace(/,/g, ''))
62
+ onDone(jackpot)
63
+ jackpot = {}
64
+ }
65
+ })
66
+ ```
67
+
68
+ ### Comment puis-je envoyer une commande ?
69
+
70
+ En utilisant `bot.chat()`.
71
+
72
+ **Example:**
73
+
74
+ ```js
75
+ bot.chat('/give @p diamond')
76
+ ```
77
+
78
+ ### Est-il possible de se connecter à plusieurs comptes en utilisant bot = mineflayer.createbot tout en les contrôlant tous séparément ?
79
+
80
+ Créer différentes instances de bot en appelant createBot puis faire différentes choses pour chacune, voir multiple.js
81
+
82
+ ### Comment faire pour que le robot lâche tout son inventaire ?
83
+
84
+ bot.inventory.items() renvoie un tableau des objets du bot. Vous pouvez utiliser une fonction récursive pour les parcourir en boucle et déposer chaque objet en utilisant bot.toss(). Cliquez [ici](https://gist.github.com/dada513/3d88f772be4224b40f9e5d1787bd63e9) pour voir un exemple.
85
+
86
+ ### Comment vérifier les paquets qui sont envoyés/reçus ?
87
+
88
+ Activation du mode de débogage <https://github.com/PrismarineJS/mineflayer#debug>
89
+
90
+ ### Je veux éviter la déconnexion même en cas de lag du serveur, comment puis-je y parvenir ?
91
+
92
+ Un moyen est d'augmenter l'option [checkTimeoutInterval](https://github.com/PrismarineJS/node-minecraft-protocol/blob/master/docs/API.md#mccreateclientoptions) (à définir dans createBot) à une valeur plus élevée (par exemple `300*1000` qui est 5min au lieu des 30s par défaut). Si vous êtes toujours déconnecté, vous pouvez vous reconnecter automatiquement en utilisant quelque chose comme cet exemple <https://github.com/PrismarineJS/mineflayer/blob/master/examples/reconnector.js>
93
+
94
+ ### Comment obtenir l'histoire / le texte d'un objet ?
95
+
96
+ Vous pouvez utiliser la propriété `item.nbt`. Il est également recommandé d'utiliser la bibliothèque `prismarine-nbt`. La méthode `nbt.simplify()` peut être utile.
97
+
98
+ **Exemple:**
99
+
100
+ ```js
101
+ function getLore (item) {
102
+ let message = ''
103
+ if (item.nbt == null) return message
104
+
105
+ const nbt = require('prismarine-nbt')
106
+ const ChatMessage = require('prismarine-chat')(bot.version)
107
+
108
+ const data = nbt.simplify(item.nbt)
109
+ const display = data.display
110
+ if (display == null) return message
111
+
112
+ const lore = display.Lore
113
+ if (lore == null) return message
114
+ for (const line of lore) {
115
+ message += new ChatMessage(line).toString()
116
+ message += '\n'
117
+ }
118
+
119
+ return message
120
+ }
121
+ ```
122
+
123
+ ### Comment puis-je envoyer un message de la console au serveur ?
124
+
125
+ You can use a library like `repl` to read the console input and use `bot.chat()` to send it. You can find an example [here.](https://github.com/PrismarineJS/mineflayer/blob/master/examples/repl.js)
126
+
127
+ ### Lors de la création d'un plugin, comment puis-je spécifier un autre plugin comme dépendance ?
128
+
129
+ Dans la fonction `inject()` de votre plugin, vous pouvez appeler sans risque `bot.loadPlugin(anotherPlugin)` pour vous assurer que ce plugin est chargé. Si le plugin a déjà été chargé auparavant, rien ne se passe.
130
+
131
+ Notez que l'ordre dans lequel les plugins sont chargés est dynamique, donc vous ne devriez jamais appeler un autre plugin dans votre fonction `inject()`.
132
+
133
+ ### Comment puis-je utiliser un proxy socks5 ?
134
+
135
+ In the options object for `mineflayer.createBot(options)`, remove your `host` option from the options object, have the following variables declared `PROXY_IP, PROXY_PORT, PROXY_USERNAME, PROXY_PASSWORD, MC_SERVER_ADDRESS, MC_SERVER_PORT` and add this to your options object:
136
+
137
+ ```js
138
+ connect: (client) => {
139
+ socks.createConnection({
140
+ proxy: {
141
+ host: PROXY_IP,
142
+ port: PROXY_PORT,
143
+ type: 5,
144
+ userId: PROXY_USERNAME,
145
+ password: PROXY_PASSWORD
146
+ },
147
+ command: 'connect',
148
+ destination: {
149
+ host: MC_SERVER_ADDRESS,
150
+ port: MC_SERVER_PORT
151
+ }
152
+ }, (err, info) => {
153
+ if (err) {
154
+ console.log(err)
155
+ return
156
+ }
157
+ client.setSocket(info.socket)
158
+ client.emit('connect')
159
+ })
160
+ }
161
+ ```
162
+
163
+ `socks` est déclaré avec `const socks = require('socks').SocksClient` et utilise le paquet [this](https://www.npmjs.com/package/socks).
164
+ Certains serveurs peuvent rejeter la connexion. Si cela se produit, essayez d'ajouter `fakeHost : MC_SERVER_ADDRESS` aux options de votre createBot.
165
+
166
+ # Erreurs courantes
167
+
168
+ ### `UnhandledPromiseRejectionWarning: Error: Failed to read asymmetric key`
169
+
170
+ Voici ce qui se passe lorsque vous avez donné à Mineflayer la mauvaise version du serveur, ou que Mineflayer détecte la mauvaise version du serveur.
171
+
172
+ ### `TypeError: Cannot read property '?' of undefined`
173
+
174
+ Vous essayez peut-être d'utiliser quelque chose sur l'objet bot qui n'existe pas encore, essayez d'appeler l'instruction après l'événement `spawn`.
175
+
176
+ ### `SyntaxError: Unexpected token '?'`
177
+
178
+ Mettez à jour la version de votre node.
179
+
180
+ ### The bot can't break/place blocks or open chests
181
+
182
+ Vérifiez que la protection contre le spawn n'empêche pas le bot d'agir.
package/docs/history.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## 4.7.0
2
+
3
+ * 1.19.2 support (@frej4189)
4
+
5
+ ## 4.6.0
6
+
7
+ * Fix unhandled promise rejection in onceWithCleanup (@IceTank) [#2833](https://github.com/PrismarineJS/mineflayer/pull/2833)
8
+ * Extend every window that is opened with mineflayer specific window functions (@IceTank) [#2768][https://github.com/PrismarineJS/mineflayer/pull/2768]
9
+ * Fix example command line usage messages (@maximmasiutin) [#2853](https://github.com/PrismarineJS/mineflayer/pull/2853)
10
+ * Update README_ES.md (@PanIntegralus) [#2803](https://github.com/PrismarineJS/mineflayer/pull/2803)
11
+ * Fix block face position target when digging (@WhoTho) [#2801](https://github.com/PrismarineJS/mineflayer/pull/2801)
12
+ * Add a native mineflayer event for particles (@NyxaYu) [#2813](https://github.com/PrismarineJS/mineflayer/pull/2813)
13
+ * Fix viewDistance type (@Nciklol) [#2824](Fix viewDistance type (#2824) )
14
+ * Add French FAQ (@AugustinMauroy) [#2817](https://github.com/PrismarineJS/mineflayer/pull/2817)
15
+
1
16
  ## 4.5.1
2
17
 
3
18
  * Fixed syntax error in TypeScript definitions (@JungleDome) [commit](https://github.com/PrismarineJS/mineflayer/commit/2c6a4036d84bedb5f349ea5a82d743e344c34224)
package/examples/anvil.js CHANGED
@@ -18,7 +18,7 @@
18
18
  const mineflayer = require('mineflayer')
19
19
 
20
20
  if (process.argv.length < 4 || process.argv.length > 6) {
21
- console.log('Usage : node use_anvil.js <host> <port> [<name>] [<password>]')
21
+ console.log('Usage : node anvil.js <host> <port> [<name>] [<password>]')
22
22
  process.exit(1)
23
23
  }
24
24
 
@@ -6,12 +6,7 @@ const pathfinder = require('mineflayer-pathfinder').pathfinder
6
6
  const collectBlock = require('mineflayer-collectblock').plugin
7
7
 
8
8
  if (process.argv.length < 4 || process.argv.length > 6) {
9
- console.log('Usage : node collector.js <host> <port> [<name>] [<password>]')
10
- process.exit(1)
11
- }
12
-
13
- if (process.argv.length < 4 || process.argv.length > 6) {
14
- console.log('Usage : node collectBlock.js <host> <port> [<name>] [<password>]')
9
+ console.log('Usage : node collectblock.js <host> <port> [<name>] [<password>]')
15
10
  process.exit(1)
16
11
  }
17
12
 
@@ -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])
@@ -5,7 +5,7 @@
5
5
  const mineflayer = require('mineflayer')
6
6
 
7
7
  if (process.argv.length < 4 || process.argv.length > 6) {
8
- console.log('Usage : node echo.js <host> <port> [<name>] [<password>]')
8
+ console.log('Usage : node looker.js <host> <port> [<name>] [<password>]')
9
9
  process.exit(1)
10
10
  }
11
11
 
@@ -7,7 +7,7 @@
7
7
  const mineflayer = require('mineflayer')
8
8
 
9
9
  if (process.argv.length < 4 || process.argv.length > 6) {
10
- console.log('Usage : node jumper.js <host> <port> [<name>] [<password>]')
10
+ console.log('Usage : node skin_blinker.js <host> <port> [<name>] [<password>]')
11
11
  process.exit(1)
12
12
  }
13
13
 
@@ -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
@@ -30,7 +31,7 @@ export interface BotOptions extends ClientOptions {
30
31
  }
31
32
 
32
33
  export type ChatLevel = 'enabled' | 'commandsOnly' | 'disabled'
33
- export type ViewDistance = 'far' | 'normal' | 'short' | 'tiny'
34
+ export type ViewDistance = 'far' | 'normal' | 'short' | 'tiny' | number
34
35
  export type MainHands = 'left' | 'right'
35
36
 
36
37
  export interface PluginOptions {
@@ -151,6 +152,7 @@ interface BotEvents {
151
152
  bossBarDeleted: (bossBar: BossBar) => Promise<void> | void
152
153
  bossBarUpdated: (bossBar: BossBar) => Promise<void> | void
153
154
  resourcePack: (url: string, hash: string) => Promise<void> | void
155
+ particle: (particle: Particle) => Promise<void> | void
154
156
  }
155
157
 
156
158
  export interface Bot extends TypedEmitter<BotEvents> {
@@ -191,6 +193,7 @@ export interface Bot extends TypedEmitter<BotEvents> {
191
193
  currentWindow: Window | null
192
194
  simpleClick: simpleClick
193
195
  tablist: Tablist
196
+ registry: Registry
194
197
 
195
198
  connect: (options: BotOptions) => void
196
199
 
@@ -826,6 +829,26 @@ export class BossBar {
826
829
  );
827
830
  }
828
831
 
832
+ export class Particle {
833
+ id: number
834
+ name: string
835
+ position: Vec3
836
+ offset: Vec3
837
+ count: number
838
+ movementSpeed: number
839
+ longDistanceRender: boolean
840
+ static fromNetwork(packet: Object): Particle
841
+
842
+ constructor (
843
+ id: number,
844
+ position: Vec3,
845
+ offset: Vec3,
846
+ count?: number,
847
+ movementSpeed?: number,
848
+ longDistanceRender?: boolean
849
+ );
850
+ }
851
+
829
852
  export let supportedVersions: string[]
830
853
  export let testedVersions: string[]
831
854
 
package/lib/loader.js CHANGED
@@ -41,7 +41,8 @@ const plugins = {
41
41
  villager: require('./plugins/villager'),
42
42
  anvil: require('./plugins/anvil'),
43
43
  place_entity: require('./plugins/place_entity'),
44
- generic_place: require('./plugins/generic_place')
44
+ generic_place: require('./plugins/generic_place'),
45
+ particle: require('./plugins/particle')
45
46
  }
46
47
 
47
48
  const supportedVersions = require('./version').supportedVersions
@@ -53,6 +54,7 @@ module.exports = {
53
54
  Painting: require('./painting'),
54
55
  ScoreBoard: require('./scoreboard'),
55
56
  BossBar: require('./bossbar'),
57
+ Particle: require('./particle'),
56
58
  supportedVersions,
57
59
  testedVersions,
58
60
  supportFeature: (feature, version) => require('prismarine-registry')(version).supportFeature(feature)
@@ -0,0 +1,30 @@
1
+ const { Vec3 } = require('vec3')
2
+
3
+ module.exports = loader
4
+
5
+ function loader (registry) {
6
+ class Particle {
7
+ constructor (id, position, offset, count = 1, movementSpeed = 0, longDistanceRender = false) {
8
+ Object.assign(this, registry.particles[id])
9
+ this.id = id
10
+ this.position = position
11
+ this.offset = offset
12
+ this.count = count
13
+ this.movementSpeed = movementSpeed
14
+ this.longDistanceRender = longDistanceRender
15
+ }
16
+
17
+ static fromNetwork (packet) {
18
+ return new Particle(
19
+ packet.particleId,
20
+ new Vec3(packet.x, packet.y, packet.z),
21
+ new Vec3(packet.offsetX, packet.offsetY, packet.offsetZ),
22
+ packet.particles,
23
+ packet.particleData,
24
+ packet.longDistance
25
+ )
26
+ }
27
+ }
28
+
29
+ return Particle
30
+ }
@@ -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,49 @@ 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
+ let sender
117
+
118
+ try {
119
+ sender = JSON.parse(data.senderName)
120
+ } catch {
121
+ sender = {
122
+ insertion: data.senderName,
123
+ clickEvent: { action: 'suggest_command', value: `/tell ${data.senderName} ` },
124
+ hoverEvent: { action: 'show_entity', contents: { id: bot.findPlayer(data.senderName).id, name: data.senderName } },
125
+ text: data.senderName
126
+ }
127
+ }
124
128
 
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)
129
+ const parameters = {
130
+ sender,
131
+ content: message ? JSON.parse(message) : { text: data.plainMessage }
132
+ }
133
+ msg = ChatMessage.fromNetwork(data.type, parameters)
134
+
135
+ if (data.unsignedContent) {
136
+ msg.unsigned = ChatMessage.fromNetwork(data.type, { sender, content: JSON.parse(data.unsignedContent) })
137
+ }
138
+ } else {
139
+ msg = ChatMessage.fromNotch(data.formattedMessage)
137
140
  }
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)
141
+ bot.emit('message', msg, 'chat', data.sender, verified)
142
+ bot.emit('messagestr', msg.toString(), 'chat', msg, data.sender, verified)
142
143
  })
143
144
 
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)
145
+ bot._client.on('systemChat', (data) => {
146
+ const msg = ChatMessage.fromNotch(data.formattedMessage)
147
+ const chatPositions = {
148
+ 1: 'system',
149
+ 2: 'game_info'
150
+ }
151
+ bot.emit('message', msg, chatPositions[data.positionid], null)
152
+ bot.emit('messagestr', msg.toString(), chatPositions[data.positionid], msg, null)
153
+ if (data.positionid === 2) bot.emit('actionBar', msg, null)
148
154
  })
149
155
 
150
156
  function chatWithHeader (header, message) {
@@ -163,7 +169,9 @@ function inject (bot, options) {
163
169
  timestamp,
164
170
  salt: 0n,
165
171
  argumentSignatures: [],
166
- signedPreview: false
172
+ signedPreview: false,
173
+ // 1.19.2 Chat Command packet also includes an array of last seen messages
174
+ previousMessages: []
167
175
  })
168
176
  return
169
177
  }
@@ -176,17 +184,7 @@ function inject (bot, options) {
176
184
  let smallMsg
177
185
  for (i = 0; i < subMessage.length; i += lengthLimit) {
178
186
  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
- }
187
+ bot._client.chat(smallMsg)
190
188
  }
191
189
  })
192
190
  }
@@ -36,15 +36,17 @@ function inject (bot) {
36
36
  } else if (digFace.z) {
37
37
  diggingFace = digFace.z > 0 ? BlockFaces.SOUTH : BlockFaces.NORTH
38
38
  }
39
- await bot.lookAt(block.position.offset(0.5, 0.5, 0.5).offset(digFace.x * 0.5, digFace.y * 0.5, digFace.z * 0.5), forceLook)
39
+ await bot.lookAt(
40
+ block.position.offset(0.5, 0.5, 0.5).offset(digFace.x * 0.5, digFace.y * 0.5, digFace.z * 0.5),
41
+ forceLook
42
+ )
40
43
  } else if (digFace === 'raycast') {
41
44
  // Check faces that could be seen from the current position. If the delta is smaller then 0.5 that means the
42
45
  // bot cam most likely not see the face as the block is 1 block thick
43
46
  // this could be false for blocks that have a smaller bounding box then 1x1x1
44
- const dx = bot.entity.position.x - block.position.x + 0.5
45
- const dy = bot.entity.position.y - block.position.y - 0.5 + bot.entity.height // -0.5 because the bot position
46
- // is calculated from the block position that is inside its feet so 0.5 - 1 = -0.5
47
- const dz = bot.entity.position.z - block.position.z + 0.5
47
+ const dx = bot.entity.position.x - (block.position.x + 0.5)
48
+ const dy = bot.entity.position.y + bot.entity.height - (block.position.y + 0.5)
49
+ const dz = bot.entity.position.z - (block.position.z + 0.5)
48
50
  // Check y first then x and z
49
51
  const visibleFaces = {
50
52
  y: Math.sign(Math.abs(dy) > 0.5 ? dy : 0),
@@ -55,12 +57,20 @@ function inject (bot) {
55
57
  for (const i in visibleFaces) {
56
58
  if (!visibleFaces[i]) continue // skip as this face is not visible
57
59
  // target position on the target block face. -> 0.5 + (current face) * 0.5
58
- const targetPos = block.position.offset(0.5 + (i === 'x' ? visibleFaces[i] * 0.5 : 0), 0.5 + (i === 'y' ? visibleFaces[i] * 0.5 : 0), 0.5 + (i === 'z' ? visibleFaces[i] * 0.5 : 0))
60
+ const targetPos = block.position.offset(
61
+ 0.5 + (i === 'x' ? visibleFaces[i] * 0.5 : 0),
62
+ 0.5 + (i === 'y' ? visibleFaces[i] * 0.5 : 0),
63
+ 0.5 + (i === 'z' ? visibleFaces[i] * 0.5 : 0)
64
+ )
59
65
  const startPos = bot.entity.position.offset(0, bot.entity.height, 0)
60
66
  const rayBlock = bot.world.raycast(startPos, targetPos.clone().subtract(startPos).normalize(), 5)
61
67
  if (rayBlock) {
62
68
  const rayPos = rayBlock.position
63
- if (rayPos.x === block.position.x && rayPos.y === block.position.y && rayPos.z === block.position.z) {
69
+ if (
70
+ rayPos.x === block.position.x &&
71
+ rayPos.y === block.position.y &&
72
+ rayPos.z === block.position.z
73
+ ) {
64
74
  // console.info(rayBlock)
65
75
  validFaces.push({
66
76
  face: rayBlock.face,
@@ -75,7 +85,9 @@ function inject (bot) {
75
85
  let distSqrt = 999
76
86
  for (const i in validFaces) {
77
87
  const tPos = validFaces[i].targetPos
78
- const cDist = new Vec3(tPos.x, tPos.y, tPos.z).distanceSquared(bot.entity.position.offset(0, bot.entity.height, 0))
88
+ const cDist = new Vec3(tPos.x, tPos.y, tPos.z).distanceSquared(
89
+ bot.entity.position.offset(0, bot.entity.height, 0)
90
+ )
79
91
  if (distSqrt > cDist) {
80
92
  closest = validFaces[i]
81
93
  distSqrt = cDist
@@ -172,7 +184,11 @@ function inject (bot) {
172
184
  })
173
185
 
174
186
  function canDigBlock (block) {
175
- return block && block.diggable && block.position.offset(0.5, 0.5, 0.5).distanceTo(bot.entity.position.offset(0, 1.65, 0)) <= 5.1
187
+ return (
188
+ block &&
189
+ block.diggable &&
190
+ block.position.offset(0.5, 0.5, 0.5).distanceTo(bot.entity.position.offset(0, 1.65, 0)) <= 5.1
191
+ )
176
192
  }
177
193
 
178
194
  function digTime (block) {
@@ -195,7 +211,14 @@ function inject (bot) {
195
211
  }
196
212
 
197
213
  const creative = bot.game.gameMode === 'creative'
198
- return block.digTime(type, creative, bot.entity.isInWater, !bot.entity.onGround, enchantments, bot.entity.effects)
214
+ return block.digTime(
215
+ type,
216
+ creative,
217
+ bot.entity.isInWater,
218
+ !bot.entity.onGround,
219
+ enchantments,
220
+ bot.entity.effects
221
+ )
199
222
  }
200
223
 
201
224
  bot.dig = dig
@@ -588,6 +588,7 @@ function inject (bot, { hideErrors }) {
588
588
  if (!windowItems || window.id !== windowItems.windowId) {
589
589
  // don't emit windowOpen until we have the slot data
590
590
  bot.once(`setWindowItems:${window.id}`, () => {
591
+ extendWindow(window)
591
592
  bot.emit('windowOpen', window)
592
593
  })
593
594
  } else {
@@ -596,6 +597,7 @@ function inject (bot, { hideErrors }) {
596
597
  window.updateSlot(i, item)
597
598
  }
598
599
  updateHeldItem()
600
+ extendWindow(window)
599
601
  bot.emit('windowOpen', window)
600
602
  }
601
603
  }
@@ -0,0 +1,9 @@
1
+ module.exports = inject
2
+
3
+ function inject (bot, { version }) {
4
+ const Particle = require('../particle')(bot.registry)
5
+
6
+ bot._client.on('world_particles', (packet) => {
7
+ bot.emit('particle', Particle.fromNetwork(packet))
8
+ })
9
+ }
@@ -67,7 +67,7 @@ function onceWithCleanup (emitter, event, { timeout = 0, checkCondition = undefi
67
67
  })
68
68
  }
69
69
 
70
- task.promise.finally(() => emitter.removeListener(event, onEvent))
70
+ task.promise.catch(() => {}).finally(() => emitter.removeListener(event, onEvent))
71
71
 
72
72
  return task.promise
73
73
  }
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']
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.5.1",
3
+ "version": "4.7.0",
4
4
  "description": "create minecraft bots with a stable, high level API",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -22,7 +22,7 @@
22
22
  "license": "MIT",
23
23
  "dependencies": {
24
24
  "minecraft-data": "^3.15.2",
25
- "minecraft-protocol": "^1.36.0",
25
+ "minecraft-protocol": "^1.38.1",
26
26
  "prismarine-biome": "^1.1.1",
27
27
  "prismarine-block": "^1.13.1",
28
28
  "prismarine-chat": "^1.7.1",