mineflayer 3.10.0 → 3.12.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.
Files changed (46) hide show
  1. package/.github/FUNDING.yml +0 -2
  2. package/.github/workflows/ci.yml +20 -16
  3. package/README.md +16 -15
  4. package/docs/README.md +16 -15
  5. package/docs/api.md +50 -27
  6. package/docs/es/README_ES.md +1 -1
  7. package/docs/es/api_es.md +34 -18
  8. package/docs/fr/README_FR.md +1 -1
  9. package/docs/history.md +28 -0
  10. package/docs/ru/README_RU.md +1 -1
  11. package/docs/ru/api_ru.md +1 -1
  12. package/docs/tr/README_TR.md +1 -1
  13. package/docs/zh/README_ZH_CN.md +1 -1
  14. package/examples/chatterbox.js +1 -1
  15. package/examples/discord.js +15 -5
  16. package/examples/plugins/afk.js +50 -37
  17. package/examples/python/basic.py +2 -2
  18. package/examples/python/chatterbox.py +1 -1
  19. package/examples/screenshot-with-node-canvas-webgl/screenshot.js +2 -2
  20. package/index.d.ts +108 -134
  21. package/lib/conversions.js +1 -1
  22. package/lib/features.json +57 -27
  23. package/lib/loader.js +5 -4
  24. package/lib/plugins/bed.js +1 -1
  25. package/lib/plugins/block_actions.js +19 -7
  26. package/lib/plugins/blocks.js +17 -4
  27. package/lib/plugins/chat.js +5 -6
  28. package/lib/plugins/command_block.js +1 -1
  29. package/lib/plugins/craft.js +10 -18
  30. package/lib/plugins/creative.js +2 -2
  31. package/lib/plugins/digging.js +15 -6
  32. package/lib/plugins/enchantment_table.js +4 -2
  33. package/lib/plugins/entities.js +13 -8
  34. package/lib/plugins/explosion.js +3 -1
  35. package/lib/plugins/fishing.js +2 -2
  36. package/lib/plugins/game.js +55 -50
  37. package/lib/plugins/inventory.js +164 -40
  38. package/lib/plugins/physics.js +16 -5
  39. package/lib/plugins/place_block.js +7 -6
  40. package/lib/plugins/ray_trace.js +10 -0
  41. package/lib/plugins/simple_inventory.js +1 -1
  42. package/lib/plugins/sound.js +1 -1
  43. package/lib/plugins/spawn_point.js +1 -1
  44. package/lib/plugins/villager.js +57 -42
  45. package/lib/version.js +3 -3
  46. package/package.json +23 -22
@@ -13,6 +13,13 @@ const DIG_CLICK_TIMEOUT = 500
13
13
  // The eat time comes from https://minecraft.fandom.com/wiki/Food#Usage
14
14
  const CONSUME_TIMEOUT = 2500
15
15
 
16
+ const ALWAYS_CONSUMABLES = [
17
+ 'potion',
18
+ 'milk_bucket',
19
+ 'enchanted_golden_apple',
20
+ 'golden_apple'
21
+ ]
22
+
16
23
  function inject (bot, { version, hideErrors }) {
17
24
  const Item = require('prismarine-item')(version)
18
25
  const windows = require('prismarine-windows')(version)
@@ -20,7 +27,13 @@ function inject (bot, { version, hideErrors }) {
20
27
 
21
28
  let eatingTask = createDoneTask()
22
29
 
23
- let nextActionNumber = 0
30
+ let nextActionNumber = 0 // < 1.17
31
+ let stateId = -1
32
+ if (bot.supportFeature('stateIdUsed')) {
33
+ const listener = packet => { stateId = packet.stateId }
34
+ bot._client.on('window_items', listener)
35
+ bot._client.on('set_slot', listener)
36
+ }
24
37
  const windowClickQueue = []
25
38
  let windowItems
26
39
 
@@ -30,11 +43,36 @@ function inject (bot, { version, hideErrors }) {
30
43
  bot.inventory = windows.createWindow(0, 'minecraft:inventory', 'Inventory')
31
44
  bot.currentWindow = null
32
45
  bot.heldItem = null
46
+ bot.usingHeldItem = false
33
47
 
34
48
  bot._client.on('entity_status', (packet) => {
35
49
  if (packet.entityId === bot.entity.id && packet.entityStatus === 9 && !eatingTask.done) {
36
50
  eatingTask.finish()
37
51
  }
52
+ bot.usingHeldItem = false
53
+ })
54
+
55
+ let previousHeldItem = null
56
+ bot.on('heldItemChanged', (heldItem) => {
57
+ // we only disable the item if the item type or count changes
58
+ if (
59
+ heldItem?.type === previousHeldItem?.type && heldItem?.count === previousHeldItem?.count
60
+ ) {
61
+ previousHeldItem = heldItem
62
+ return
63
+ }
64
+ if (!eatingTask.done) {
65
+ eatingTask.finish()
66
+ }
67
+ bot.usingHeldItem = false
68
+ })
69
+
70
+ bot._client.on('set_cooldown', (packet) => {
71
+ if (bot.heldItem && bot.heldItem.type !== packet.itemID) return
72
+ if (!eatingTask.done) {
73
+ eatingTask.finish()
74
+ }
75
+ bot.usingHeldItem = false
38
76
  })
39
77
 
40
78
  async function consume () {
@@ -42,7 +80,7 @@ function inject (bot, { version, hideErrors }) {
42
80
  eatingTask.cancel(new Error('Consuming cancelled due to calling bot.consume() again'))
43
81
  }
44
82
 
45
- if (bot.food === 20) {
83
+ if (bot.game.gameMode !== 'creative' && !ALWAYS_CONSUMABLES.includes(bot.heldItem.name) && bot.food === 20) {
46
84
  throw new Error('Food is full')
47
85
  }
48
86
 
@@ -54,6 +92,7 @@ function inject (bot, { version, hideErrors }) {
54
92
  }
55
93
 
56
94
  function activateItem (offHand = false) {
95
+ bot.usingHeldItem = true
57
96
  if (bot.supportFeature('useItemWithBlockPlace')) {
58
97
  bot._client.write('block_place', {
59
98
  location: new Vec3(-1, 255, -1),
@@ -76,9 +115,10 @@ function inject (bot, { version, hideErrors }) {
76
115
  location: new Vec3(0, 0, 0),
77
116
  face: 5
78
117
  })
118
+ bot.usingHeldItem = false
79
119
  }
80
120
 
81
- async function putSelectedItemRange (start, end, window, slot, noWaiting = false) {
121
+ async function putSelectedItemRange (start, end, window, slot) {
82
122
  // put the selected item back indow the slot range in window
83
123
 
84
124
  // try to put it in an item that already exists and just increase
@@ -88,11 +128,7 @@ function inject (bot, { version, hideErrors }) {
88
128
  const item = window.findItemRange(start, end, window.selectedItem.type, window.selectedItem.metadata, true, window.selectedItem.nbt)
89
129
 
90
130
  if (item && item.stackSize !== item.count) { // something to join with
91
- if (noWaiting) {
92
- await clickWindow(item.slot, 0, 0)
93
- } else {
94
- await Promise.all([clickWindow(item.slot, 0, 0), once(window, `updateSlot:${item.slot}`)])
95
- }
131
+ await clickWindow(item.slot, 0, 0)
96
132
  } else { // nothing to join with
97
133
  const emptySlot = window.firstEmptySlotRange(start, end)
98
134
  if (emptySlot === null) { // no room left
@@ -103,11 +139,7 @@ function inject (bot, { version, hideErrors }) {
103
139
  await tossLeftover()
104
140
  }
105
141
  } else {
106
- if (noWaiting) {
107
- await Promise.all([clickWindow(emptySlot, 0, 0), once(window, `updateSlot:${emptySlot}`)])
108
- } else {
109
- await clickWindow(emptySlot, 0, 0)
110
- }
142
+ await clickWindow(emptySlot, 0, 0)
111
143
  }
112
144
  }
113
145
  }
@@ -171,8 +203,9 @@ function inject (bot, { version, hideErrors }) {
171
203
  await bot.lookAt(entity.position.offset(0, 1, 0), false)
172
204
  bot._client.write('use_entity', {
173
205
  target: entity.id,
174
- mouse: 0,
175
- sneaking: false
206
+ mouse: 0, // interact with entity
207
+ sneaking: false,
208
+ hand: 0 // interact with the main hand
176
209
  })
177
210
  }
178
211
 
@@ -181,8 +214,9 @@ function inject (bot, { version, hideErrors }) {
181
214
  await bot.lookAt(position, false)
182
215
  bot._client.write('use_entity', {
183
216
  target: entity.id,
184
- mouse: 2,
217
+ mouse: 2, // interact with entity at
185
218
  sneaking: false,
219
+ hand: 0, // interact with the main hand
186
220
  x: position.x - entity.position.x,
187
221
  y: position.y - entity.position.y,
188
222
  z: position.z - entity.position.z
@@ -333,20 +367,84 @@ function inject (bot, { version, hideErrors }) {
333
367
  bot._client.write('close_window', {
334
368
  windowId: window.id
335
369
  })
370
+ copyInventory(window)
336
371
  bot.currentWindow = null
337
372
  bot.emit('windowClose', window)
338
373
  }
339
374
 
375
+ function copyInventory (window) {
376
+ const slotOffset = window.inventoryStart - bot.inventory.inventoryStart
377
+ for (let i = window.inventoryStart; i < window.inventoryEnd; i++) {
378
+ const item = window.slots[i]
379
+ const slot = i - slotOffset
380
+ if (item) {
381
+ item.slot = slot
382
+ }
383
+ bot.inventory.slots[slot] = item
384
+ }
385
+ }
386
+
387
+ function tradeMatch (limitItem, targetItem) {
388
+ return targetItem.type === limitItem.type && targetItem.count >= limitItem.count
389
+ }
390
+
391
+ function expectTradeUpdate (window) {
392
+ const trade = window.selectedTrade
393
+ const hasItem = !!window.slots[2]
394
+
395
+ if (hasItem !== tradeMatch(trade.inputItem1, window.slots[0])) {
396
+ if (trade.hasItems2) {
397
+ return hasItem !== tradeMatch(trade.inputItem2, window.slots[1])
398
+ }
399
+ return true
400
+ }
401
+ return false
402
+ }
403
+
404
+ async function waitForWindowUpdate (window, slot) {
405
+ if (window.type === 'minecraft:inventory') {
406
+ if (slot >= 1 && slot <= 4) {
407
+ await once(bot.inventory, 'updateSlot:0')
408
+ }
409
+ } else if (window.type === 'minecraft:crafting') {
410
+ if (slot >= 1 && slot <= 9) {
411
+ await once(bot.currentWindow, 'updateSlot:0')
412
+ }
413
+ } else if (window.type === 'minecraft:merchant') {
414
+ const toUpdate = []
415
+ if (slot <= 2 && !window.selectedTrade.tradeDisabled && expectTradeUpdate(window)) {
416
+ toUpdate.push(once(bot.currentWindow, 'updateSlot:2'))
417
+ }
418
+ if (slot === 2) {
419
+ for (const item of bot.currentWindow.containerItems()) {
420
+ toUpdate.push(once(bot.currentWindow, `updateSlot:${item.slot}`))
421
+ }
422
+ }
423
+ await Promise.all(toUpdate)
424
+ }
425
+ }
426
+
340
427
  function confirmTransaction (windowId, actionId, accepted) {
341
428
  // drop the queue entries for all the clicks that the server did not send
342
429
  // transaction packets for.
343
- let click = windowClickQueue.shift()
344
- if (click === undefined) {
430
+ // Also reject transactions that aren't sent from mineflayer
431
+ let click = windowClickQueue[0]
432
+ if (click === undefined || !windowClickQueue.some(clicks => clicks.id === actionId)) {
433
+ // mimic vanilla client and send a rejection for faulty transaction packets
434
+ bot._client.write('transaction', {
435
+ windowId: windowId,
436
+ action: actionId,
437
+ accepted: true
438
+ // bot.emit(`confirmTransaction${click.id}`, false)
439
+ })
345
440
  if (!hideErrors) {
346
441
  console.log(`WARNING : unknown transaction confirmation for window ${windowId}, action ${actionId} and accepted ${accepted}`)
347
442
  }
348
443
  return
349
444
  }
445
+ // shift it later if packets are sent out of order
446
+ click = windowClickQueue.shift()
447
+
350
448
  assert.ok(click.id <= actionId)
351
449
  while (actionId > click.id) {
352
450
  onAccepted()
@@ -401,37 +499,66 @@ function inject (bot, { version, hideErrors }) {
401
499
  windowId: window.id,
402
500
  item: slot === -999 ? null : window.slots[slot]
403
501
  }
404
- windowClickQueue.push(click)
405
- bot._client.write('window_click', {
406
- windowId: window.id,
407
- slot,
408
- mouseButton,
409
- action: actionId,
410
- mode,
411
- item: Item.toNotch(click.item)
412
- })
413
502
 
414
- const response = once(bot, `confirmTransaction${actionId}`)
503
+ let changedSlots
504
+ if (bot.supportFeature('transactionPacketExists')) {
505
+ windowClickQueue.push(click)
506
+ } else {
507
+ changedSlots = window.acceptClick(click)
508
+ }
415
509
 
416
- // notchian servers are assholes and only confirm certain transactions.
417
- if (!window.transactionRequiresConfirmation(click)) {
418
- // jump the gun and accept the click
419
- confirmTransaction(window.id, actionId, true)
510
+ // WHEN ADDING SUPPORT FOR OTHER CLICKS, MAKE SURE TO CHANGE changedSlots TO SUPPORT THEM
511
+ if (bot.supportFeature('stateIdUsed')) { // 1.17.1 +
512
+ bot._client.write('window_click', {
513
+ windowId: window.id,
514
+ stateId,
515
+ slot,
516
+ mouseButton,
517
+ mode,
518
+ changedSlots: changedSlots,
519
+ cursorItem: Item.toNotch(window.selectedItem)
520
+ })
521
+ } else if (bot.supportFeature('actionIdUsed')) { // <= 1.16.5
522
+ bot._client.write('window_click', {
523
+ windowId: window.id,
524
+ slot,
525
+ mouseButton,
526
+ action: actionId,
527
+ mode,
528
+ item: Item.toNotch(click.item)
529
+ })
530
+ } else { // 1.17
531
+ bot._client.write('window_click', {
532
+ windowId: window.id,
533
+ slot,
534
+ mouseButton,
535
+ mode,
536
+ changedSlots: changedSlots,
537
+ cursorItem: Item.toNotch(window.selectedItem)
538
+ })
420
539
  }
421
540
 
422
- const [success] = await response
423
- if (!success) {
424
- throw new Error(`Server rejected transaction for clicking on slot ${slot}, on window ${JSON.stringify(window.slots, null, 2)}.`)
541
+ if (bot.supportFeature('transactionPacketExists')) {
542
+ const response = once(bot, `confirmTransaction${actionId}`)
543
+ if (!window.transactionRequiresConfirmation(click)) {
544
+ confirmTransaction(window.id, actionId, true)
545
+ }
546
+ const [success] = await response
547
+ if (!success) {
548
+ throw new Error(`Server rejected transaction for clicking on slot ${slot}, on window with id ${window?.id}.`)
549
+ }
550
+ } else {
551
+ await waitForWindowUpdate(window, slot)
425
552
  }
426
553
  }
427
554
 
428
- async function putAway (slot, noWaiting = false) {
555
+ async function putAway (slot) {
429
556
  const window = bot.currentWindow || bot.inventory
430
557
  const promisePutAway = once(window, `updateSlot:${slot}`)
431
558
  await clickWindow(slot, 0, 0)
432
559
  const start = window.inventoryStart
433
560
  const end = window.inventoryEnd
434
- await putSelectedItemRange(start, end, window, null, noWaiting)
561
+ await putSelectedItemRange(start, end, window, null)
435
562
  await promisePutAway
436
563
  }
437
564
 
@@ -448,9 +575,6 @@ function inject (bot, { version, hideErrors }) {
448
575
 
449
576
  bot._client.on('transaction', (packet) => {
450
577
  // confirm transaction
451
- if (packet.action < 0) {
452
- return
453
- }
454
578
  confirmTransaction(packet.windowId, packet.action, packet.accepted)
455
579
  })
456
580
 
@@ -1,4 +1,4 @@
1
- const Vec3 = require('vec3').Vec3
1
+ const { Vec3 } = require('vec3')
2
2
  const assert = require('assert')
3
3
  const math = require('../math')
4
4
  const conv = require('../conversions')
@@ -33,6 +33,7 @@ function inject (bot, { physicsEnabled }) {
33
33
  sneak: false
34
34
  }
35
35
  let lastSentYaw = null
36
+ let lastSentPitch = null
36
37
  let doPhysicsTimer = null
37
38
  let lastPhysicsFrameTime = null
38
39
  let shouldUsePhysics = false
@@ -122,13 +123,16 @@ function inject (bot, { physicsEnabled }) {
122
123
 
123
124
  // Increment the yaw in baby steps so that notchian clients (not the server) can keep up.
124
125
  const dYaw = deltaYaw(bot.entity.yaw, lastSentYaw)
126
+ const dPitch = bot.entity.pitch - (lastSentPitch || 0)
125
127
 
126
128
  // Vanilla doesn't clamp yaw, so we don't want to do it either
127
129
  const maxDeltaYaw = dt * physics.yawSpeed
130
+ const maxDeltaPitch = dt * physics.pitchSpeed
128
131
  lastSentYaw += math.clamp(-maxDeltaYaw, dYaw, maxDeltaYaw)
132
+ lastSentPitch += math.clamp(-maxDeltaPitch, dPitch, maxDeltaPitch)
129
133
 
130
- const yaw = conv.toNotchianYaw(lastSentYaw)
131
- const pitch = conv.toNotchianPitch(bot.entity.pitch)
134
+ const yaw = Math.fround(conv.toNotchianYaw(lastSentYaw))
135
+ const pitch = Math.fround(conv.toNotchianPitch(lastSentPitch))
132
136
  const position = bot.entity.position
133
137
  const onGround = bot.entity.onGround
134
138
 
@@ -225,8 +229,15 @@ function inject (bot, { physicsEnabled }) {
225
229
  }
226
230
  lookingTask = createTask()
227
231
 
228
- bot.entity.yaw = yaw
229
- bot.entity.pitch = pitch
232
+ // this is done to bypass certain anticheat checks that detect the player's sensitivity
233
+ // by calculating the gcd of how much they move the mouse each tick
234
+ const sensitivity = conv.fromNotchianPitch(0.15) // this is equal to 100% sensitivity in vanilla
235
+ const yawChange = Math.round((yaw - bot.entity.yaw) / sensitivity) * sensitivity
236
+ const pitchChange = Math.round((pitch - bot.entity.pitch) / sensitivity) * sensitivity
237
+
238
+ bot.entity.yaw += yawChange
239
+ bot.entity.pitch += pitchChange
240
+
230
241
  if (force) {
231
242
  lastSentYaw = yaw
232
243
  return
@@ -4,13 +4,14 @@ module.exports = inject
4
4
 
5
5
  function inject (bot) {
6
6
  async function placeBlockWithOptions (referenceBlock, faceVector, options) {
7
- bot.swingArm()
8
- const pos = await bot._genericPlace(referenceBlock, faceVector, options)
7
+ const dest = referenceBlock.position.plus(faceVector)
8
+ let oldBlock = bot.blockAt(dest)
9
+ await bot._genericPlace(referenceBlock, faceVector, options)
9
10
 
10
- const dest = pos.plus(faceVector)
11
- const eventName = `blockUpdate:${dest}`
12
-
13
- const [oldBlock, newBlock] = await onceWithCleanup(bot, eventName, { timeout: 5000 })
11
+ let newBlock = bot.blockAt(dest)
12
+ if (oldBlock.type === newBlock.type) {
13
+ [oldBlock, newBlock] = await onceWithCleanup(bot, `blockUpdate:${dest}`, { timeout: 5000 })
14
+ }
14
15
 
15
16
  if (oldBlock.type === newBlock.type) {
16
17
  throw new Error(`No block has been placed : the block is still ${oldBlock.name}`)
@@ -23,4 +23,14 @@ module.exports = (bot) => {
23
23
 
24
24
  return bot.world.raycast(eyePosition, viewDirection, maxDistance, matcher)
25
25
  }
26
+
27
+ bot.blockAtEntityCursor = (entity = bot.entity, maxDistance = 256, matcher = null) => {
28
+ if (!entity.position || !entity.height || !entity.pitch || !entity.yaw) return null
29
+ const { position, height, pitch, yaw } = entity
30
+
31
+ const eyePosition = position.offset(0, height, 0)
32
+ const viewDirection = getViewDirection(pitch, yaw)
33
+
34
+ return bot.world.raycast(eyePosition, viewDirection, maxDistance, matcher)
35
+ }
26
36
  }
@@ -91,7 +91,7 @@ function inject (bot) {
91
91
  item = bot.inventory.findInventoryItem(item)
92
92
  }
93
93
  if (item == null || typeof item !== 'object') {
94
- throw new Error('Invalid item object in equip')
94
+ throw new Error('Invalid item object in equip (item is null or typeof item is not object)')
95
95
  }
96
96
  if (!destination || destination === null) {
97
97
  destination = 'hand'
@@ -1,4 +1,4 @@
1
- const Vec3 = require('vec3').Vec3
1
+ const { Vec3 } = require('vec3')
2
2
 
3
3
  module.exports = inject
4
4
 
@@ -1,4 +1,4 @@
1
- const Vec3 = require('vec3').Vec3
1
+ const { Vec3 } = require('vec3')
2
2
 
3
3
  module.exports = inject
4
4
 
@@ -83,6 +83,7 @@ function inject (bot, { version }) {
83
83
  }
84
84
 
85
85
  villager.trades = null
86
+ villager.selectedTrade = null
86
87
 
87
88
  villager.once('close', () => {
88
89
  bot._client.removeListener(tradeListPacket, gotTrades)
@@ -117,7 +118,6 @@ function inject (bot, { version }) {
117
118
  if (!ready) {
118
119
  ready = true
119
120
  villager.emit('ready')
120
- console.log('emit ready')
121
121
  }
122
122
  }
123
123
  }
@@ -127,6 +127,7 @@ function inject (bot, { version }) {
127
127
  assert.notStrictEqual(villager.trades, null)
128
128
  assert.notStrictEqual(villager.trades[choice], null)
129
129
  const Trade = villager.trades[choice]
130
+ villager.selectedTrade = Trade
130
131
  count = count || Trade.maximumNbTradeUses - Trade.nbTradeUses
131
132
  assert.ok(Trade.maximumNbTradeUses - Trade.nbTradeUses > 0, 'trade blocked')
132
133
  assert.ok(Trade.maximumNbTradeUses - Trade.nbTradeUses >= count)
@@ -134,8 +135,9 @@ function inject (bot, { version }) {
134
135
  const itemCount1 = villager.count(Trade.inputItem1.type, Trade.inputItem1.metadata)
135
136
  const hasEnoughItem1 = itemCount1 >= Trade.realPrice * count
136
137
  let hasEnoughItem2 = true
138
+ let itemCount2 = 0
137
139
  if (Trade.hasItem2) {
138
- const itemCount2 = villager.count(Trade.inputItem2.type, Trade.inputItem2.metadata)
140
+ itemCount2 = villager.count(Trade.inputItem2.type, Trade.inputItem2.metadata)
139
141
  hasEnoughItem2 = itemCount2 >= Trade.inputItem2.count * count
140
142
  }
141
143
  if (!hasEnoughItem1 || !hasEnoughItem2) {
@@ -143,60 +145,73 @@ function inject (bot, { version }) {
143
145
  }
144
146
 
145
147
  selectTrade(choice)
146
-
147
148
  if (bot.supportFeature('selectingTradeMovesItems')) { // 1.14+ the server moves items around by itself after selecting a trade
148
- await new Promise((resolve, reject) => {
149
- const updatedSlots = {}
150
- function cb (slot) {
151
- updatedSlots[slot] = true
152
- if (updatedSlots[0] && updatedSlots[2] && (!Trade.hasItem2 || updatedSlots[1])) {
153
- clearTimeout(timeout)
154
- villager.removeListener('updateSlot', cb)
155
- resolve()
149
+ const proms = []
150
+ proms.push(once(villager, 'updateSlot:0'))
151
+ if (Trade.hasItem2) proms.push(once(villager, 'updateSlot:1'))
152
+ if (bot.supportFeature('setSlotAsTransaction')) {
153
+ proms.push(once(villager, 'updateSlot:2'))
154
+ await new Promise((resolve, reject) => {
155
+ let countOfItemOneLeftToTake = itemCount1 > 64 ? 64 : itemCount1
156
+ let countOfItemTwoLeftToTake = 0
157
+ if (Trade.hasItem2) {
158
+ countOfItemTwoLeftToTake = itemCount2 > 64 ? 64 : itemCount2
156
159
  }
157
- }
158
- villager.on('updateSlot', cb)
159
- const timeout = setTimeout(() => {
160
- clearTimeout(timeout)
161
- villager.removeListener('updateSlot', cb)
162
- reject(new Error('Timed out waiting for window updates'))
163
- }, 30000)
164
- })
160
+ const listener = (slot, oldItem, newItem) => {
161
+ if (!(slot >= villager.inventoryStart && slot <= villager.inventoryEnd)) return
162
+ if (newItem === null) {
163
+ if (oldItem.type === Trade.inputItem1.type) countOfItemOneLeftToTake -= oldItem.count
164
+ else if (Trade.hasItem2 && oldItem.type === Trade.inputItem2.type) countOfItemTwoLeftToTake -= oldItem.count
165
+ }
166
+ if (countOfItemOneLeftToTake === 0 && countOfItemTwoLeftToTake === 0) {
167
+ villager.off('updateSlot', listener)
168
+ resolve()
169
+ }
170
+ }
171
+ villager.on('updateSlot', listener)
172
+ })
173
+ }
174
+ await Promise.all(proms)
165
175
  }
176
+
166
177
  for (let i = 0; i < count; i++) {
167
178
  await putRequirements(villager, Trade, count)
168
- villager.updateSlot(2, Object.assign({}, Trade.outputItem))
169
- await bot.putAway(2, true)
170
- const [slot1, slot2] = villager.slots
171
- if (slot1) {
172
- assert.strictEqual(slot1.type, Trade.inputItem1.type)
173
- const updatedCount1 = slot1.count - Trade.realPrice
174
- const updatedSlot1 = updatedCount1 <= 0
175
- ? null
176
- : { ...slot1, count: updatedCount1 }
177
- villager.updateSlot(0, updatedSlot1)
179
+ // ToDo: See if this does anything kappa
180
+ Trade.nbTradeUses++
181
+ if (Trade.maximumNbTradeUses - Trade.nbTradeUses === 0) {
182
+ Trade.tradeDisabled = true
178
183
  }
184
+ if (!bot.supportFeature('setSlotAsTransaction')) {
185
+ villager.updateSlot(2, Object.assign({}, Trade.outputItem))
186
+
187
+ const [slot1, slot2] = villager.slots
188
+ if (slot1) {
189
+ assert.strictEqual(slot1.type, Trade.inputItem1.type)
190
+ const updatedCount1 = slot1.count - Trade.realPrice
191
+ const updatedSlot1 = updatedCount1 <= 0
192
+ ? null
193
+ : { ...slot1, count: updatedCount1 }
194
+ villager.updateSlot(0, updatedSlot1)
195
+ }
179
196
 
180
- if (slot2) {
181
- assert.strictEqual(slot2.type, Trade.inputItem2.type)
182
- const updatedCount2 = slot2.count - Trade.inputItem2.count
183
- const updatedSlot2 = updatedCount2 <= 0
184
- ? null
185
- : { ...slot2, count: updatedCount2 }
186
- villager.updateSlot(1, updatedSlot2)
197
+ if (slot2) {
198
+ assert.strictEqual(slot2.type, Trade.inputItem2.type)
199
+ const updatedCount2 = slot2.count - Trade.inputItem2.count
200
+ const updatedSlot2 = updatedCount2 <= 0
201
+ ? null
202
+ : { ...slot2, count: updatedCount2 }
203
+ villager.updateSlot(1, updatedSlot2)
204
+ }
187
205
  }
188
- Trade.nbTradeUses++
206
+
207
+ await bot.putAway(2)
189
208
  }
190
209
 
191
210
  for (const i of [0, 1]) {
192
211
  if (villager.slots[i]) {
193
- await bot.putAway(i, true) // 1.14+ whole stacks of items will automatically be placed , so there might be some left over
212
+ await bot.putAway(i) // 1.14+ whole stacks of items will automatically be placed , so there might be some left over
194
213
  }
195
214
  }
196
-
197
- if (Trade.maximumNbTradeUses - Trade.nbTradeUses === 0) {
198
- Trade.tradeDisabled = true
199
- }
200
215
  }
201
216
 
202
217
  async function putRequirements (window, Trade, count) {
package/lib/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  module.exports = {
2
- supportedVersions: ['1.8', '1.9', '1.10', '1.11', '1.12', '1.13', '1.14', '1.15', '1.16'],
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']
4
- }
2
+ supportedVersions: ['1.8', '1.9', '1.10', '1.11', '1.12', '1.13', '1.14', '1.15', '1.16', '1.17'],
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']
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": "3.10.0",
3
+ "version": "3.12.0",
4
4
  "description": "create minecraft bots with a stable, high level API",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -21,31 +21,32 @@
21
21
  },
22
22
  "license": "MIT",
23
23
  "dependencies": {
24
- "minecraft-data": "^2.79.0",
25
- "minecraft-protocol": "^1.17.0",
26
- "prismarine-biome": "^1.1.0",
27
- "prismarine-block": "^1.6.0",
28
- "prismarine-chat": "^1.1.0",
29
- "prismarine-chunk": "^1.20.3",
30
- "prismarine-entity": "^1.0.0",
31
- "prismarine-item": "^1.6.0",
32
- "prismarine-physics": "^1.0.4",
24
+ "minecraft-data": "^2.95.0",
25
+ "minecraft-protocol": "^1.26.5",
26
+ "prismarine-biome": "^1.1.1",
27
+ "prismarine-block": "^1.10.3",
28
+ "prismarine-chat": "^1.3.3",
29
+ "prismarine-chunk": "^1.26.0",
30
+ "prismarine-entity": "^1.2.0",
31
+ "prismarine-item": "^1.11.0",
32
+ "prismarine-nbt": "^2.0.0",
33
+ "prismarine-physics": "^1.3.1",
33
34
  "prismarine-recipe": "^1.1.0",
34
- "prismarine-windows": "^2.2.0",
35
+ "prismarine-windows": "^2.4.2",
35
36
  "prismarine-world": "^3.6.0",
36
- "protodef": "^1.8.0",
37
- "typed-emitter": "^1.2.0",
38
- "vec3": "^0.1.6"
37
+ "protodef": "^1.14.0",
38
+ "typed-emitter": "^1.3.1",
39
+ "vec3": "^0.1.7"
39
40
  },
40
41
  "devDependencies": {
41
- "@types/node": "^16.0.1",
42
- "doctoc": "^2.0.0",
43
- "minecraft-wrap": "^1.2.1",
42
+ "@types/node": "^17.0.0",
43
+ "doctoc": "^2.0.1",
44
+ "minecraft-wrap": "^1.3.0",
44
45
  "mineflayer": "file:.",
45
- "mocha": "^9.0.0",
46
- "standard": "^16.0.1",
47
- "ts-standard": "^10.0.0",
48
- "typescript": "^4.3.2",
49
- "standard-markdown": "^6.0.0"
46
+ "mocha": "^9.1.2",
47
+ "standard": "^16.0.4",
48
+ "standard-markdown": "^7.1.0",
49
+ "ts-standard": "^11.0.0",
50
+ "typescript": "^4.4.3"
50
51
  }
51
52
  }