mineflayer 4.3.0 → 4.4.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.
package/README.md CHANGED
@@ -238,4 +238,4 @@ Run `npm run mocha_test -- -g <test_name>`, where `<test_name>` is a name of the
238
238
 
239
239
  ## License
240
240
 
241
- [MIT](LICENSE)
241
+ [MIT](/LICENSE)
package/docs/README.md CHANGED
@@ -238,4 +238,4 @@ Run `npm run mocha_test -- -g <test_name>`, where `<test_name>` is a name of the
238
238
 
239
239
  ## License
240
240
 
241
- [MIT](LICENSE)
241
+ [MIT](/LICENSE)
package/docs/api.md CHANGED
@@ -244,6 +244,7 @@
244
244
  - [bot.waitForChunksToLoad()](#botwaitforchunkstoload)
245
245
  - [bot.blockInSight(maxSteps, vectorLength)](#botblockinsightmaxsteps-vectorlength)
246
246
  - [bot.blockAtCursor(maxDistance=256)](#botblockatcursormaxdistance256)
247
+ - [bot.entityAtCursor(maxDistance = 3.5)](#botentityatcursormaxdistance35)
247
248
  - [bot.blockAtEntityCursor(entity=bot.entity, maxDistance=256)](#botblockatentitycursorentitybotentity-maxdistance256)
248
249
  - [bot.canSeeBlock(block)](#botcanseeblockblock)
249
250
  - [bot.findBlocks(options)](#botfindblocksoptions)
@@ -288,7 +289,7 @@
288
289
  - [bot.denyResourcePack()](#botdenyresourcepack)
289
290
  - [bot.placeBlock(referenceBlock, faceVector)](#botplaceblockreferenceblock-facevector)
290
291
  - [bot.placeEntity(referenceBlock, faceVector)](#botplaceentityreferenceblock-facevector)
291
- - [bot.activateBlock(block)](#botactivateblockblock)
292
+ - [bot.activateBlock(block, direction?: Vec3, cursorPos?: Vec3)](#botactivateblockblock-direction-vec3-cursorpos-vec3)
292
293
  - [bot.activateEntity(entity)](#botactivateentityentity)
293
294
  - [bot.activateEntityAt(entity, position)](#botactivateentityatentity-position)
294
295
  - [bot.consume()](#botconsume)
@@ -304,8 +305,8 @@
304
305
  - [bot.setQuickBarSlot(slot)](#botsetquickbarslotslot)
305
306
  - [bot.craft(recipe, count, craftingTable)](#botcraftrecipe-count-craftingtable)
306
307
  - [bot.writeBook(slot, pages)](#botwritebookslot-pages)
307
- - [bot.openContainer(containerBlock or containerEntity)](#botopencontainercontainerblock-or-containerentity)
308
- - [bot.openChest(chestBlock or minecartchestEntity)](#botopenchestchestblock-or-minecartchestentity)
308
+ - [bot.openContainer(containerBlock or containerEntity, direction?, cursorPos?)](#botopencontainercontainerblock-or-containerentity-direction-cursorpos)
309
+ - [bot.openChest(chestBlock or minecartchestEntity, direction?, cursorPos?)](#botopenchestchestblock-or-minecartchestentity-direction-cursorpos)
309
310
  - [bot.openFurnace(furnaceBlock)](#botopenfurnacefurnaceblock)
310
311
  - [bot.openDispenser(dispenserBlock)](#botopendispenserdispenserblock)
311
312
  - [bot.openEnchantmentTable(enchantmentTableBlock)](#botopenenchantmenttableenchantmenttableblock)
@@ -321,7 +322,7 @@
321
322
  - [bot.putAway(slot)](#botputawayslot)
322
323
  - [bot.closeWindow(window)](#botclosewindowwindow)
323
324
  - [bot.transfer(options)](#bottransferoptions)
324
- - [bot.openBlock(block)](#botopenblockblock)
325
+ - [bot.openBlock(block, direction?: Vec3, cursorPos?: Vec3)](#botopenblockblock-direction-vec3-cursorpos-vec3)
325
326
  - [bot.openEntity(entity)](#botopenentityentity)
326
327
  - [bot.moveSlotItem(sourceSlot, destSlot)](#botmoveslotitemsourceslot-destslot)
327
328
  - [bot.updateHeldItem()](#botupdatehelditem)
@@ -453,7 +454,7 @@ See [prismarine-recipe](https://github.com/PrismarineJS/prismarine-recipe)
453
454
  ### mineflayer.Container
454
455
 
455
456
  Extends windows.Window for chests, dispensers, etc...
456
- See `bot.openChest(chestBlock or minecartchestEntity)`.
457
+ See `bot.openContainer(chestBlock or minecartchestEntity)`.
457
458
 
458
459
  ### mineflayer.Furnace
459
460
 
@@ -1321,19 +1322,21 @@ Fires when a note block goes off somewhere.
1321
1322
  * `isOpen`: number of players that have the chest open. 0 if it's closed
1322
1323
  * `block2`: a Block instance, the other half of the block whose lid opened. null if it's not a double chest
1323
1324
 
1324
- #### "blockBreakProgressObserved" (block, destroyStage)
1325
+ #### "blockBreakProgressObserved" (block, destroyStage, entity)
1325
1326
 
1326
1327
  Fires when the client observes a block in the process of being broken.
1327
1328
 
1328
1329
  * `block`: a Block instance, the block being broken
1329
1330
  * `destroyStage`: integer corresponding to the destroy progress (0-9)
1331
+ * `entity`: the entity which is breaking the block.
1330
1332
 
1331
- #### "blockBreakProgressEnd" (block)
1333
+ #### "blockBreakProgressEnd" (block, entity)
1332
1334
 
1333
1335
  Fires when the client observes a block stops being broken.
1334
1336
  This occurs whether the process was completed or aborted.
1335
1337
 
1336
1338
  * `block`: a Block instance, the block no longer being broken
1339
+ * `entity`: the entity which has stopped breaking the block
1337
1340
 
1338
1341
  #### "diggingCompleted" (block)
1339
1342
 
@@ -1477,6 +1480,11 @@ Returns the block at which bot is looking at or `null`
1477
1480
  Returns the block at which bot is looking at or `null`
1478
1481
  * `maxDistance` - The maximum distance the block can be from the eye, defaults to 256.
1479
1482
 
1483
+ #### bot.entityAtCursor(maxDistance=3.5)
1484
+
1485
+ Returns the entity at which bot is looking at or `null`
1486
+ * `maxDistance` - The maximum distance the entity can be from the eye, defaults to 3.5.
1487
+
1480
1488
  #### bot.blockAtEntityCursor(entity=bot.entity, maxDistance=256)
1481
1489
 
1482
1490
  Returns the block at which specific entity is looking at or `null`
@@ -1820,13 +1828,15 @@ This function returns a `Promise`, with `Entity` as its argument upon completion
1820
1828
 
1821
1829
  The new block will be placed at `referenceBlock.position.plus(faceVector)`.
1822
1830
 
1823
- #### bot.activateBlock(block)
1831
+ #### bot.activateBlock(block, direction?: Vec3, cursorPos?: Vec3)
1824
1832
 
1825
1833
  This function returns a `Promise`, with `void` as its argument upon completion.
1826
1834
 
1827
1835
  Punch a note block, open a door, etc.
1828
1836
 
1829
1837
  * `block` - the block to activate
1838
+ * `direction` Optional defaults to `new Vec3(0, 1, 0)` (up). A vector off the direction the container block should be interacted with. Does nothing when a container entity is targeted.
1839
+ * `cursorPos` Optional defaults to `new Vec3(0.5, 0.5, 0.5)` (block center). The curos position when opening the block instance. This is send with the activate block packet. Does nothing when a container entity is targeted.
1830
1840
 
1831
1841
  #### bot.activateEntity(entity)
1832
1842
 
@@ -1927,11 +1937,16 @@ This function returns a `Promise`, with `void` as its argument when the writing
1927
1937
  * `slot` is in inventory window coordinates (where 36 is the first quickbar slot, etc.).
1928
1938
  * `pages` is an array of strings represents the pages.
1929
1939
 
1930
- #### bot.openContainer(containerBlock or containerEntity)
1940
+ #### bot.openContainer(containerBlock or containerEntity, direction?, cursorPos?)
1941
+ Opens a block container or entity.
1942
+
1943
+ * `containerBlock` or `containerEntity` The block instance to open or the entity to open.
1944
+ * `direction` Optional defaults to `new Vec3(0, 1, 0)` (up). A vector off the direction the container block should be interacted with. Does nothing when a container entity is targeted.
1945
+ * `cursorPos` Optional defaults to `new Vec3(0.5, 0.5, 0.5)` (block center). The curos position when opening the block instance. This is send with the activate block packet. Does nothing when a container entity is targeted.
1931
1946
 
1932
1947
  Returns a promise on a `Container` instance which represents the container you are opening.
1933
1948
 
1934
- #### bot.openChest(chestBlock or minecartchestEntity)
1949
+ #### bot.openChest(chestBlock or minecartchestEntity, direction?, cursorPos?)
1935
1950
 
1936
1951
  Deprecated. Same as `openContainer`
1937
1952
 
@@ -1995,9 +2010,13 @@ These are lower level methods for the inventory, they can be useful sometimes bu
1995
2010
  #### bot.clickWindow(slot, mouseButton, mode)
1996
2011
 
1997
2012
  This function returns a `Promise`, with `void` as its argument upon completion.
2013
+
2014
+ The only valid mode option at the moment is 0. Shift clicking or mouse draging is not implemented.
1998
2015
 
1999
2016
  Click on the current window. See details at https://wiki.vg/Protocol#Click_Window
2000
2017
 
2018
+ Prefer using bot.simpleClick.*
2019
+
2001
2020
  #### bot.putSelectedItemRange(start, end, window, slot)
2002
2021
 
2003
2022
  This function returns a `Promise`, with `void` as its argument upon completion.
@@ -2028,11 +2047,13 @@ Transfer some kind of item from one range to an other. `options` is an object co
2028
2047
  * `count` : the amount of items to transfer. Default: `1`
2029
2048
  * `nbt` : nbt data of the item to transfer. Default: `nullish` (ignores nbt)
2030
2049
 
2031
- #### bot.openBlock(block)
2050
+ #### bot.openBlock(block, direction?: Vec3, cursorPos?: Vec3)
2032
2051
 
2033
2052
  Open a block, for example a chest, returns a promise on the opening `Window`.
2034
2053
 
2035
- * `block` is the block the bot will open
2054
+ * `block` is the block the bot will open.
2055
+ * `direction` Optional defaults to `new Vec3(0, 1, 0)` (up). A vector off the direction the container block should be interacted with. Does nothing when a container entity is targeted.
2056
+ * `cursorPos` Optional defaults to `new Vec3(0.5, 0.5, 0.5)` (block center). The curos position when opening the block instance. This is send with the activate block packet. Does nothing when a container entity is targeted.
2036
2057
 
2037
2058
  #### bot.openEntity(entity)
2038
2059
 
package/docs/es/api_es.md CHANGED
@@ -423,7 +423,7 @@ Mira [prismarine-recipe](https://github.com/PrismarineJS/prismarine-recipe)
423
423
  ### mineflayer.Container
424
424
 
425
425
  Extiende windows.Window para cofres, dispensadores, etc...
426
- Mira `bot.openChest(chestBlock o minecartchestEntity)`.
426
+ Mira `bot.openContainer(chestBlock o minecartchestEntity)`.
427
427
 
428
428
  ### mineflayer.Furnace
429
429
 
package/docs/history.md CHANGED
@@ -1,3 +1,23 @@
1
+ ## 4.4.0
2
+
3
+ * Fix chatterbox example not getting dropped item
4
+ * Fix 404d link to license [#2601](https://github.com/PrismarineJS/mineflayer/pull/2601)
5
+ * Add bot.clickWindow mode disclaimer [#2595](https://github.com/PrismarineJS/mineflayer/pull/2595)
6
+ * Add spectator to GameMode types [#2627](https://github.com/PrismarineJS/mineflayer/pull/2627)
7
+ * Update types for isABed [#2628](https://github.com/PrismarineJS/mineflayer/pull/2628)
8
+ * Replace openChest with openContainer in docs and examples [#2656](https://github.com/PrismarineJS/mineflayer/pull/2656)
9
+ * Add ender chests as a chest type [#2642](https://github.com/PrismarineJS/mineflayer/pull/2642)
10
+ * Added method to wait until sleep function is in reality sleeping [#2617](https://github.com/PrismarineJS/mineflayer/pull/2617)
11
+ * Added type on move event [#2712](https://github.com/PrismarineJS/mineflayer/pull/2712)
12
+ * Added thunderState type [#2711](https://github.com/PrismarineJS/mineflayer/pull/2711)
13
+ * Fix type error on chest open [#2684](https://github.com/PrismarineJS/mineflayer/pull/2684)
14
+ * Add support for repeating and chain command blocks. [#2669](https://github.com/PrismarineJS/mineflayer/pull/2669)
15
+ * Add player object to blockBreakProgressEnd & observed. [#2647](https://github.com/PrismarineJS/mineflayer/pull/2647)
16
+ * Add entity to blockBreakProgress [#2648](https://github.com/PrismarineJS/mineflayer/pull/2648)
17
+ * Add direction support to activateBlock, openBlock [#2039](https://github.com/PrismarineJS/mineflayer/pull/2039)
18
+ * Add entityAtCursor function [#2077](https://github.com/PrismarineJS/mineflayer/pull/2077)
19
+ * Fix regex dos [#2350](https://github.com/PrismarineJS/mineflayer/pull/2350)
20
+
1
21
  ## 4.3.0
2
22
 
3
23
  * Cache 'positionUpdateSentEveryTick' feature lookup (@IceTank)
package/docs/ru/api_ru.md CHANGED
@@ -368,7 +368,7 @@
368
368
  ### mineflayer.Chest
369
369
 
370
370
  Предоставляет сеанс взаимодействия с сундуками ( Открытие и закрытие )
371
- Смотрите `bot.openChest(chestBlock or minecartchestEntity)`.
371
+ Смотрите `bot.openContainer(chestBlock or minecartchestEntity)`.
372
372
 
373
373
  #### chest.window
374
374
 
@@ -1490,7 +1490,7 @@ bot.once('login', () => {
1490
1490
 
1491
1491
  #### bot.openChest(chestBlock or minecartchestEntity)
1492
1492
 
1493
- Открывает сундук
1493
+ Устарело.Открывает сундук. Такой же как "openContainer"
1494
1494
 
1495
1495
  #### bot.openFurnace(furnaceBlock)
1496
1496
 
package/docs/zh/api.md CHANGED
@@ -446,7 +446,7 @@ See [prismarine-recipe](https://github.com/PrismarineJS/prismarine-recipe)
446
446
  ### mineflayer.Container
447
447
 
448
448
  Extends windows.Window for chests, dispensers, etc...
449
- See `bot.openChest(chestBlock or minecartchestEntity)`.
449
+ See `bot.openContainer(chestBlock or minecartchestEntity)`.
450
450
 
451
451
  ### mineflayer.Furnace
452
452
 
@@ -168,9 +168,8 @@ bot.on('playerLeft', (player) => {
168
168
  bot.chat(`Bye ${player.username}`)
169
169
  })
170
170
  bot.on('playerCollect', (collector, collected) => {
171
- if (collector.type === 'player' && collected.type === 'object') {
172
- const rawItem = collected.metadata[10]
173
- const item = mineflayer.Item.fromNotch(rawItem)
171
+ if (collector.type === 'player') {
172
+ const item = collected.getDroppedItem()
174
173
  bot.chat(`${collector.username !== bot.username ? ("I'm so jealous. " + collector.username) : 'I '} collected ${item.count} ${item.displayName}`)
175
174
  }
176
175
  })
package/examples/chest.js CHANGED
@@ -103,7 +103,7 @@ async function watchChest (minecart, blocks = []) {
103
103
  return
104
104
  }
105
105
  }
106
- const chest = await bot.openChest(chestToOpen)
106
+ const chest = await bot.openContainer(chestToOpen)
107
107
  sayItems(chest.containerItems())
108
108
  chest.on('updateSlot', (slot, oldItem, newItem) => {
109
109
  bot.chat(`chest update: ${itemToString(oldItem)} -> ${itemToString(newItem)} (slot: ${slot})`)
@@ -21,7 +21,7 @@ const {
21
21
  const intents = new Intents(['GUILDS', 'GUILD_MESSAGES'])
22
22
  // Create Discord client
23
23
  const client = new Client({
24
- intents: intents
24
+ intents
25
25
  })
26
26
 
27
27
  let channel = process.argv[3]
package/index.d.ts CHANGED
@@ -126,7 +126,7 @@ interface BotEvents {
126
126
  blockBreakProgressEnd: (block: Block) => Promise<void> | void
127
127
  diggingCompleted: (block: Block) => Promise<void> | void
128
128
  diggingAborted: (block: Block) => Promise<void> | void
129
- move: () => Promise<void> | void
129
+ move: (position: Vec3) => Promise<void> | void
130
130
  forcedMove: () => Promise<void> | void
131
131
  mount: () => Promise<void> | void
132
132
  dismount: (vehicle: Entity) => Promise<void> | void
@@ -165,6 +165,7 @@ export interface Bot extends TypedEmitter<BotEvents> {
165
165
  player: Player
166
166
  players: { [username: string]: Player }
167
167
  isRaining: boolean
168
+ thunderState: number
168
169
  chatPatterns: ChatPattern[]
169
170
  settings: GameSettings
170
171
  experience: Experience
@@ -249,7 +250,7 @@ export interface Bot extends TypedEmitter<BotEvents> {
249
250
 
250
251
  sleep: (bedBlock: Block) => Promise<void>
251
252
 
252
- isABed: (bedBlock: Block) => void
253
+ isABed: (bedBlock: Block) => boolean
253
254
 
254
255
  wake: () => Promise<void>
255
256
 
@@ -298,7 +299,7 @@ export interface Bot extends TypedEmitter<BotEvents> {
298
299
 
299
300
  placeEntity: (referenceBlock: Block, faceVector: Vec3) => Promise<Entity>
300
301
 
301
- activateBlock: (block: Block) => Promise<void>
302
+ activateBlock: (block: Block, direction?: Vec3, cursorPos?: Vec3) => Promise<void>
302
303
 
303
304
  activateEntity: (block: Entity) => Promise<void>
304
305
 
@@ -337,9 +338,9 @@ export interface Bot extends TypedEmitter<BotEvents> {
337
338
  pages: string[]
338
339
  ) => Promise<void>
339
340
 
340
- openContainer: (chest: Block | Entity) => Promise<Chest | Furnace | Dispenser>
341
+ openContainer: (chest: Block | Entity, direction?: Vec3, cursorPos?: Vec3) => Promise<Chest | Furnace | Dispenser>
341
342
 
342
- openChest: (chest: Block | Entity) => Promise<Chest>
343
+ openChest: (chest: Block | Entity, direction?: number, cursorPos?: Vec3) => Promise<Chest>
343
344
 
344
345
  openFurnace: (furnace: Block) => Promise<Furnace>
345
346
 
@@ -380,7 +381,7 @@ export interface Bot extends TypedEmitter<BotEvents> {
380
381
 
381
382
  transfer: (options: TransferOptions) => Promise<void>
382
383
 
383
- openBlock: (block: Block, Class: new () => EventEmitter) => Promise<void>
384
+ openBlock: (block: Block, direction?: Vec3, cursorPos?: Vec3) => Promise<void>
384
385
 
385
386
  openEntity: (block: Entity, Class: new () => EventEmitter) => Promise<void>
386
387
 
@@ -444,7 +445,7 @@ export type LevelType =
444
445
  | 'customized'
445
446
  | 'buffet'
446
447
  | 'default_1_1'
447
- export type GameMode = 'survival' | 'creative' | 'adventure'
448
+ export type GameMode = 'survival' | 'creative' | 'adventure' | 'spectator'
448
449
  export type Dimension = 'minecraft:nether' | 'minecraft:overworld' | 'minecraft:end'
449
450
  export type Difficulty = 'peaceful' | 'easy' | 'normal' | 'hard'
450
451
 
@@ -146,10 +146,25 @@ function inject (bot) {
146
146
  }
147
147
  }
148
148
 
149
- await bot.activateBlock(bedBlock)
149
+ bot.activateBlock(bedBlock)
150
+
151
+ await waitUntilSleep()
150
152
  }
151
153
  }
152
154
 
155
+ async function waitUntilSleep () {
156
+ return new Promise((resolve, reject) => {
157
+ const timeoutForSleep = setTimeout(() => {
158
+ reject(new Error('bot is not sleeping'))
159
+ }, 3000)
160
+
161
+ bot.once('sleep', () => {
162
+ clearTimeout(timeoutForSleep)
163
+ resolve()
164
+ })
165
+ })
166
+ }
167
+
153
168
  bot._client.on('game_state_change', (packet) => {
154
169
  if (packet.reason === 0) {
155
170
  // occurs when you can't spawn in your bed and your spawn point gets reset
@@ -44,7 +44,7 @@ function inject (bot) {
44
44
  const perpendicularCardinals = Object.keys(FACING_MAP[facing])
45
45
  for (const cardinal of perpendicularCardinals) {
46
46
  const cardinalOffset = CARDINALS[cardinal]
47
- if (bot.blockAt(chestBlock.position.plus(cardinalOffset)).type === chestBlock.type) {
47
+ if (bot.blockAt(chestBlock.position.plus(cardinalOffset))?.type === chestBlock.type) {
48
48
  return FACING_MAP[cardinal][facing]
49
49
  }
50
50
  }
@@ -100,13 +100,14 @@ function inject (bot) {
100
100
  const destroyStage = packet.destroyStage
101
101
  const pt = new Vec3(packet.location.x, packet.location.y, packet.location.z)
102
102
  const block = bot.blockAt(pt)
103
+ const entity = bot.entities[packet.entityId]
103
104
 
104
105
  if (destroyStage < 0 || destroyStage > 9) {
105
106
  // http://wiki.vg/Protocol#Block_Break_Progress
106
107
  // "0-9 to set it, any other value to remove it"
107
- bot.emit('blockBreakProgressEnd', block)
108
+ bot.emit('blockBreakProgressEnd', block, entity)
108
109
  } else {
109
- bot.emit('blockBreakProgressObserved', block, destroyStage)
110
+ bot.emit('blockBreakProgressObserved', block, destroyStage, entity)
110
111
  }
111
112
  })
112
113
  }
@@ -173,7 +173,7 @@ function inject (bot, options) {
173
173
 
174
174
  function addDefaultPatterns () {
175
175
  if (!defaultChatPatterns) return
176
- const USERNAME_REGEX = '(?:\\(.+\\)|\\[.+\\]|.)*?(\\w+)'
176
+ const USERNAME_REGEX = '(?:\\(.{1,15}\\)|\\[.{1,15}\\]|.){0,5}?(\\w+)'
177
177
  bot.addChatPattern('whisper', new RegExp(`^${USERNAME_REGEX} whispers(?: to you)?:? (.*)$`), { deprecated: true })
178
178
  bot.addChatPattern('whisper', new RegExp(`^\\[${USERNAME_REGEX} -> \\w+\\s?\\] (.*)$`), { deprecated: true })
179
179
  bot.addChatPattern('chat', new RegExp(`^${USERNAME_REGEX}\\s?[>:\\-»\\]\\)~]+\\s(.*)$`), { deprecated: true })
@@ -1,8 +1,9 @@
1
+ const { Vec3 } = require('vec3')
1
2
 
2
3
  module.exports = inject
3
4
 
4
5
  function inject (bot) {
5
- const allowedWindowTypes = ['minecraft:generic', 'minecraft:chest', 'minecraft:dispenser', 'minecraft:shulker_box', 'minecraft:hopper', 'minecraft:container', 'minecraft:dropper', 'minecraft:trapped_chest']
6
+ const allowedWindowTypes = ['minecraft:generic', 'minecraft:chest', 'minecraft:dispenser', 'minecraft:ender_chest', 'minecraft:shulker_box', 'minecraft:hopper', 'minecraft:container', 'minecraft:dropper', 'minecraft:trapped_chest']
6
7
 
7
8
  function matchWindowType (window) {
8
9
  for (const type of allowedWindowTypes) {
@@ -11,10 +12,12 @@ function inject (bot) {
11
12
  return false
12
13
  }
13
14
 
14
- async function openContainer (containerToOpen) {
15
+ async function openContainer (containerToOpen, direction, cursorPos) {
16
+ direction = direction ?? new Vec3(0, 1, 0)
17
+ cursorPos = cursorPos ?? new Vec3(0.5, 0.5, 0.5)
15
18
  let chest
16
19
  if (containerToOpen.constructor.name === 'Block' && allowedWindowTypes.map(name => name.replace('minecraft:', '')).includes(containerToOpen.name)) {
17
- chest = await bot.openBlock(containerToOpen)
20
+ chest = await bot.openBlock(containerToOpen, direction, cursorPos)
18
21
  } else if (containerToOpen.constructor.name === 'Entity') {
19
22
  chest = await bot.openEntity(containerToOpen)
20
23
  } else {
@@ -8,7 +8,7 @@ function inject (bot) {
8
8
  assert.strictEqual(bot.player.gamemode, 1, new Error('The bot has to be in creative mode to open the command block window'))
9
9
  assert.notStrictEqual(pos, null)
10
10
  assert.notStrictEqual(command, null)
11
- assert.strictEqual(bot.blockAt(pos).name, 'command_block', new Error("The block isn't a command block"))
11
+ assert.strictEqual(bot.blockAt(pos).name.includes('command_block'), true, new Error("The block isn't a command block"))
12
12
 
13
13
  // Default values when a command block is placed in vanilla minecraft
14
14
  options.trackOutput = options.trackOutput ?? false
@@ -11,7 +11,7 @@ function inject (bot) {
11
11
  // these features only work when you are in creative mode.
12
12
  bot.creative = {
13
13
  setInventorySlot,
14
- flyTo: flyTo,
14
+ flyTo,
15
15
  startFlying,
16
16
  stopFlying,
17
17
  clearSlot: slotNum => setInventorySlot(slotNum, null),
@@ -569,7 +569,7 @@ function inject (bot) {
569
569
  function moveVehicle (left, forward) {
570
570
  bot._client.write('steer_vehicle', {
571
571
  sideways: left,
572
- forward: forward,
572
+ forward,
573
573
  jump: 0x01
574
574
  })
575
575
  }
@@ -150,45 +150,48 @@ function inject (bot, { hideErrors }) {
150
150
  }
151
151
  }
152
152
 
153
- async function activateBlock (block) {
153
+ async function activateBlock (block, direction, cursorPos) {
154
+ direction = direction ?? new Vec3(0, 1, 0)
155
+ const directionNum = vectorToDirection(direction) // The packet needs a number as the direction
156
+ cursorPos = cursorPos ?? new Vec3(0.5, 0.5, 0.5)
154
157
  // TODO: tell the server that we are not sneaking while doing this
155
158
  await bot.lookAt(block.position.offset(0.5, 0.5, 0.5), false)
156
159
  // place block message
157
160
  if (bot.supportFeature('blockPlaceHasHeldItem')) {
158
161
  bot._client.write('block_place', {
159
162
  location: block.position,
160
- direction: 1,
163
+ direction: directionNum,
161
164
  heldItem: Item.toNotch(bot.heldItem),
162
- cursorX: 8,
163
- cursorY: 8,
164
- cursorZ: 8
165
+ cursorX: cursorPos.scaled(16).x,
166
+ cursorY: cursorPos.scaled(16).y,
167
+ cursorZ: cursorPos.scaled(16).z
165
168
  })
166
169
  } else if (bot.supportFeature('blockPlaceHasHandAndIntCursor')) {
167
170
  bot._client.write('block_place', {
168
171
  location: block.position,
169
- direction: 1,
172
+ direction: directionNum,
170
173
  hand: 0,
171
- cursorX: 8,
172
- cursorY: 8,
173
- cursorZ: 8
174
+ cursorX: cursorPos.scaled(16).x,
175
+ cursorY: cursorPos.scaled(16).y,
176
+ cursorZ: cursorPos.scaled(16).z
174
177
  })
175
178
  } else if (bot.supportFeature('blockPlaceHasHandAndFloatCursor')) {
176
179
  bot._client.write('block_place', {
177
180
  location: block.position,
178
- direction: 1,
181
+ direction: directionNum,
179
182
  hand: 0,
180
- cursorX: 0.5,
181
- cursorY: 0.5,
182
- cursorZ: 0.5
183
+ cursorX: cursorPos.x,
184
+ cursorY: cursorPos.y,
185
+ cursorZ: cursorPos.z
183
186
  })
184
187
  } else if (bot.supportFeature('blockPlaceHasInsideBlock')) {
185
188
  bot._client.write('block_place', {
186
189
  location: block.position,
187
- direction: 1,
190
+ direction: directionNum,
188
191
  hand: 0,
189
- cursorX: 0.5,
190
- cursorY: 0.5,
191
- cursorZ: 0.5,
192
+ cursorX: cursorPos.x,
193
+ cursorY: cursorPos.y,
194
+ cursorZ: cursorPos.z,
192
195
  insideBlock: false
193
196
  })
194
197
  }
@@ -325,7 +328,7 @@ function inject (bot, { hideErrors }) {
325
328
  }
326
329
  window.deposit = async (itemType, metadata, count, nbt) => {
327
330
  const options = {
328
- window: window,
331
+ window,
329
332
  itemType,
330
333
  metadata,
331
334
  count,
@@ -339,8 +342,8 @@ function inject (bot, { hideErrors }) {
339
342
  }
340
343
  }
341
344
 
342
- async function openBlock (block) {
343
- bot.activateBlock(block)
345
+ async function openBlock (block, direction, cursorPos) {
346
+ bot.activateBlock(block, direction, cursorPos)
344
347
  const [window] = await once(bot, 'windowOpen')
345
348
  extendWindow(window)
346
349
  return window
@@ -433,7 +436,7 @@ function inject (bot, { hideErrors }) {
433
436
  if (click === undefined || !windowClickQueue.some(clicks => clicks.id === actionId)) {
434
437
  // mimic vanilla client and send a rejection for faulty transaction packets
435
438
  bot._client.write('transaction', {
436
- windowId: windowId,
439
+ windowId,
437
440
  action: actionId,
438
441
  accepted: true
439
442
  // bot.emit(`confirmTransaction${click.id}`, false)
@@ -513,7 +516,7 @@ function inject (bot, { hideErrors }) {
513
516
  slot,
514
517
  mouseButton,
515
518
  mode,
516
- changedSlots: changedSlots,
519
+ changedSlots,
517
520
  cursorItem: Item.toNotch(window.selectedItem)
518
521
  })
519
522
  } else if (bot.supportFeature('actionIdUsed')) { // <= 1.16.5
@@ -531,7 +534,7 @@ function inject (bot, { hideErrors }) {
531
534
  slot,
532
535
  mouseButton,
533
536
  mode,
534
- changedSlots: changedSlots,
537
+ changedSlots,
535
538
  cursorItem: Item.toNotch(window.selectedItem)
536
539
  })
537
540
  }
@@ -641,6 +644,28 @@ function inject (bot, { hideErrors }) {
641
644
  bot.emit(`setWindowItems:${window.id}`)
642
645
  })
643
646
 
647
+ /**
648
+ * Convert a vector direction to minecraft packet number direction
649
+ * @param {Vec3} v
650
+ * @returns {number}
651
+ */
652
+ function vectorToDirection (v) {
653
+ if (v.y < 0) {
654
+ return 0
655
+ } else if (v.y > 0) {
656
+ return 1
657
+ } else if (v.z < 0) {
658
+ return 2
659
+ } else if (v.z > 0) {
660
+ return 3
661
+ } else if (v.x < 0) {
662
+ return 4
663
+ } else if (v.x > 0) {
664
+ return 5
665
+ }
666
+ assert.ok(false, `invalid direction vector ${v}`)
667
+ }
668
+
644
669
  bot.activateBlock = activateBlock
645
670
  bot.activateEntity = activateEntity
646
671
  bot.activateEntityAt = activateEntityAt
@@ -1,4 +1,5 @@
1
1
  const { Vec3 } = require('vec3')
2
+ const { RaycastIterator } = require('prismarine-world').iterators
2
3
 
3
4
  module.exports = (bot) => {
4
5
  function getViewDirection (pitch, yaw) {
@@ -24,6 +25,41 @@ module.exports = (bot) => {
24
25
  return bot.world.raycast(eyePosition, viewDirection, maxDistance, matcher)
25
26
  }
26
27
 
28
+ bot.entityAtCursor = (maxDistance = 3.5) => {
29
+ const block = bot.blockAtCursor(maxDistance)
30
+ maxDistance = block?.intersect.distanceTo(bot.entity.position) ?? maxDistance
31
+
32
+ const entities = Object.values(bot.entities)
33
+ .filter(entity => entity.type !== 'object' && entity.username !== bot.username && entity.position.distanceTo(bot.entity.position) <= maxDistance)
34
+
35
+ const dir = new Vec3(-Math.sin(bot.entity.yaw) * Math.cos(bot.entity.pitch), Math.sin(bot.entity.pitch), -Math.cos(bot.entity.yaw) * Math.cos(bot.entity.pitch))
36
+ const iterator = new RaycastIterator(bot.entity.position.offset(0, bot.entity.height, 0), dir.normalize(), maxDistance)
37
+
38
+ let targetEntity = null
39
+ let targetDist = maxDistance
40
+
41
+ for (let i = 0; i < entities.length; i++) {
42
+ const entity = entities[i]
43
+ const w = entity.width / 2
44
+
45
+ const shapes = [[-w, 0, -w, w, entity.height + (entity.type === 'player' ? 0.18 : 0), w]]
46
+ const intersect = iterator.intersect(shapes, entity.position)
47
+ if (intersect) {
48
+ const entityDir = entity.position.minus(bot.entity.position) // Can be combined into 1 line
49
+ const sign = Math.sign(entityDir.dot(dir))
50
+ if (sign !== -1) {
51
+ const dist = bot.entity.position.distanceTo(intersect.pos)
52
+ if (dist < targetDist) {
53
+ targetEntity = entity
54
+ targetDist = dist
55
+ }
56
+ }
57
+ }
58
+ }
59
+
60
+ return targetEntity
61
+ }
62
+
27
63
  bot.blockAtEntityCursor = (entity = bot.entity, maxDistance = 256, matcher = null) => {
28
64
  if (!entity.position || !entity.height || !entity.pitch || !entity.yaw) return null
29
65
  const { position, height, pitch, yaw } = entity
@@ -58,7 +58,7 @@ function inject (bot, options) {
58
58
  viewDistance: viewDistanceBits,
59
59
  chatFlags: chatBits,
60
60
  chatColors: bot.settings.colorsEnabled,
61
- skinParts: skinParts,
61
+ skinParts,
62
62
  mainHand: handBits,
63
63
  enableTextFiltering: bot.settings.enableTextFiltering,
64
64
  enableServerListing: bot.settings.enableServerListing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mineflayer",
3
- "version": "4.3.0",
3
+ "version": "4.4.0",
4
4
  "description": "create minecraft bots with a stable, high level API",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -8,8 +8,8 @@
8
8
  "mocha_test": "mocha --reporter spec --exit",
9
9
  "test": "npm run mocha_test",
10
10
  "pretest": "npm run lint",
11
- "lint": "standard && ts-standard *.d.ts && standard-markdown",
12
- "fix": "standard --fix && ts-standard --fix *.d.ts && standard-markdown --fix",
11
+ "lint": "standard && standard-markdown",
12
+ "fix": "standard --fix && standard-markdown --fix",
13
13
  "prepublishOnly": "cp docs/README.md README.md"
14
14
  },
15
15
  "repository": {
@@ -40,14 +40,13 @@
40
40
  "vec3": "^0.1.7"
41
41
  },
42
42
  "devDependencies": {
43
- "@types/node": "^17.0.0",
43
+ "@types/node": "^18.0.6",
44
44
  "doctoc": "^2.0.1",
45
45
  "minecraft-wrap": "^1.3.0",
46
46
  "mineflayer": "file:.",
47
- "mocha": "^9.1.2",
48
- "standard": "^16.0.4",
47
+ "mocha": "^10.0.0",
48
+ "standard": "^17.0.0",
49
49
  "standard-markdown": "^7.1.0",
50
- "ts-standard": "^11.0.0",
51
50
  "typescript": "^4.4.3"
52
51
  }
53
52
  }