mineflayer 4.8.0 → 4.9.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.
@@ -35,6 +35,8 @@ jobs:
35
35
  mcVersion: '1.19.2'
36
36
  - javaVersion: 17
37
37
  mcVersion: '1.19.3'
38
+ - javaVersion: 17
39
+ mcVersion: '1.19.4'
38
40
  fail-fast: false
39
41
 
40
42
  steps:
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Mineflayer
2
2
 
3
3
  [![NPM version](https://img.shields.io/npm/v/mineflayer.svg?color=success&label=npm%20package&logo=npm)](https://www.npmjs.com/package/mineflayer)
4
- [![Build Status](https://img.shields.io/github/workflow/status/PrismarineJS/mineflayer/CI.svg?label=CI&logo=github&logoColor=lightgrey)](https://github.com/PrismarineJS/mineflayer/actions?query=workflow%3A%22CI%22)
4
+ [![Build Status](https://img.shields.io/github/actions/workflow/status/PrismarineJS/mineflayer/ci.yml.svg?label=CI&logo=github&logoColor=lightgrey)](https://github.com/PrismarineJS/mineflayer/actions?query=workflow%3A%22CI%22)
5
5
  [![Try it on gitpod](https://img.shields.io/static/v1.svg?label=try&message=on%20gitpod&color=brightgreen&logo=gitpod)](https://gitpod.io/#https://github.com/PrismarineJS/mineflayer)
6
6
  [![Open In Colab](https://img.shields.io/static/v1.svg?label=open&message=on%20colab&color=blue&logo=google-colab)](https://colab.research.google.com/github/PrismarineJS/mineflayer/blob/master/docs/mineflayer.ipynb)
7
7
  [![GitHub Sponsors](https://img.shields.io/github/sponsors/PrismarineJS)](https://github.com/sponsors/PrismarineJS)
@@ -39,13 +39,15 @@ First install Node.js >= 14 from [nodejs.org](https://nodejs.org/) then:
39
39
 
40
40
  `npm install mineflayer`
41
41
 
42
+ To update mineflayer (or any Node.js) package and its dependencies, use `npm update --depth 9999`
43
+
42
44
  ## Documentation
43
45
 
44
46
  | link | description |
45
47
  |---|---|
46
48
  |[tutorial](tutorial.md) | Begin with Node.js and mineflayer |
47
49
  | [FAQ.md](FAQ.md) | Got a question ? go there first |
48
- | [api.md](api.md) [unstable_api.md](unstable_api.md) | The full API reference |
50
+ | **[api.md](api.md)** <br/>[unstable_api.md](unstable_api.md) | The full API reference |
49
51
  | [history.md](history.md) | The changelog for mineflayer |
50
52
  | [examples/](https://github.com/PrismarineJS/mineflayer/tree/master/examples) | Checkout all the mineflayer examples |
51
53
 
@@ -79,10 +81,10 @@ const mineflayer = require('mineflayer')
79
81
  const bot = mineflayer.createBot({
80
82
  host: 'localhost', // minecraft server ip
81
83
  username: 'email@example.com', // minecraft username
82
- password: '12345678' // minecraft password, comment out if you want to log into online-mode=false servers
84
+ auth: 'microsoft' // for offline mode servers, you can set this to 'offline'
83
85
  // port: 25565, // only set if you need a port that isn't 25565
84
86
  // version: false, // only set if you need a specific version or snapshot (ie: "1.8.9" or "1.16.5"), otherwise it's set automatically
85
- // auth: 'mojang' // only set if you need microsoft auth, then set this to 'microsoft'
87
+ // password: '12345678' // set if you want to use password-based auth (may be unreliable)
86
88
  })
87
89
 
88
90
  bot.on('chat', (username, message) => {
@@ -107,7 +109,7 @@ bot.once('spawn', () => {
107
109
  ```
108
110
  And you'll get a *live* view looking like this:
109
111
 
110
- [<img src="https://prismarine.js.org/prismarine-viewer/test_1.16.1.png" alt="viewer" width="500">](https://prismarine.js.org/prismarine-viewer/)
112
+ [<img src="https://prismarinejs.github.io/prismarine-viewer/test_1.16.1.png" alt="viewer" width="500">](https://prismarinejs.github.io/prismarine-viewer/)
111
113
 
112
114
  #### More Examples
113
115
 
@@ -123,7 +125,7 @@ And you'll get a *live* view looking like this:
123
125
  |[guard](https://github.com/PrismarineJS/mineflayer/blob/master/examples/guard.js) | Make a bot guard a defined area from nearby mobs |
124
126
  |[multiple-from-file](https://github.com/PrismarineJS/mineflayer/blob/master/examples/multiple_from_file.js) | Add a text file with accounts and have them all login |
125
127
 
126
- And many mores in the [examples](https://github.com/PrismarineJS/mineflayer/tree/master/examples) folder
128
+ And many more in the [examples](https://github.com/PrismarineJS/mineflayer/tree/master/examples) folder.
127
129
 
128
130
  ### Modules
129
131
 
@@ -180,19 +182,18 @@ The most updated and useful are :
180
182
  * [pathfinder](https://github.com/Karang/mineflayer-pathfinder) - advanced A* pathfinding with a lot of configurable features
181
183
  * [prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer) - simple web chunk viewer
182
184
  * [web-inventory](https://github.com/ImHarvol/mineflayer-web-inventory) - web based inventory viewer
183
- * [statemachine](https://github.com/TheDudeFromCI/mineflayer-statemachine) - A state machine API for more complex bot behaviors
185
+ * [statemachine](https://github.com/PrismarineJS/mineflayer-statemachine) - A state machine API for more complex bot behaviors
184
186
  * [Armor Manager](https://github.com/G07cha/MineflayerArmorManager) - automatic armor management
185
- * [Collect Block](https://github.com/TheDudeFromCI/mineflayer-collectblock) - Quick and simple block collection API.
186
187
  * [Dashboard](https://github.com/wvffle/mineflayer-dashboard) - Frontend dashboard for mineflayer bot
187
- * [PVP](https://github.com/TheDudeFromCI/mineflayer-pvp) - Easy API for basic PVP and PVE.
188
+ * [PVP](https://github.com/PrismarineJS/mineflayer-pvp) - Easy API for basic PVP and PVE.
188
189
  * [Auto Eat](https://github.com/link-discord/mineflayer-auto-eat) - Automatic eating of food.
189
190
  * [Auto Crystal](https://github.com/link-discord/mineflayer-autocrystal) - Automatic placing & breaking of end crystals.
190
191
  * [Tool](https://github.com/TheDudeFromCI/mineflayer-tool) - A utility for automatic tool/weapon selection with a high level API.
191
192
  * [Hawkeye](https://github.com/sefirosweb/minecraftHawkEye) - A utility for using auto-aim with bows.
192
193
  * [GUI](https://github.com/firejoust/mineflayer-GUI) - Interact with nested GUI windows using async/await
193
194
  * [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
195
-
195
+ * [Movement](https://github.com/firejoust/mineflayer-movement) - Smooth and realistic player movement, best suited for PvP
196
+ * [Collect Block](https://github.com/PrismarineJS/mineflayer-collectblock) - Quick and simple block collection API.
196
197
 
197
198
  But also check out :
198
199
 
@@ -206,6 +207,7 @@ The most updated and useful are :
206
207
 
207
208
  ## Projects Using Mineflayer
208
209
 
210
+ * [Voyager](https://github.com/MineDojo/Voyager) An Open-Ended Embodied Agent with Large Language Models
209
211
  * [rom1504/rbot](https://github.com/rom1504/rbot)
210
212
  - [YouTube - building a spiral staircase](https://www.youtube.com/watch?v=UM1ZV5200S0)
211
213
  - [YouTube - replicating a building](https://www.youtube.com/watch?v=0cQxg9uDnzA)
@@ -213,7 +215,7 @@ The most updated and useful are :
213
215
  * [vogonistic/voxel](https://github.com/vogonistic/mineflayer-voxel) - visualize what
214
216
  the bot is up to using voxel.js
215
217
  * [JonnyD/Skynet](https://github.com/JonnyD/Skynet) - log player activity onto an online API
216
- * [MinecraftChat](https://github.com/rom1504/MinecraftChat) (last open source version, built by AlexKvazos) - Minecraft web based chat client <https://minecraftchat.net/>
218
+ * [MinecraftChat](https://github.com/rom1504/MinecraftChat) (last open source version, built by AlexKvazos) - Minecraft web based chat client
217
219
  * [Cheese Bot](https://github.com/Minecheesecraft/Cheese-Bot) - Plugin based bot with a clean GUI. Made with Node-Webkit.
218
220
  * [Chaoscraft](https://github.com/schematical/chaoscraft) - Minecraft bot using genetic algorithms, see [its youtube videos](https://www.youtube.com/playlist?list=PLLkpLgU9B5xJ7Qy4kOyBJl5J6zsDIMceH)
219
221
  * [hexatester/minetelegram](https://github.com/hexatester/minetelegram) - Minecraft - Telegram bridge, build on top of mineflayer & telegraf.
package/docs/FAQ.md CHANGED
@@ -22,7 +22,7 @@ client.on('end', () => {})
22
22
 
23
23
  Spigot servers, in particular some plugins, use custom chat formats, you need to parse it with a custom regex / parser.
24
24
  Read and adapt [chat_parsing.js](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chat_parsing.js) to make it work for your particular
25
- chat plugin. Also read http://mineflayer.prismarine.js.org/#/tutorial?id=custom-chat
25
+ chat plugin. Also read http://prismarinejs.github.io/mineflayer/#/tutorial?id=custom-chat
26
26
 
27
27
  ### How can I collect info from an custom plugin in chat ?
28
28
 
package/docs/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Mineflayer
2
2
 
3
3
  [![NPM version](https://img.shields.io/npm/v/mineflayer.svg?color=success&label=npm%20package&logo=npm)](https://www.npmjs.com/package/mineflayer)
4
- [![Build Status](https://img.shields.io/github/workflow/status/PrismarineJS/mineflayer/CI.svg?label=CI&logo=github&logoColor=lightgrey)](https://github.com/PrismarineJS/mineflayer/actions?query=workflow%3A%22CI%22)
4
+ [![Build Status](https://img.shields.io/github/actions/workflow/status/PrismarineJS/mineflayer/ci.yml.svg?label=CI&logo=github&logoColor=lightgrey)](https://github.com/PrismarineJS/mineflayer/actions?query=workflow%3A%22CI%22)
5
5
  [![Try it on gitpod](https://img.shields.io/static/v1.svg?label=try&message=on%20gitpod&color=brightgreen&logo=gitpod)](https://gitpod.io/#https://github.com/PrismarineJS/mineflayer)
6
6
  [![Open In Colab](https://img.shields.io/static/v1.svg?label=open&message=on%20colab&color=blue&logo=google-colab)](https://colab.research.google.com/github/PrismarineJS/mineflayer/blob/master/docs/mineflayer.ipynb)
7
7
  [![GitHub Sponsors](https://img.shields.io/github/sponsors/PrismarineJS)](https://github.com/sponsors/PrismarineJS)
@@ -39,13 +39,15 @@ First install Node.js >= 14 from [nodejs.org](https://nodejs.org/) then:
39
39
 
40
40
  `npm install mineflayer`
41
41
 
42
+ To update mineflayer (or any Node.js) package and its dependencies, use `npm update --depth 9999`
43
+
42
44
  ## Documentation
43
45
 
44
46
  | link | description |
45
47
  |---|---|
46
48
  |[tutorial](tutorial.md) | Begin with Node.js and mineflayer |
47
49
  | [FAQ.md](FAQ.md) | Got a question ? go there first |
48
- | [api.md](api.md) [unstable_api.md](unstable_api.md) | The full API reference |
50
+ | **[api.md](api.md)** <br/>[unstable_api.md](unstable_api.md) | The full API reference |
49
51
  | [history.md](history.md) | The changelog for mineflayer |
50
52
  | [examples/](https://github.com/PrismarineJS/mineflayer/tree/master/examples) | Checkout all the mineflayer examples |
51
53
 
@@ -79,10 +81,10 @@ const mineflayer = require('mineflayer')
79
81
  const bot = mineflayer.createBot({
80
82
  host: 'localhost', // minecraft server ip
81
83
  username: 'email@example.com', // minecraft username
82
- password: '12345678' // minecraft password, comment out if you want to log into online-mode=false servers
84
+ auth: 'microsoft' // for offline mode servers, you can set this to 'offline'
83
85
  // port: 25565, // only set if you need a port that isn't 25565
84
86
  // version: false, // only set if you need a specific version or snapshot (ie: "1.8.9" or "1.16.5"), otherwise it's set automatically
85
- // auth: 'mojang' // only set if you need microsoft auth, then set this to 'microsoft'
87
+ // password: '12345678' // set if you want to use password-based auth (may be unreliable)
86
88
  })
87
89
 
88
90
  bot.on('chat', (username, message) => {
@@ -107,7 +109,7 @@ bot.once('spawn', () => {
107
109
  ```
108
110
  And you'll get a *live* view looking like this:
109
111
 
110
- [<img src="https://prismarine.js.org/prismarine-viewer/test_1.16.1.png" alt="viewer" width="500">](https://prismarine.js.org/prismarine-viewer/)
112
+ [<img src="https://prismarinejs.github.io/prismarine-viewer/test_1.16.1.png" alt="viewer" width="500">](https://prismarinejs.github.io/prismarine-viewer/)
111
113
 
112
114
  #### More Examples
113
115
 
@@ -123,7 +125,7 @@ And you'll get a *live* view looking like this:
123
125
  |[guard](https://github.com/PrismarineJS/mineflayer/blob/master/examples/guard.js) | Make a bot guard a defined area from nearby mobs |
124
126
  |[multiple-from-file](https://github.com/PrismarineJS/mineflayer/blob/master/examples/multiple_from_file.js) | Add a text file with accounts and have them all login |
125
127
 
126
- And many mores in the [examples](https://github.com/PrismarineJS/mineflayer/tree/master/examples) folder
128
+ And many more in the [examples](https://github.com/PrismarineJS/mineflayer/tree/master/examples) folder.
127
129
 
128
130
  ### Modules
129
131
 
@@ -180,19 +182,18 @@ The most updated and useful are :
180
182
  * [pathfinder](https://github.com/Karang/mineflayer-pathfinder) - advanced A* pathfinding with a lot of configurable features
181
183
  * [prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer) - simple web chunk viewer
182
184
  * [web-inventory](https://github.com/ImHarvol/mineflayer-web-inventory) - web based inventory viewer
183
- * [statemachine](https://github.com/TheDudeFromCI/mineflayer-statemachine) - A state machine API for more complex bot behaviors
185
+ * [statemachine](https://github.com/PrismarineJS/mineflayer-statemachine) - A state machine API for more complex bot behaviors
184
186
  * [Armor Manager](https://github.com/G07cha/MineflayerArmorManager) - automatic armor management
185
- * [Collect Block](https://github.com/TheDudeFromCI/mineflayer-collectblock) - Quick and simple block collection API.
186
187
  * [Dashboard](https://github.com/wvffle/mineflayer-dashboard) - Frontend dashboard for mineflayer bot
187
- * [PVP](https://github.com/TheDudeFromCI/mineflayer-pvp) - Easy API for basic PVP and PVE.
188
+ * [PVP](https://github.com/PrismarineJS/mineflayer-pvp) - Easy API for basic PVP and PVE.
188
189
  * [Auto Eat](https://github.com/link-discord/mineflayer-auto-eat) - Automatic eating of food.
189
190
  * [Auto Crystal](https://github.com/link-discord/mineflayer-autocrystal) - Automatic placing & breaking of end crystals.
190
191
  * [Tool](https://github.com/TheDudeFromCI/mineflayer-tool) - A utility for automatic tool/weapon selection with a high level API.
191
192
  * [Hawkeye](https://github.com/sefirosweb/minecraftHawkEye) - A utility for using auto-aim with bows.
192
193
  * [GUI](https://github.com/firejoust/mineflayer-GUI) - Interact with nested GUI windows using async/await
193
194
  * [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
195
-
195
+ * [Movement](https://github.com/firejoust/mineflayer-movement) - Smooth and realistic player movement, best suited for PvP
196
+ * [Collect Block](https://github.com/PrismarineJS/mineflayer-collectblock) - Quick and simple block collection API.
196
197
 
197
198
  But also check out :
198
199
 
@@ -206,6 +207,7 @@ The most updated and useful are :
206
207
 
207
208
  ## Projects Using Mineflayer
208
209
 
210
+ * [Voyager](https://github.com/MineDojo/Voyager) An Open-Ended Embodied Agent with Large Language Models
209
211
  * [rom1504/rbot](https://github.com/rom1504/rbot)
210
212
  - [YouTube - building a spiral staircase](https://www.youtube.com/watch?v=UM1ZV5200S0)
211
213
  - [YouTube - replicating a building](https://www.youtube.com/watch?v=0cQxg9uDnzA)
@@ -213,7 +215,7 @@ The most updated and useful are :
213
215
  * [vogonistic/voxel](https://github.com/vogonistic/mineflayer-voxel) - visualize what
214
216
  the bot is up to using voxel.js
215
217
  * [JonnyD/Skynet](https://github.com/JonnyD/Skynet) - log player activity onto an online API
216
- * [MinecraftChat](https://github.com/rom1504/MinecraftChat) (last open source version, built by AlexKvazos) - Minecraft web based chat client <https://minecraftchat.net/>
218
+ * [MinecraftChat](https://github.com/rom1504/MinecraftChat) (last open source version, built by AlexKvazos) - Minecraft web based chat client
217
219
  * [Cheese Bot](https://github.com/Minecheesecraft/Cheese-Bot) - Plugin based bot with a clean GUI. Made with Node-Webkit.
218
220
  * [Chaoscraft](https://github.com/schematical/chaoscraft) - Minecraft bot using genetic algorithms, see [its youtube videos](https://www.youtube.com/playlist?list=PLLkpLgU9B5xJ7Qy4kOyBJl5J6zsDIMceH)
219
221
  * [hexatester/minetelegram](https://github.com/hexatester/minetelegram) - Minecraft - Telegram bridge, build on top of mineflayer & telegraf.
package/docs/api.md CHANGED
@@ -16,6 +16,7 @@
16
16
  - [vec3](#vec3)
17
17
  - [mineflayer.Location](#mineflayerlocation)
18
18
  - [Entity](#entity)
19
+ - [Player Skin Data](#player-skin-data)
19
20
  - [Block](#block)
20
21
  - [Biome](#biome)
21
22
  - [Item](#item)
@@ -405,6 +406,18 @@ Entities represent players, mobs, and objects. They are emitted
405
406
  in many events, and you can access your own entity with `bot.entity`.
406
407
  See [prismarine-entity](https://github.com/PrismarineJS/prismarine-entity)
407
408
 
409
+ #### Player Skin Data
410
+
411
+ The skin data is stored in the `skinData` property of the player object, if present.
412
+
413
+ ```js
414
+ // player.skinData
415
+ {
416
+ url: 'http://textures.minecraft.net/texture/...',
417
+ model: 'slim' // or 'classic'
418
+ }
419
+ ```
420
+
408
421
  ### Block
409
422
 
410
423
  See [prismarine-block](https://github.com/PrismarineJS/prismarine-block)
@@ -785,6 +798,8 @@ Create and return an instance of the class bot.
785
798
  * loadInternalPlugins : defaults to true
786
799
  * storageBuilder : an optional function, takes as argument version and worldName and return an instance of something with the same API as prismarine-provider-anvil. Will be used to save the world.
787
800
  * client : an instance of node-minecraft-protocol, if not specified, mineflayer makes it's own client. This can be used to enable using mineflayer through a proxy of many clients or a vanilla client and a mineflayer client.
801
+ * brand : the brand name for the client to use. Defaults to vanilla. Can be used to simulate custom clients for servers that require it.
802
+ * respawn : when set to false disables bot from automatically respawning, defaults to true.
788
803
  * plugins : object : defaults to {}
789
804
  - pluginName : false : don't load internal plugin with given name ie. `pluginName`
790
805
  - pluginName : true : load internal plugin with given name ie. `pluginName` even though loadInternalplugins is set to false
@@ -814,15 +829,13 @@ A sync representation of the world. Check the doc at http://github.com/Prismarin
814
829
 
815
830
  Fires when a block updates. Both `oldBlock` and `newBlock` provided for
816
831
  comparison.
817
-
818
- Note that `oldBlock` may be `null`.
832
+ `oldBlock` may be `null` with normal block updates.
819
833
 
820
834
  ##### world "blockUpdate:(x, y, z)" (oldBlock, newBlock)
821
835
 
822
836
  Fires for a specific point. Both `oldBlock` and `newBlock` provided for
823
- comparison.
824
-
825
- Note that `oldBlock` may be `null`.
837
+ comparison. All listeners receive null for `oldBlock` and `newBlock` and get automatically removed when the world is unloaded.
838
+ `oldBlock` may be `null` with normal block updates.
826
839
 
827
840
 
828
841
  #### bot.entity
@@ -853,6 +866,8 @@ Whether the bot is using the item that it's holding, for example eating food or
853
866
 
854
867
  #### bot.game.dimension
855
868
 
869
+ The bot's current dimension, such as `overworld`, `the_end` or `the_nether`.
870
+
856
871
  #### bot.game.difficulty
857
872
 
858
873
  #### bot.game.gameMode
@@ -2064,9 +2079,9 @@ These are lower level methods for the inventory, they can be useful sometimes bu
2064
2079
 
2065
2080
  This function returns a `Promise`, with `void` as its argument upon completion.
2066
2081
 
2067
- The only valid mode option at the moment is 0. Shift clicking or mouse draging is not implemented.
2082
+ The only valid mode option at the moment is 0. Shift clicking or mouse dragging is not implemented.
2068
2083
 
2069
- Click on the current window. See details at https://wiki.vg/Protocol#Click_Window
2084
+ Click on the current window. See details at https://wiki.vg/Protocol#Click_Container
2070
2085
 
2071
2086
  Prefer using bot.simpleClick.*
2072
2087
 
package/docs/es/FAQ_ES.md CHANGED
@@ -15,7 +15,7 @@ client.on('end', () => {})
15
15
  ## Mi evento de chat no se emite en un servidor personalizado, cómo lo resuelvo?
16
16
 
17
17
  Los servidores spigot, en particular algunos plugins, usan formatos personalizados de chat, tienes que analizarlos con un regex personalizado.
18
- Lee y modifica [chat_parsing.js](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chat_parsing.js) para que funcione con tu plugin de chat particular. Lee también http://mineflayer.prismarine.js.org/#/tutorial?id=custom-chat
18
+ Lee y modifica [chat_parsing.js](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chat_parsing.js) para que funcione con tu plugin de chat particular. Lee también http://prismarinejs.github.io/mineflayer/#/tutorial?id=custom-chat
19
19
 
20
20
  ### Como puedo recolectar información de un plugin de chat personalizado?
21
21
 
@@ -104,7 +104,7 @@ bot.once('spawn', () => {
104
104
  ```
105
105
  Y podrás ver una representación *en vivo* como esta:
106
106
 
107
- [<img src="https://prismarine.js.org/prismarine-viewer/test_1.16.1.png" alt="viewer" width="500">](https://prismarine.js.org/prismarine-viewer/)
107
+ [<img src="https://prismarinejs.github.io/prismarine-viewer/test_1.16.1.png" alt="viewer" width="500">](https://prismarinejs.github.io/prismarine-viewer/)
108
108
 
109
109
  #### Más ejemplos
110
110
 
package/docs/fr/FAQ_FR.md CHANGED
@@ -23,7 +23,7 @@ client.on('end', () => {})
23
23
 
24
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
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>
26
+ plugin de chat. A lire également <http://prismarinejs.github.io/mineflayer/#/tutorial?id=custom-chat>
27
27
 
28
28
  ### Comment puis-je collecter les informations d'un plugin personnalisé dans le chat ?
29
29
 
@@ -108,7 +108,7 @@ bot.once('spawn', () => {
108
108
  ```
109
109
  et vous obtiendrez un affichage en *direct* qui ressemble à ceci:
110
110
 
111
- [<img src="https://prismarine.js.org/prismarine-viewer/test_1.16.1.png" alt="viewer" width="500">](https://prismarine.js.org/prismarine-viewer/)
111
+ [<img src="https://prismarinejs.github.io/prismarine-viewer/test_1.16.1.png" alt="viewer" width="500">](https://prismarinejs.github.io/prismarine-viewer/)
112
112
 
113
113
  #### Exemples:
114
114
 
package/docs/history.md CHANGED
@@ -1,3 +1,24 @@
1
+ ## 4.9.0
2
+
3
+ * Fix bot not updating world height on respawn packet (@frej4189)
4
+ * Persist properties received in player_info packet (@Paulomart)
5
+ * Fix reference error with block updates (@IceTank)
6
+ * Add spectator to gameModes array (@williamd5)
7
+ * Standardize dimensions for all versions (@sefirosweb)
8
+ * Emit inject_allowed after a timeout of 0 (@IceTank)
9
+ * Add window transaction timeout (@firejoust)
10
+ * Made bot auto respawning togglable (@Averagess)
11
+ * support 1.19.4 (@extremeheat)
12
+
13
+ ## 4.8.1
14
+
15
+ * Fix client crashing when player_remove contains unknown player (@frej4189)
16
+ * Improve look and fix bug slow craft (@sefirosweb)
17
+ * Fix player entity being unset when player is updated (@frej4189)
18
+ * Fix type (@sefirosweb)
19
+ * Improve crafting stacks (@sefirosweb)
20
+ * add example for using the node:readline module (@Jovan-04)
21
+
1
22
  ## 4.8.0
2
23
 
3
24
  * Update chat parsing (@frej4189)
package/docs/ru/FAQ_RU.md CHANGED
@@ -14,7 +14,7 @@ client.on('end', () => {})
14
14
 
15
15
  Сервера Spigot, в частности некоторые плагины, используют разные форматы чата, вам необходимо проанализировать его с помощью регулярного выражения/парсера.
16
16
  Посмотрите и измените скрипт [chatAddPattern.js](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chatAddPattern.js), чтобы он работал для вашего плагина чата,
17
- также прочтите http://mineflayer.prismarine.js.org/#/tutorial?id=custom-chat.
17
+ также прочтите http://prismarinejs.github.io/mineflayer/#/tutorial?id=custom-chat.
18
18
 
19
19
  ### Как я могу отправлять команды серверу?
20
20
 
@@ -108,7 +108,7 @@ bot.once('spawn', () => {
108
108
  ```
109
109
  После запуска, вы в прямом эфире сможете наблюдать за происходящим:
110
110
 
111
- [<img src="https://prismarine.js.org/prismarine-viewer/test_1.16.1.png" alt="viewer" width="500">](https://prismarine.js.org/prismarine-viewer/)
111
+ [<img src="https://prismarinejs.github.io/prismarine-viewer/test_1.16.1.png" alt="viewer" width="500">](https://prismarinejs.github.io/prismarine-viewer/)
112
112
 
113
113
  #### Больше примеров
114
114
 
@@ -104,7 +104,7 @@ bot.once('spawn', () => {
104
104
  ```
105
105
  ve şuna benzeyen *canlı* bir görüntü elde edeceksin:
106
106
 
107
- [<img src="https://prismarine.js.org/prismarine-viewer/test_1.16.1.png" alt="viewer" width="500">](https://prismarine.js.org/prismarine-viewer/)
107
+ [<img src="https://prismarinejs.github.io/prismarine-viewer/test_1.16.1.png" alt="viewer" width="500">](https://prismarinejs.github.io/prismarine-viewer/)
108
108
 
109
109
  #### Daha fazla örnek
110
110
 
package/docs/tutorial.md CHANGED
@@ -417,7 +417,7 @@ bot.once('spawn', () => {
417
417
 
418
418
  ### Listening for an event
419
419
 
420
- The bot object has many useful [events](http://mineflayer.prismarine.js.org/#/api?id=events).
420
+ The bot object has many useful [events](http://prismarinejs.github.io/mineflayer/#/api?id=events).
421
421
  You can listen for an event by using either `bot.on()` method or `bot.once()` method of the bot object, which takes the name of an event and a function.
422
422
  To remove specific listener you can use `bot.removeListener()` method.
423
423
 
@@ -428,7 +428,7 @@ To remove specific listener you can use `bot.removeListener()` method.
428
428
  - `bot.removeListener(eventName, listener)`
429
429
  Removes the specified `listener` for the event named `eventName`. In order to use this you either need to define your function with `function myNamedFunc() {}` or put your function in a variable with `const myNamedFunc = () => {}`. You can then use `myNamedFunc` in the listener argument.
430
430
 
431
- Not only bot object, [`Chest`](http://mineflayer.prismarine.js.org/#/api?id=mineflayerchest), [`Furnace`](http://mineflayer.prismarine.js.org/#/api?id=mineflayerfurnace), [`Dispenser`](http://mineflayer.prismarine.js.org/#/api?id=mineflayerdispenser), [`EnchantmentTable`](http://mineflayer.prismarine.js.org/#/api?id=mineflayerenchantmenttable), [`Villager`](http://mineflayer.prismarine.js.org/#/api?id=mineflayervillager) object also have their own events!
431
+ Not only bot object, [`Chest`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayerchest), [`Furnace`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayerfurnace), [`Dispenser`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayerdispenser), [`EnchantmentTable`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayerenchantmenttable), [`Villager`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayervillager) object also have their own events!
432
432
 
433
433
  ### Promises
434
434
  A [promise](https://nodejs.dev/learn/understanding-javascript-promises) is a function that you can use the `await` variable to wait on until it's job is complete. (you can omit the await to not wait for results)
@@ -557,8 +557,8 @@ In general, you'll want to use `for of` instead of `for in` so make sure you don
557
557
 
558
558
  ### Creating an event from chat
559
559
 
560
- You can create your own event from chat using [`bot.chatAddPattern()`](http://mineflayer.prismarine.js.org/#/api?id=botchataddpatternpattern-chattype-description) method. Useful for Bukkit servers where the chat format changes a lot.
561
- [`bot.chatAddPattern()`](http://mineflayer.prismarine.js.org/#/api?id=botchataddpatternpattern-chattype-description) method takes three arguments :
560
+ You can create your own event from chat using [`bot.chatAddPattern()`](http://prismarinejs.github.io/mineflayer/#/api?id=botchataddpatternpattern-chattype-description) method. Useful for Bukkit servers where the chat format changes a lot.
561
+ [`bot.chatAddPattern()`](http://prismarinejs.github.io/mineflayer/#/api?id=botchataddpatternpattern-chattype-description) method takes three arguments :
562
562
 
563
563
  - `pattern` - regular expression (regex) to match chat
564
564
  - `chatType` - the event the bot emits when the pattern matches. e.g. "chat" or "whisper"
package/docs/zh/FAQ.md CHANGED
@@ -15,7 +15,7 @@ client.on('end', () => {})
15
15
  ### 我无法在自定义服务器上获取聊天事件,如何解决?
16
16
 
17
17
  Spigot 服务器, 特别是一些插件, 使用的是自定义聊天格式,您需要使用自定义正则表达式/解析器对其进行解析。
18
- 阅读并改编[chat_parsing.js](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chat_parsing.js)使其适用于您的特定聊天插件. 或者阅读 http://mineflayer.prismarine.js.org/#/tutorial?id=custom-chat
18
+ 阅读并改编[chat_parsing.js](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chat_parsing.js)使其适用于您的特定聊天插件. 或者阅读 http://prismarinejs.github.io/mineflayer/#/tutorial?id=custom-chat
19
19
 
20
20
  ### 如何用自定义插件在聊天中收集信息 ?
21
21
 
@@ -101,7 +101,7 @@ bot.on('error', console.log)
101
101
  ### 看看你的bot在做什么
102
102
 
103
103
  感谢 [prismarin-viewer](https://github.com/PrismarineJS/prismarine-viewer)项目,它可以在浏览器窗口显示你的机器人正在做什么。
104
- 只需要运行 `npm install prismane-viewer` 并将其添加到你的bot代码中。
104
+ 只需要运行 `npm install prismarine-viewer` 并将其添加到你的bot代码中。
105
105
 
106
106
  ```js
107
107
  const { mineflayer: mineflayerViewer } = require('prismarine-viewer')
@@ -112,7 +112,7 @@ bot.once('spawn', () => {
112
112
 
113
113
  然后你会得到一个看起来像这样的*实时视图*:
114
114
 
115
- [<img src="https://prismarine.js.org/prismarine-viewer/test_1.16.1.png" alt="viewer" width="500">](https://prismarine.js.org/prismarine-viewer/)
115
+ [<img src="https://prismarinejs.github.io/prismarine-viewer/test_1.16.1.png" alt="viewer" width="500">](https://prismarinejs.github.io/prismarine-viewer/)
116
116
 
117
117
  #### 更多示例
118
118
 
@@ -417,7 +417,7 @@ bot.once('spawn', () => {
417
417
 
418
418
  ### Listening for an event
419
419
 
420
- The bot object has many useful [events](http://mineflayer.prismarine.js.org/#/api?id=events).
420
+ The bot object has many useful [events](http://prismarinejs.github.io/mineflayer/#/api?id=events).
421
421
  You can listen for an event by using either `bot.on()` method or `bot.once()` method of the bot object, which takes the name of an event and a function.
422
422
  To remove specific listener you can use `bot.removeListener()` method.
423
423
 
@@ -428,7 +428,7 @@ To remove specific listener you can use `bot.removeListener()` method.
428
428
  - `bot.removeListener(eventName, listener)`
429
429
  Removes the specified `listener` for the event named `eventName`. In order to use this you either need to define your function with `function myNamedFunc() {}` or put your function in a variable with `const myNamedFunc = () => {}`. You can then use `myNamedFunc` in the listener argument.
430
430
 
431
- Not only bot object, [`Chest`](http://mineflayer.prismarine.js.org/#/api?id=mineflayerchest), [`Furnace`](http://mineflayer.prismarine.js.org/#/api?id=mineflayerfurnace), [`Dispenser`](http://mineflayer.prismarine.js.org/#/api?id=mineflayerdispenser), [`EnchantmentTable`](http://mineflayer.prismarine.js.org/#/api?id=mineflayerenchantmenttable), [`Villager`](http://mineflayer.prismarine.js.org/#/api?id=mineflayervillager) object also have their own events!
431
+ Not only bot object, [`Chest`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayerchest), [`Furnace`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayerfurnace), [`Dispenser`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayerdispenser), [`EnchantmentTable`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayerenchantmenttable), [`Villager`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayervillager) object also have their own events!
432
432
 
433
433
  ### Callbacks
434
434
  A [callback](https://en.wikipedia.org/wiki/Callback_(computer_programming)) is a function that you can give to another function, that is expected to be *called back*, generally when that function ends.
@@ -491,7 +491,7 @@ The reason the incorrect approach is wrong is because when `bot.craft()` is call
491
491
  By the time the code reaches the second `bot.craft()`, the first probably hasn't finished yet, which means the wanted resource is not available yet.
492
492
  Using callbacks can fix this because they will only be called after the `bot.craft()` is finished.
493
493
 
494
- More on the [bot.craft()](https://mineflayer.prismarine.js.org/#/api?id=botcraftrecipe-count-craftingtable-callback) method.
494
+ More on the [bot.craft()](https://prismarinejs.github.io/mineflayer/#/api?id=botcraftrecipe-count-craftingtable-callback) method.
495
495
 
496
496
  ## 高级
497
497
 
@@ -608,8 +608,8 @@ In general, you'll want to use `for of` instead of `for in` so make sure you don
608
608
 
609
609
  ### 从聊天中创建事件
610
610
 
611
- You can create your own event from chat using [`bot.chatAddPattern()`](http://mineflayer.prismarine.js.org/#/api?id=botchataddpatternpattern-chattype-description) method. Useful for Bukkit servers where the chat format changes a lot.
612
- [`bot.chatAddPattern()`](http://mineflayer.prismarine.js.org/#/api?id=botchataddpatternpattern-chattype-description) method takes three arguments :
611
+ You can create your own event from chat using [`bot.chatAddPattern()`](http://prismarinejs.github.io/mineflayer/#/api?id=botchataddpatternpattern-chattype-description) method. Useful for Bukkit servers where the chat format changes a lot.
612
+ [`bot.chatAddPattern()`](http://prismarinejs.github.io/mineflayer/#/api?id=botchataddpatternpattern-chattype-description) method takes three arguments :
613
613
 
614
614
  - `pattern` - regular expression (regex) to match chat
615
615
  - `chatType` - the event the bot emits when the pattern matches. e.g. "chat" or "whisper"
@@ -0,0 +1,50 @@
1
+ /*
2
+ * This example is an easy way to connect mineflayer to the node:readline module
3
+ * See: https://nodejs.org/api/readline.html
4
+ * Using this, we can make a simple terminal-to-ingame-chat interface
5
+ *
6
+ * Made by Jovan04 01/24/2023
7
+ */
8
+
9
+ if (process.argv.length < 4 || process.argv.length > 6) {
10
+ console.log('Usage : node readline.js <host> <port> [<name>] [<auth>]')
11
+ process.exit(1)
12
+ }
13
+
14
+ const mineflayer = require('mineflayer') // load mineflayer library
15
+ const readline = require('node:readline') // load the node.js readline module
16
+
17
+ // bot options
18
+ const options = {
19
+ host: process.argv[2],
20
+ port: parseInt(process.argv[3]),
21
+ username: process.argv[4] || 'readline',
22
+ auth: process.argv[5] || 'offline'
23
+ }
24
+
25
+ const bot = mineflayer.createBot(options) // join the minecraft server
26
+
27
+ const rl = readline.createInterface({ // creates our readline interface with our console as input and output
28
+ input: process.stdin,
29
+ output: process.stdout
30
+ })
31
+
32
+ bot.once('spawn', () => {
33
+ console.log(`Bot joined the game with username ${bot.username}.`)
34
+ rl.setPrompt('> '); rl.prompt() // gives us a little arrow at the bottom for the input line
35
+ })
36
+
37
+ bot.on('message', (message) => {
38
+ readline.moveCursor(process.stdout, -2, 0) // we move the cursor to the left two places because our cursor is already two positions in (because of the input arrow)
39
+ console.log(message.toAnsi()) // convert our message to ansi to preserve chat formatting
40
+ rl.prompt() // regenerate our little arrow on the input line
41
+ })
42
+
43
+ rl.on('line', (line) => {
44
+ readline.moveCursor(process.stdout, 0, -1) // move cursor up one line
45
+ readline.clearScreenDown(process.stdout) // clear all the lines below the cursor (i.e. the last line we entered)
46
+ bot.chat(line.toString()) // sends the line we entered to ingame chat
47
+ })
48
+
49
+ bot.on('kicked', console.log)
50
+ bot.on('error', console.log)
@@ -0,0 +1,26 @@
1
+ /*
2
+ * This script will automatically set if a totem is in the inventory or the off-hand.
3
+ * It checks for a totem every tick.
4
+ */
5
+ const mineflayer = require('mineflayer')
6
+
7
+ if (process.argv.length < 4 || process.argv.length > 6) {
8
+ console.log('Usage : node skin_data.js <host> <port> [<name>] [<password>]')
9
+ process.exit(1)
10
+ }
11
+
12
+ const bot = mineflayer.createBot({
13
+ host: process.argv[2],
14
+ port: parseInt(process.argv[3]),
15
+ username: process.argv[4] ? process.argv[4] : 'skin_data',
16
+ password: process.argv[5]
17
+ })
18
+
19
+ setTimeout(() => {
20
+ bot.quit()
21
+ console.log('Skin data:')
22
+ console.log(Object.entries(bot.players).map(([name, player]) => ({
23
+ name,
24
+ skinData: player.skinData
25
+ })))
26
+ }, 10000)
@@ -96,7 +96,7 @@ async function trade (id, index, count) {
96
96
  default: {
97
97
  const villager = await bot.openVillager(e)
98
98
  const trade = villager.trades[index - 1]
99
- count = count || trade.maxTradeuses - trade.tooluses
99
+ count = count || trade.maximumNbTradeUses - trade.nbTradeUses
100
100
  switch (true) {
101
101
  case !trade:
102
102
  villager.close()
@@ -106,11 +106,11 @@ async function trade (id, index, count) {
106
106
  villager.close()
107
107
  bot.chat('trade is disabled')
108
108
  break
109
- case trade.maxTradeuses - trade.tooluses < count:
109
+ case trade.maximumNbTradeUses - trade.nbTradeUses < count:
110
110
  villager.close()
111
111
  bot.chat('cant trade that often')
112
112
  break
113
- case !hasResources(villager.window, trade, count):
113
+ case !hasResources(villager.slots, trade, count):
114
114
  villager.close()
115
115
  bot.chat('dont have the resources to do that trade')
116
116
  break
@@ -120,7 +120,7 @@ async function trade (id, index, count) {
120
120
  await bot.trade(villager, index - 1, count)
121
121
  bot.chat(`traded ${count} times`)
122
122
  } catch (err) {
123
- bot.chat('an error acured while tyring to trade')
123
+ bot.chat('an error occurred while trying to trade')
124
124
  console.log(err)
125
125
  }
126
126
  villager.close()
@@ -129,23 +129,29 @@ async function trade (id, index, count) {
129
129
  }
130
130
 
131
131
  function hasResources (window, trade, count) {
132
- const first = enough(trade.firstInput, count)
133
- const second = !trade.hasSecondItem || enough(trade.secondaryInput, count)
132
+ const first = enough(trade.inputItem1, count)
133
+ const second = !trade.inputItem2 || enough(trade.inputItem2, count)
134
134
  return first && second
135
135
 
136
136
  function enough (item, count) {
137
- return window.count(item.type, item.metadata) >= item.count * count
137
+ let c = 0
138
+ window.forEach((element) => {
139
+ if (element && element.type === item.type && element.metadata === item.metadata) {
140
+ c += element.count
141
+ }
142
+ })
143
+ return c >= item.count * count
138
144
  }
139
145
  }
140
146
  }
141
147
 
142
148
  function stringifyTrades (trades) {
143
149
  return trades.map((trade) => {
144
- let text = stringifyItem(trade.firstInput)
145
- if (trade.secondaryInput) text += ` & ${stringifyItem(trade.secondaryInput)}`
150
+ let text = stringifyItem(trade.inputItem1)
151
+ if (trade.inputItem2) text += ` & ${stringifyItem(trade.inputItem2)}`
146
152
  if (trade.disabled) text += ' x '; else text += ' » '
147
- text += stringifyItem(trade.output)
148
- return `(${trade.tooluses}/${trade.maxTradeuses}) ${text}`
153
+ text += stringifyItem(trade.outputItem)
154
+ return `(${trade.nbTradeUses}/${trade.maximumNbTradeUses}) ${text}`
149
155
  })
150
156
  }
151
157
 
@@ -158,7 +164,7 @@ function stringifyItem (item) {
158
164
  const Potion = item.nbt.value.Potion
159
165
  const display = item.nbt.value.display
160
166
 
161
- if (Potion) text += ` of ${Potion.value.replace(/_/g, ' ').split(':')[1] || 'unknow type'}`
167
+ if (Potion) text += ` of ${Potion.value.replace(/_/g, ' ').split(':')[1] || 'unknown type'}`
162
168
  if (display) text += ` named ${display.value.Name.value}`
163
169
  if (ench || StoredEnchantments) {
164
170
  text += ` enchanted with ${(ench || StoredEnchantments).value.value.map((e) => {
@@ -1 +1 @@
1
- [<img src="https://prismarine.js.org/prismarine-viewer/test_1.16.1.png" alt="viewer" width="800">](https://prismarine.js.org/prismarine-viewer/)
1
+ [<img src="https://prismarinejs.github.io/prismarine-viewer/test_1.16.1.png" alt="viewer" width="800">](https://prismarinejs.github.io/prismarine-viewer/)
package/index.d.ts CHANGED
@@ -28,6 +28,7 @@ export interface BotOptions extends ClientOptions {
28
28
  client?: Client
29
29
  brand?: string
30
30
  defaultChatPatterns?: boolean
31
+ respawn?: boolean
31
32
  }
32
33
 
33
34
  export type ChatLevel = 'enabled' | 'commandsOnly' | 'disabled'
@@ -40,7 +41,7 @@ export interface PluginOptions {
40
41
 
41
42
  export type Plugin = (bot: Bot, options: BotOptions) => void
42
43
 
43
- interface BotEvents {
44
+ export interface BotEvents {
44
45
  chat: (
45
46
  username: string,
46
47
  message: string,
@@ -104,7 +105,7 @@ interface BotEvents {
104
105
  playerUpdated: (player: Player) => Promise<void> | void
105
106
  playerLeft: (entity: Player) => Promise<void> | void
106
107
  blockUpdate: (oldBlock: Block | null, newBlock: Block) => Promise<void> | void
107
- 'blockUpdate:(x, y, z)': (oldBlock: Block | null, newBlock: Block) => Promise<void> | void
108
+ 'blockUpdate:(x, y, z)': (oldBlock: Block | null, newBlock: Block | null) => Promise<void> | void
108
109
  chunkColumnLoad: (entity: Vec3) => Promise<void> | void
109
110
  chunkColumnUnload: (entity: Vec3) => Promise<void> | void
110
111
  soundEffectHeard: (
@@ -122,7 +123,7 @@ interface BotEvents {
122
123
  ) => Promise<void> | void
123
124
  noteHeard: (block: Block, instrument: Instrument, pitch: number) => Promise<void> | void
124
125
  pistonMove: (block: Block, isPulling: number, direction: number) => Promise<void> | void
125
- chestLidMove: (block: Block, isOpen: number) => Promise<void> | void
126
+ chestLidMove: (block: Block, isOpen: number, block2: Block | null) => Promise<void> | void
126
127
  blockBreakProgressObserved: (block: Block, destroyStage: number) => Promise<void> | void
127
128
  blockBreakProgressEnd: (block: Block) => Promise<void> | void
128
129
  diggingCompleted: (block: Block) => Promise<void> | void
@@ -190,6 +191,7 @@ export interface Bot extends TypedEmitter<BotEvents> {
190
191
  world: any
191
192
  _client: Client
192
193
  heldItem: Item | null
194
+ usingHeldItem: boolean
193
195
  currentWindow: Window | null
194
196
  simpleClick: simpleClick
195
197
  tablist: Tablist
@@ -449,7 +451,7 @@ export type LevelType =
449
451
  | 'buffet'
450
452
  | 'default_1_1'
451
453
  export type GameMode = 'survival' | 'creative' | 'adventure' | 'spectator'
452
- export type Dimension = 'minecraft:the_nether' | 'minecraft:overworld' | 'minecraft:the_end'
454
+ export type Dimension = 'the_nether' | 'overworld' | 'the_end'
453
455
  export type Difficulty = 'peaceful' | 'easy' | 'normal' | 'hard'
454
456
 
455
457
  export interface Player {
@@ -459,12 +461,18 @@ export interface Player {
459
461
  gamemode: number
460
462
  ping: number
461
463
  entity: Entity
464
+ skinData: SkinData | undefined
462
465
  profileKeys?: {
463
466
  publicKey: Buffer
464
467
  signature: Buffer
465
468
  }
466
469
  }
467
470
 
471
+ export interface SkinData {
472
+ url: string
473
+ model: string | null
474
+ }
475
+
468
476
  export interface ChatPattern {
469
477
  pattern: RegExp
470
478
  type: string
@@ -558,7 +566,7 @@ export interface FindBlockOptions {
558
566
  matching: number | number[] | ((block: Block) => boolean)
559
567
  maxDistance?: number
560
568
  count?: number
561
- useExtraInfo?: boolean
569
+ useExtraInfo?: boolean | ((block: Block) => boolean)
562
570
  }
563
571
 
564
572
  export type EquipmentDestination = 'hand' | 'head' | 'torso' | 'legs' | 'feet' | 'off-hand'
package/lib/loader.js CHANGED
@@ -69,6 +69,7 @@ function createBot (options = {}) {
69
69
  options.loadInternalPlugins = options.loadInternalPlugins ?? true
70
70
  options.client = options.client ?? null
71
71
  options.brand = options.brand ?? 'vanilla'
72
+ options.respawn = options.respawn ?? true
72
73
  const bot = new EventEmitter()
73
74
  bot._client = options.client
74
75
  bot.end = (reason) => bot._client.end(reason)
@@ -123,7 +124,7 @@ function createBot (options = {}) {
123
124
  bot.version = version.minecraftVersion
124
125
  options.version = version.minecraftVersion
125
126
  bot.supportFeature = bot.registry.supportFeature
126
- bot.emit('inject_allowed')
127
+ setTimeout(() => bot.emit('inject_allowed'), 0)
127
128
  }
128
129
  return bot
129
130
  }
@@ -131,7 +131,7 @@ function inject (bot) {
131
131
  throw new Error('the bed is too far')
132
132
  }
133
133
 
134
- if (bot.gameMode !== 'creative' || bot.supportFeature('creativeSleepNearMobs')) { // If in creative mode the bot should be able to sleep even if there are monster nearby (starting in 1.13)
134
+ if (bot.game.gameMode !== 'creative' || bot.supportFeature('creativeSleepNearMobs')) { // If in creative mode the bot should be able to sleep even if there are monster nearby (starting in 1.13)
135
135
  const nwMonsterCorner = headPoint.offset(monsterRange[1], -6, monsterRange[2]) // North-West lower corner
136
136
  const seMonsterCorner = headPoint.offset(monsterRange[3], 4, monsterRange[0]) // South-East upper corner
137
137
 
@@ -275,7 +275,7 @@ function inject (bot, { version, storageBuilder, hideErrors }) {
275
275
  bitMap: packet.bitMap,
276
276
  heightmaps: packet.heightmaps,
277
277
  biomes: packet.biomes,
278
- skyLightSent: bot.game.dimension === 'minecraft:overworld',
278
+ skyLightSent: bot.game.dimension === 'overworld',
279
279
  groundUp: packet.groundUp,
280
280
  data: packet.chunkData,
281
281
  trustEdges: packet.trustEdges,
@@ -6,6 +6,7 @@ module.exports = inject
6
6
  function inject (bot) {
7
7
  const Item = require('prismarine-item')(bot.registry)
8
8
  const Recipe = require('prismarine-recipe')(bot.registry).Recipe
9
+ let windowCraftingTable
9
10
 
10
11
  async function craft (recipe, count, craftingTable) {
11
12
  assert.ok(recipe)
@@ -13,19 +14,36 @@ function inject (bot) {
13
14
  if (recipe.requiresTable && !craftingTable) {
14
15
  throw new Error('recipe requires craftingTable')
15
16
  }
16
- for (let i = 0; i < count; i++) {
17
- await craftOnce(recipe, craftingTable)
17
+
18
+ try {
19
+ for (let i = 0; i < count; i++) {
20
+ await craftOnce(recipe, craftingTable)
21
+ }
22
+
23
+ if (windowCraftingTable) {
24
+ bot.closeWindow(windowCraftingTable)
25
+ windowCraftingTable = undefined
26
+ }
27
+ } catch (err) {
28
+ if (windowCraftingTable) {
29
+ bot.closeWindow(windowCraftingTable)
30
+ windowCraftingTable = undefined
31
+ }
32
+ throw new Error(err)
18
33
  }
19
34
  }
20
35
 
21
36
  async function craftOnce (recipe, craftingTable) {
22
37
  if (craftingTable) {
23
- bot.activateBlock(craftingTable)
24
- const [window] = await once(bot, 'windowOpen')
25
- if (!window.type.startsWith('minecraft:crafting')) {
38
+ if (!windowCraftingTable) {
39
+ bot.activateBlock(craftingTable)
40
+ const [window] = await once(bot, 'windowOpen')
41
+ windowCraftingTable = window
42
+ }
43
+ if (!windowCraftingTable.type.startsWith('minecraft:crafting')) {
26
44
  throw new Error('crafting: non craftingTable used as craftingTable')
27
45
  }
28
- await startClicking(window, 3, 3)
46
+ await startClicking(windowCraftingTable, 3, 3)
29
47
  } else {
30
48
  await startClicking(bot.inventory, 2, 2)
31
49
  }
@@ -73,7 +91,7 @@ function inject (bot) {
73
91
  if (ingredient.id === -1) return nextShapeClick()
74
92
  if (!window.selectedItem || window.selectedItem.type !== ingredient.id ||
75
93
  (ingredient.metadata != null &&
76
- window.selectedItem.metadata !== ingredient.metadata)) {
94
+ window.selectedItem.metadata !== ingredient.metadata)) {
77
95
  // we are not holding the item we need. click it.
78
96
  const sourceItem = window.findInventoryItem(ingredient.id, ingredient.metadata)
79
97
  if (!sourceItem) throw new Error('missing ingredient')
@@ -89,7 +107,7 @@ function inject (bot) {
89
107
  const destSlot = extraSlots.pop()
90
108
  if (!window.selectedItem || window.selectedItem.type !== ingredient.id ||
91
109
  (ingredient.metadata != null &&
92
- window.selectedItem.metadata !== ingredient.metadata)) {
110
+ window.selectedItem.metadata !== ingredient.metadata)) {
93
111
  // we are not holding the item we need. click it.
94
112
  const sourceItem = window.findInventoryItem(ingredient.id, ingredient.metadata)
95
113
  if (!sourceItem) throw new Error('missing ingredient')
@@ -126,7 +144,6 @@ function inject (bot) {
126
144
  for (let i = 1; i <= w * h; i++) {
127
145
  window.updateSlot(i, null)
128
146
  }
129
- closeTheWindow()
130
147
  return
131
148
  }
132
149
  const slotsToClick = []
@@ -145,11 +162,6 @@ function inject (bot) {
145
162
  for (const _slot of slotsToClick) {
146
163
  await bot.putAway(_slot)
147
164
  }
148
- closeTheWindow()
149
- }
150
-
151
- function closeTheWindow () {
152
- bot.closeWindow(window)
153
165
  }
154
166
 
155
167
  function slot (x, y) {
@@ -162,7 +162,8 @@ function inject (bot) {
162
162
  function onBlockUpdate (oldBlock, newBlock) {
163
163
  // vanilla server never actually interrupt digging, but some server send block update when you start digging
164
164
  // so ignore block update if not air
165
- if (newBlock.type !== 0) return
165
+ // All block update listeners receive (null, null) when the world is unloaded. So newBlock can be null.
166
+ if (newBlock?.type !== 0) return
166
167
  bot.removeListener(eventName, onBlockUpdate)
167
168
  clearInterval(swingInterval)
168
169
  clearTimeout(waitTimeout)
@@ -361,28 +361,48 @@ function inject (bot) {
361
361
  entity.metadata = metadata
362
362
  bot.emit('entityUpdate', entity)
363
363
 
364
- const typeSlot = (bot.supportFeature('itemsAreAlsoBlocks') ? 5 : 6) + (bot.supportFeature('entityMetadataHasLong') ? 1 : 0)
365
- const slot = packet.metadata.find(e => e.type === typeSlot)
366
- if (entity.name && (entity.name.toLowerCase() === 'item' || entity.name === 'item_stack') && slot) {
367
- bot.emit('itemDrop', entity)
368
- }
364
+ if (bot.supportFeature('mcDataHasEntityMetadata')) {
365
+ const { metadataKeys } = bot.registry.entitiesByName[entity.name] ?? {}
366
+ const metas = Object.fromEntries(packet.metadata.map(e => [metadataKeys[e.key], e.value]))
367
+ if (packet.metadata.some(m => m.type === 'item_stack')) {
368
+ bot.emit('itemDrop', entity)
369
+ }
370
+ if (metas.sleeping_pos || metas.pose === 2) {
371
+ bot.emit('entitySleep', entity)
372
+ }
373
+ if (metas.shared_flags != null) {
374
+ if (metas.shared_flags & 2) {
375
+ entity.crouching = true
376
+ bot.emit('entityCrouch', entity)
377
+ } else if (entity.crouching) { // prevent the initial entity_metadata packet from firing off an uncrouch event
378
+ entity.crouching = false
379
+ bot.emit('entityUncrouch', entity)
380
+ }
381
+ }
382
+ } else {
383
+ const typeSlot = (bot.supportFeature('itemsAreAlsoBlocks') ? 5 : 6) + (bot.supportFeature('entityMetadataHasLong') ? 1 : 0)
384
+ const slot = packet.metadata.find(e => e.type === typeSlot)
385
+ if (entity.name && (entity.name.toLowerCase() === 'item' || entity.name === 'item_stack') && slot) {
386
+ bot.emit('itemDrop', entity)
387
+ }
369
388
 
370
- const typePose = bot.supportFeature('entityMetadataHasLong') ? 19 : 18
371
- const pose = packet.metadata.find(e => e.type === typePose)
372
- if (pose && pose.value === 2) {
373
- bot.emit('entitySleep', entity)
374
- }
389
+ const typePose = bot.supportFeature('entityMetadataHasLong') ? 19 : 18
390
+ const pose = packet.metadata.find(e => e.type === typePose)
391
+ if (pose && pose.value === 2) {
392
+ bot.emit('entitySleep', entity)
393
+ }
375
394
 
376
- const bitField = packet.metadata.find(p => p.key === 0)
377
- if (bitField === undefined) {
378
- return
379
- }
380
- if ((bitField.value & 2) !== 0) {
381
- entity.crouching = true
382
- bot.emit('entityCrouch', entity)
383
- } else if (entity.crouching) { // prevent the initial entity_metadata packet from firing off an uncrouch event
384
- entity.crouching = false
385
- bot.emit('entityUncrouch', entity)
395
+ const bitField = packet.metadata.find(p => p.key === 0)
396
+ if (bitField === undefined) {
397
+ return
398
+ }
399
+ if ((bitField.value & 2) !== 0) {
400
+ entity.crouching = true
401
+ bot.emit('entityCrouch', entity)
402
+ } else if (entity.crouching) { // prevent the initial entity_metadata packet from firing off an uncrouch event
403
+ entity.crouching = false
404
+ bot.emit('entityUncrouch', entity)
405
+ }
386
406
  }
387
407
  })
388
408
 
@@ -462,6 +482,7 @@ function inject (bot) {
462
482
  if (packet.action & 1) {
463
483
  obj.username = item.player.name
464
484
  obj.displayName = player.displayName || new ChatMessage({ text: '', extra: [{ text: item.player.name }] })
485
+ obj.skinData = extractSkinInformation(item.player.properties)
465
486
  }
466
487
 
467
488
  if (packet.action & 4) {
@@ -484,7 +505,7 @@ function inject (bot) {
484
505
  Object.assign(player, obj)
485
506
  }
486
507
 
487
- const playerEntity = Object.values(bot.entities).find(e => e.type === 'player' && e.username === obj.username)
508
+ const playerEntity = Object.values(bot.entities).find(e => e.type === 'player' && e.username === player.username)
488
509
  player.entity = playerEntity
489
510
 
490
511
  if (playerEntity === bot.entity) {
@@ -510,6 +531,7 @@ function inject (bot) {
510
531
  ping: item.ping,
511
532
  uuid: item.UUID,
512
533
  displayName: new ChatMessage({ text: '', extra: [{ text: item.name }] }),
534
+ skinData: extractSkinInformation(item.properties),
513
535
  profileKeys: item.crypto
514
536
  ? {
515
537
  publicKey: item.crypto.publicKey, // DER-encoded public key
@@ -525,6 +547,7 @@ function inject (bot) {
525
547
  // Just an Update
526
548
  player.gamemode = item.gamemode
527
549
  player.ping = item.ping
550
+ player.skinData = extractSkinInformation(item.properties)
528
551
  if (item.crypto) {
529
552
  player.profileKeys = {
530
553
  publicKey: item.crypto.publicKey,
@@ -579,7 +602,7 @@ function inject (bot) {
579
602
  for (const uuid of packet.players) {
580
603
  const player = bot.uuidToUsername[uuid] ? bot.players[bot.uuidToUsername[uuid]] : null
581
604
 
582
- if (player.entity === bot.entity) continue
605
+ if (!player || player.entity === bot.entity) continue
583
606
 
584
607
  player.entity = null
585
608
  delete bot.players[player.username]
@@ -706,3 +729,25 @@ function parseMetadata (metadata, entityMetadata = {}) {
706
729
 
707
730
  return entityMetadata
708
731
  }
732
+
733
+ function extractSkinInformation (properties) {
734
+ if (!properties) {
735
+ return undefined
736
+ }
737
+
738
+ const props = Object.fromEntries(properties.map((e) => [e.name, e]))
739
+ if (!props.textures || !props.textures.value) {
740
+ return undefined
741
+ }
742
+
743
+ const skinTexture = JSON.parse(Buffer.from(props.textures.value, 'base64').toString('utf8'))
744
+
745
+ const skinTextureUrl = skinTexture?.textures?.SKIN?.url ?? undefined
746
+ const skinTextureModel = skinTexture?.textures?.SKIN?.metadata?.model ?? undefined
747
+
748
+ if (!skinTextureUrl) {
749
+ return undefined
750
+ }
751
+
752
+ return { url: skinTextureUrl, model: skinTextureModel }
753
+ }
@@ -2,12 +2,12 @@ const nbt = require('prismarine-nbt')
2
2
  module.exports = inject
3
3
 
4
4
  const difficultyNames = ['peaceful', 'easy', 'normal', 'hard']
5
- const gameModes = ['survival', 'creative', 'adventure']
5
+ const gameModes = ['survival', 'creative', 'adventure', 'spectator']
6
6
 
7
7
  const dimensionNames = {
8
- '-1': 'minecraft:nether',
9
- 0: 'minecraft:overworld',
10
- 1: 'minecraft:end'
8
+ '-1': 'the_nether',
9
+ 0: 'overworld',
10
+ 1: 'the_end'
11
11
  }
12
12
 
13
13
  const parseGameMode = gameModeBits => gameModes[(gameModeBits & 0b11)] // lower two bits
@@ -29,9 +29,9 @@ function inject (bot, options) {
29
29
  if (bot.supportFeature('dimensionIsAnInt')) {
30
30
  bot.game.dimension = dimensionNames[packet.dimension]
31
31
  } else if (bot.supportFeature('dimensionIsAString')) {
32
- bot.game.dimension = packet.dimension
32
+ bot.game.dimension = packet.dimension.replace('minecraft:', '')
33
33
  } else if (bot.supportFeature('dimensionIsAWorld')) {
34
- bot.game.dimension = packet.worldName
34
+ bot.game.dimension = packet.worldName.replace('minecraft:', '')
35
35
  } else {
36
36
  throw new Error('Unsupported dimension type in login packet')
37
37
  }
@@ -48,6 +48,9 @@ function inject (bot, options) {
48
48
  bot.game.height = height
49
49
  } else if (packet.dimension) { // respawn
50
50
  bot.game.dimension = packet.dimension.replace('minecraft:', '')
51
+ const { minY, height } = bot.registry.dimensionsByName[bot.game.dimension]
52
+ bot.game.minY = minY
53
+ bot.game.height = height
51
54
  }
52
55
  } else if (bot.supportFeature('dimensionDataIsAvailable')) { // 1.18
53
56
  const dimensionData = nbt.simplify(packet.dimension)
@@ -57,6 +60,7 @@ function inject (bot, options) {
57
60
  bot.game.minY = 0
58
61
  bot.game.height = 256
59
62
  }
63
+
60
64
  if (packet.difficulty) {
61
65
  bot.game.difficulty = difficultyNames[packet.difficulty]
62
66
  }
@@ -1,6 +1,6 @@
1
1
  module.exports = inject
2
2
 
3
- function inject (bot) {
3
+ function inject (bot, options) {
4
4
  bot.isAlive = true
5
5
 
6
6
  bot._client.on('respawn', (packet) => {
@@ -24,6 +24,7 @@ function inject (bot) {
24
24
  bot.isAlive = false
25
25
  bot.emit('death')
26
26
  }
27
+ if (!options.respawn) return
27
28
  bot._client.write('client_command', { payload: 0 })
28
29
  } else if (bot.health > 0 && !bot.isAlive) {
29
30
  bot.isAlive = true
@@ -12,6 +12,8 @@ const DIG_CLICK_TIMEOUT = 500
12
12
  // This number is larger than the eat time of 1.61 seconds to account for latency and low tps.
13
13
  // The eat time comes from https://minecraft.fandom.com/wiki/Food#Usage
14
14
  const CONSUME_TIMEOUT = 2500
15
+ // milliseconds to wait for the server to respond to a window click transaction
16
+ const WINDOW_TIMEOUT = 5000
15
17
 
16
18
  const ALWAYS_CONSUMABLES = [
17
19
  'potion',
@@ -544,7 +546,10 @@ function inject (bot, { hideErrors }) {
544
546
  if (!window.transactionRequiresConfirmation(click)) {
545
547
  confirmTransaction(window.id, actionId, true)
546
548
  }
547
- const [success] = await response
549
+ const [success] = await withTimeout(response, WINDOW_TIMEOUT)
550
+ .catch(() => {
551
+ throw new Error(`Server didn't respond to transaction for clicking on slot ${slot} on window with id ${window?.id}.`)
552
+ })
548
553
  if (!success) {
549
554
  throw new Error(`Server rejected transaction for clicking on slot ${slot}, on window with id ${window?.id}.`)
550
555
  }
@@ -235,6 +235,10 @@ function inject (bot, { physicsEnabled }) {
235
235
  const yawChange = Math.round((yaw - bot.entity.yaw) / sensitivity) * sensitivity
236
236
  const pitchChange = Math.round((pitch - bot.entity.pitch) / sensitivity) * sensitivity
237
237
 
238
+ if (yawChange === 0 && pitchChange === 0) {
239
+ return
240
+ }
241
+
238
242
  bot.entity.yaw += yawChange
239
243
  bot.entity.pitch += pitchChange
240
244
 
@@ -13,8 +13,12 @@ function inject (bot) {
13
13
  [oldBlock, newBlock] = await onceWithCleanup(bot, `blockUpdate:${dest}`, { timeout: 5000 })
14
14
  }
15
15
 
16
- if (oldBlock.type === newBlock.type) {
17
- throw new Error(`No block has been placed : the block is still ${oldBlock.name}`)
16
+ // blockUpdate emits (null, null) when the world unloads
17
+ if (!oldBlock && !newBlock) {
18
+ return
19
+ }
20
+ if (oldBlock?.type === newBlock.type) {
21
+ throw new Error(`No block has been placed : the block is still ${oldBlock?.name}`)
18
22
  } else {
19
23
  bot.emit('blockPlaced', oldBlock, newBlock)
20
24
  }
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', '1.19.2', '1.19.3']
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', '1.19.4']
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.8.0",
3
+ "version": "4.9.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.26.0",
25
- "minecraft-protocol": "^1.40.3",
25
+ "minecraft-protocol": "^1.42.0",
26
26
  "prismarine-biome": "^1.1.1",
27
27
  "prismarine-block": "^1.13.1",
28
28
  "prismarine-chat": "^1.7.1",
@@ -40,13 +40,13 @@
40
40
  "vec3": "^0.1.7"
41
41
  },
42
42
  "devDependencies": {
43
- "@types/node": "^18.0.6",
43
+ "@types/node": "^20.2.1",
44
44
  "doctoc": "^2.0.1",
45
45
  "minecraft-wrap": "^1.3.0",
46
46
  "mineflayer": "file:.",
47
47
  "mocha": "^10.0.0",
48
48
  "standard": "^17.0.0",
49
49
  "standard-markdown": "^7.1.0",
50
- "typescript": "^4.4.3"
50
+ "typescript": "^5.0.3"
51
51
  }
52
52
  }
package/docs/CNAME DELETED
@@ -1 +0,0 @@
1
- mineflayer.prismarine.js.org