mineflayer 4.1.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.
@@ -16,8 +16,8 @@ const FACING_MAP = {
16
16
  east: { north: 'right', south: 'left' }
17
17
  }
18
18
 
19
- function inject (bot, { version }) {
20
- const { instruments, blocks } = require('minecraft-data')(version)
19
+ function inject (bot) {
20
+ const { instruments, blocks } = bot.registry
21
21
 
22
22
  // Stores how many players have currently open a container at a certain position
23
23
  const openCountByPos = {}
@@ -44,7 +44,7 @@ function inject (bot, { version }) {
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, { version }) {
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
  }
@@ -3,9 +3,8 @@ const { once } = require('events')
3
3
 
4
4
  module.exports = inject
5
5
 
6
- function inject (bot, { version }) {
7
- const mcData = require('minecraft-data')(version)
8
- const Item = require('prismarine-item')(version)
6
+ function inject (bot) {
7
+ const Item = require('prismarine-item')(bot.version)
9
8
 
10
9
  let editBook
11
10
  if (bot.supportFeature('editBookIsPluginChannel')) {
@@ -28,7 +27,7 @@ function inject (bot, { version }) {
28
27
  async function write (slot, pages, author, title, signing) {
29
28
  assert.ok(slot >= 0 && slot <= 44, 'slot out of inventory range')
30
29
  const book = bot.inventory.slots[slot]
31
- assert.ok(book && book.type === mcData.itemsByName.writable_book.id, `no book found in slot ${slot}`)
30
+ assert.ok(book && book.type === bot.registry.itemsByName.writable_book.id, `no book found in slot ${slot}`)
32
31
  const quickBarSlot = bot.quickBarSlot
33
32
  const moveToQuickBar = slot < 36
34
33
 
@@ -60,7 +59,7 @@ function inject (bot, { version }) {
60
59
  }
61
60
  if (signing) {
62
61
  if (bot.supportFeature('clientUpdateBookIdWhenSign')) {
63
- book.type = mcData.itemsByName.written_book.id
62
+ book.type = bot.registry.itemsByName.written_book.id
64
63
  }
65
64
  book.nbt.value.author = {
66
65
  type: 'string',
@@ -33,7 +33,7 @@ function inject (bot, options) {
33
33
  bot.addChatPattern = (name, pattern, opts = {}) => {
34
34
  if (!(pattern instanceof RegExp)) throw new Error('Pattern parameter should be of type RegExp')
35
35
  const { repeat = true, deprecated = false, parse = false } = opts
36
- _patterns[_length++] = {
36
+ _patterns[_length] = {
37
37
  name,
38
38
  patterns: [pattern],
39
39
  position: 0,
@@ -43,7 +43,7 @@ function inject (bot, options) {
43
43
  repeat,
44
44
  parse
45
45
  }
46
- return _length
46
+ return _length++ // increment length after we give it back to the user
47
47
  }
48
48
 
49
49
  bot.removeChatPattern = name => {
@@ -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']
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
- if (containerToOpen.constructor.name === 'Block') {
17
- chest = await bot.openBlock(containerToOpen)
19
+ if (containerToOpen.constructor.name === 'Block' && allowedWindowTypes.map(name => name.replace('minecraft:', '')).includes(containerToOpen.name)) {
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
@@ -4,8 +4,8 @@ const { once } = require('events')
4
4
  module.exports = inject
5
5
 
6
6
  function inject (bot, { version }) {
7
- const Item = require('prismarine-item')(version)
8
- const Recipe = require('prismarine-recipe')(version).Recipe
7
+ const Item = require('prismarine-item')(bot.version)
8
+ const Recipe = require('prismarine-recipe')(version).Recipe // TODO: update for prismarine-registry
9
9
 
10
10
  async function craft (recipe, count, craftingTable) {
11
11
  assert.ok(recipe)
@@ -1,32 +1,30 @@
1
1
  const assert = require('assert')
2
2
  const { Vec3 } = require('vec3')
3
- const { sleep } = require('../promise_utils')
3
+ const { sleep, onceWithCleanup } = require('../promise_utils')
4
4
  const { once } = require('events')
5
5
 
6
6
  module.exports = inject
7
7
 
8
- function inject (bot, { version }) {
9
- const Item = require('prismarine-item')(version)
8
+ function inject (bot) {
9
+ const Item = require('prismarine-item')(bot.version)
10
10
 
11
11
  // these features only work when you are in creative mode.
12
12
  bot.creative = {
13
- setInventorySlot: setInventorySlot,
14
- flyTo: flyTo,
13
+ setInventorySlot,
14
+ flyTo,
15
15
  startFlying,
16
- stopFlying
16
+ stopFlying,
17
+ clearSlot: slotNum => setInventorySlot(slotNum, null),
18
+ clearInventory
17
19
  }
18
20
 
19
21
  const creativeSlotsUpdates = []
20
- bot._client.on('set_slot', ({ windowId, slot, item }) => {
21
- if (windowId === 0 && creativeSlotsUpdates[slot]) {
22
- bot.emit(`set_creative_slot_${slot}`)
23
- }
24
- })
25
22
 
26
23
  // WARN: This method should not be called twice on the same slot before first promise succeeds
27
24
  async function setInventorySlot (slot, item) {
28
25
  assert(slot >= 0 && slot <= 44)
29
26
 
27
+ if (Item.equal(bot.inventory.slots[slot], item, true)) return
30
28
  if (creativeSlotsUpdates[slot]) {
31
29
  throw new Error(`Setting slot ${slot} cancelled due to calling bot.creative.setInventorySlot(${slot}, ...) again`)
32
30
  }
@@ -37,10 +35,14 @@ function inject (bot, { version }) {
37
35
  item: Item.toNotch(item)
38
36
  })
39
37
 
40
- await once(bot, `set_creative_slot_${slot}`)
38
+ await onceWithCleanup(bot.inventory, `updateSlot:${slot}`, { checkCondition: (oldItem, newItem) => item === null ? newItem === null : newItem?.name === item.name && newItem?.count === item.count && newItem?.metadata === item.metadata })
41
39
  creativeSlotsUpdates[slot] = false
42
40
  }
43
41
 
42
+ async function clearInventory () {
43
+ return Promise.all(bot.inventory.slots.filter(item => item).map(item => setInventorySlot(item.slot, null)))
44
+ }
45
+
44
46
  let normalGravity = null
45
47
  const flyingSpeedPerUpdate = 0.5
46
48
 
@@ -24,13 +24,12 @@ const entityStatusEvents = {
24
24
  10: 'entityEatingGrass'
25
25
  }
26
26
 
27
- function inject (bot, { version }) {
28
- const Entity = require('prismarine-entity')(version)
29
- const objects = require('minecraft-data')(version).objects
30
- const mobs = require('minecraft-data')(version).mobs
31
- const entitiesArray = require('minecraft-data')(version).entitiesArray
32
- const Item = require('prismarine-item')(version)
33
- const ChatMessage = require('prismarine-chat')(version)
27
+ function inject (bot) {
28
+ const { objects, mobs, entitiesArray } = bot.registry
29
+ const Entity = require('prismarine-entity')(bot.version) // TODO: update for prismarine-registry
30
+ const Item = require('prismarine-item')(bot.version)
31
+ const ChatMessage = require('prismarine-chat')(bot.version) // TODO: update for prismarine-registry
32
+
34
33
  // ONLY 1.17 has this destroy_entity packet which is the same thing as entity_destroy packet except the entity is singular
35
34
  // 1.17.1 reverted this change so this is just a simpler fix
36
35
  bot._client.on('destroy_entity', (packet) => {
@@ -570,7 +569,7 @@ function inject (bot, { version }) {
570
569
  function moveVehicle (left, forward) {
571
570
  bot._client.write('steer_vehicle', {
572
571
  sideways: left,
573
- forward: forward,
572
+ forward,
574
573
  jump: 0x01
575
574
  })
576
575
  }
@@ -4,14 +4,12 @@ const { createDoneTask, createTask } = require('../promise_utils')
4
4
  module.exports = inject
5
5
 
6
6
  function inject (bot) {
7
- const mcData = require('minecraft-data')(bot.version)
8
-
9
7
  let bobberId = 90
10
8
  // Before 1.14 the bobber entity keep changing name at each version (but the id stays 90)
11
9
  // 1.14 changes the id, but hopefully we can stick with the name: fishing_bobber
12
10
  // the alternative would be to rename it in all version of mcData
13
11
  if (bot.supportFeature('fishingBobberCorrectlyNamed')) {
14
- bobberId = mcData.entitiesByName.fishing_bobber.id
12
+ bobberId = bot.registry.entitiesByName.fishing_bobber.id
15
13
  }
16
14
 
17
15
  let fishingTask = createDoneTask()
@@ -27,7 +25,7 @@ function inject (bot) {
27
25
  if (!lastBobber || fishingTask.done) return
28
26
 
29
27
  const pos = lastBobber.position
30
- const parts = mcData.particlesByName
28
+ const parts = bot.registry.particlesByName
31
29
  if (packet.particleId === (parts?.fishing ?? parts.bubble).id && packet.particles === 6 && pos.distanceTo(new Vec3(packet.x, pos.y, packet.z)) <= 1.23) {
32
30
  bot.activateItem()
33
31
  lastBobber = undefined
@@ -67,10 +67,13 @@ function inject (bot, options) {
67
67
 
68
68
  bot.emit('login')
69
69
  bot.emit('game')
70
- bot._client.write('held_item_slot', { slotId: 0 })
71
70
 
72
71
  // varint length-prefixed string as data
73
72
  bot._client.writeChannel(brandChannel, options.brand)
73
+
74
+ if (packet.dimensionCodec) {
75
+ bot.registry.loadDimensionCodec(packet.dimensionCodec)
76
+ }
74
77
  })
75
78
 
76
79
  bot._client.on('respawn', (packet) => {
@@ -1,8 +1,8 @@
1
1
  const assert = require('assert')
2
2
  module.exports = inject
3
3
 
4
- function inject (bot, { version }) {
5
- const Item = require('prismarine-item')(version)
4
+ function inject (bot) {
5
+ const Item = require('prismarine-item')(bot.version)
6
6
  /**
7
7
  *
8
8
  * @param {import('prismarine-block').Block} referenceBlock
@@ -20,10 +20,9 @@ const ALWAYS_CONSUMABLES = [
20
20
  'golden_apple'
21
21
  ]
22
22
 
23
- function inject (bot, { version, hideErrors }) {
24
- const Item = require('prismarine-item')(version)
25
- const windows = require('prismarine-windows')(version)
26
- const mcData = require('minecraft-data')(version)
23
+ function inject (bot, { hideErrors }) {
24
+ const Item = require('prismarine-item')(bot.version)
25
+ const windows = require('prismarine-windows')(bot.version) // TODO: update for prismarine-registry
27
26
 
28
27
  let eatingTask = createDoneTask()
29
28
 
@@ -151,45 +150,48 @@ function inject (bot, { version, hideErrors }) {
151
150
  }
152
151
  }
153
152
 
154
- 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)
155
157
  // TODO: tell the server that we are not sneaking while doing this
156
158
  await bot.lookAt(block.position.offset(0.5, 0.5, 0.5), false)
157
159
  // place block message
158
160
  if (bot.supportFeature('blockPlaceHasHeldItem')) {
159
161
  bot._client.write('block_place', {
160
162
  location: block.position,
161
- direction: 1,
163
+ direction: directionNum,
162
164
  heldItem: Item.toNotch(bot.heldItem),
163
- cursorX: 8,
164
- cursorY: 8,
165
- cursorZ: 8
165
+ cursorX: cursorPos.scaled(16).x,
166
+ cursorY: cursorPos.scaled(16).y,
167
+ cursorZ: cursorPos.scaled(16).z
166
168
  })
167
169
  } else if (bot.supportFeature('blockPlaceHasHandAndIntCursor')) {
168
170
  bot._client.write('block_place', {
169
171
  location: block.position,
170
- direction: 1,
172
+ direction: directionNum,
171
173
  hand: 0,
172
- cursorX: 8,
173
- cursorY: 8,
174
- cursorZ: 8
174
+ cursorX: cursorPos.scaled(16).x,
175
+ cursorY: cursorPos.scaled(16).y,
176
+ cursorZ: cursorPos.scaled(16).z
175
177
  })
176
178
  } else if (bot.supportFeature('blockPlaceHasHandAndFloatCursor')) {
177
179
  bot._client.write('block_place', {
178
180
  location: block.position,
179
- direction: 1,
181
+ direction: directionNum,
180
182
  hand: 0,
181
- cursorX: 0.5,
182
- cursorY: 0.5,
183
- cursorZ: 0.5
183
+ cursorX: cursorPos.x,
184
+ cursorY: cursorPos.y,
185
+ cursorZ: cursorPos.z
184
186
  })
185
187
  } else if (bot.supportFeature('blockPlaceHasInsideBlock')) {
186
188
  bot._client.write('block_place', {
187
189
  location: block.position,
188
- direction: 1,
190
+ direction: directionNum,
189
191
  hand: 0,
190
- cursorX: 0.5,
191
- cursorY: 0.5,
192
- cursorZ: 0.5,
192
+ cursorX: cursorPos.x,
193
+ cursorY: cursorPos.y,
194
+ cursorZ: cursorPos.z,
193
195
  insideBlock: false
194
196
  })
195
197
  }
@@ -251,7 +253,7 @@ function inject (bot, { version, hideErrors }) {
251
253
  (nbt != null && window.selectedItem.nbt !== nbt)) {
252
254
  // we are not holding the item we need. click it.
253
255
  const sourceItem = window.findItemRange(sourceStart, sourceEnd, itemType, metadata, false, nbt)
254
- const mcDataEntry = mcData.itemsArray.find(x => x.id === itemType)
256
+ const mcDataEntry = bot.registry.itemsArray.find(x => x.id === itemType)
255
257
  assert(mcDataEntry, 'Invalid itemType')
256
258
  if (!sourceItem) throw new Error(`Can't find ${mcDataEntry.name} in slots [${sourceStart} - ${sourceEnd}], (item id: ${itemType})`)
257
259
  if (firstSourceSlot === null) firstSourceSlot = sourceItem.slot
@@ -303,8 +305,8 @@ function inject (bot, { version, hideErrors }) {
303
305
 
304
306
  function extendWindow (window) {
305
307
  window.close = () => {
306
- window.emit('close')
307
308
  closeWindow(window)
309
+ window.emit('close')
308
310
  }
309
311
 
310
312
  window.withdraw = async (itemType, metadata, count, nbt) => {
@@ -326,7 +328,7 @@ function inject (bot, { version, hideErrors }) {
326
328
  }
327
329
  window.deposit = async (itemType, metadata, count, nbt) => {
328
330
  const options = {
329
- window: window,
331
+ window,
330
332
  itemType,
331
333
  metadata,
332
334
  count,
@@ -340,8 +342,8 @@ function inject (bot, { version, hideErrors }) {
340
342
  }
341
343
  }
342
344
 
343
- async function openBlock (block) {
344
- bot.activateBlock(block)
345
+ async function openBlock (block, direction, cursorPos) {
346
+ bot.activateBlock(block, direction, cursorPos)
345
347
  const [window] = await once(bot, 'windowOpen')
346
348
  extendWindow(window)
347
349
  return window
@@ -382,7 +384,7 @@ function inject (bot, { version, hideErrors }) {
382
384
  if (item) {
383
385
  item.slot = slot
384
386
  }
385
- bot.inventory.slots[slot] = item
387
+ if (!Item.equal(bot.inventory.slots[slot], item, true)) bot.inventory.updateSlot(slot, item)
386
388
  }
387
389
  }
388
390
 
@@ -434,14 +436,11 @@ function inject (bot, { version, hideErrors }) {
434
436
  if (click === undefined || !windowClickQueue.some(clicks => clicks.id === actionId)) {
435
437
  // mimic vanilla client and send a rejection for faulty transaction packets
436
438
  bot._client.write('transaction', {
437
- windowId: windowId,
439
+ windowId,
438
440
  action: actionId,
439
441
  accepted: true
440
442
  // bot.emit(`confirmTransaction${click.id}`, false)
441
443
  })
442
- if (!hideErrors) {
443
- console.log(`WARNING : unknown transaction confirmation for window ${windowId}, action ${actionId} and accepted ${accepted}`)
444
- }
445
444
  return
446
445
  }
447
446
  // shift it later if packets are sent out of order
@@ -517,7 +516,7 @@ function inject (bot, { version, hideErrors }) {
517
516
  slot,
518
517
  mouseButton,
519
518
  mode,
520
- changedSlots: changedSlots,
519
+ changedSlots,
521
520
  cursorItem: Item.toNotch(window.selectedItem)
522
521
  })
523
522
  } else if (bot.supportFeature('actionIdUsed')) { // <= 1.16.5
@@ -535,7 +534,7 @@ function inject (bot, { version, hideErrors }) {
535
534
  slot,
536
535
  mouseButton,
537
536
  mode,
538
- changedSlots: changedSlots,
537
+ changedSlots,
539
538
  cursorItem: Item.toNotch(window.selectedItem)
540
539
  })
541
540
  }
@@ -645,6 +644,28 @@ function inject (bot, { version, hideErrors }) {
645
644
  bot.emit(`setWindowItems:${window.id}`)
646
645
  })
647
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
+
648
669
  bot.activateBlock = activateBlock
649
670
  bot.activateEntity = activateEntity
650
671
  bot.activateEntityAt = activateEntityAt
@@ -15,10 +15,10 @@ const PHYSICS_INTERVAL_MS = 50
15
15
  const PHYSICS_TIMESTEP = PHYSICS_INTERVAL_MS / 1000
16
16
 
17
17
  function inject (bot, { physicsEnabled }) {
18
- const mcData = require('minecraft-data')(bot.version)
19
-
20
18
  const world = { getBlock: (pos) => { return bot.blockAt(pos, false) } }
21
- const physics = Physics(mcData, world)
19
+ const physics = Physics(bot.registry, world)
20
+
21
+ const positionUpdateSentEveryTick = bot.supportFeature('positionUpdateSentEveryTick')
22
22
 
23
23
  bot.jumpQueued = false
24
24
  bot.jumpTicks = 0 // autojump cooldown
@@ -150,7 +150,7 @@ function inject (bot, { physicsEnabled }) {
150
150
  // Send a position packet every second, even if no update was made
151
151
  sendPacketPosition(position, onGround)
152
152
  lastSent.time = performance.now()
153
- } else if (bot.supportFeature('positionUpdateSentEveryTick') && bot.isAlive) {
153
+ } else if (positionUpdateSentEveryTick && bot.isAlive) {
154
154
  // For versions < 1.12, one player packet should be sent every tick
155
155
  // for the server to update health correctly
156
156
  bot._client.write('flying', { onGround: bot.entity.onGround })
@@ -2,8 +2,8 @@ const assert = require('assert')
2
2
 
3
3
  module.exports = inject
4
4
 
5
- function inject (bot, { version }) {
6
- const Item = require('prismarine-item')(version)
5
+ function inject (bot) {
6
+ const Item = require('prismarine-item')(bot.version)
7
7
 
8
8
  /**
9
9
  *
@@ -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
@@ -90,7 +90,7 @@ function inject (bot, options) {
90
90
  enableServerListing: options.enableServerListing || true
91
91
  }
92
92
 
93
- bot._client.once('login', () => {
93
+ bot._client.on('login', () => {
94
94
  setSettings({})
95
95
  })
96
96
 
@@ -5,7 +5,7 @@ const escapeValueNewlines = str => {
5
5
  }
6
6
 
7
7
  function inject (bot) {
8
- const ChatMessage = require('prismarine-chat')(bot.version)
8
+ const ChatMessage = require('prismarine-chat')(bot.version) // TODO: update for prismarine-registry
9
9
 
10
10
  bot.tablist = {
11
11
  header: new ChatMessage(''),
@@ -29,8 +29,11 @@ function inject (bot) {
29
29
  }
30
30
  if (team !== undefined) {
31
31
  if (mode === 1) {
32
- bot.emit('teamRemoved', teams[teamName])
32
+ team.members.forEach(member => {
33
+ delete bot.teamMap[member]
34
+ })
33
35
  delete teams[teamName]
36
+ bot.emit('teamRemoved', teams[teamName])
34
37
  }
35
38
  if (mode === 2) {
36
39
  team.update(
@@ -4,8 +4,8 @@ const { once } = require('events')
4
4
  module.exports = inject
5
5
 
6
6
  function inject (bot, { version }) {
7
- const mcData = require('minecraft-data')(version)
8
- const Item = require('prismarine-item')(version)
7
+ const { entitiesByName } = bot.registry
8
+ const Item = require('prismarine-item')(bot.version)
9
9
 
10
10
  let selectTrade
11
11
  if (bot.supportFeature('useMCTrSel')) {
@@ -70,7 +70,7 @@ function inject (bot, { version }) {
70
70
  }
71
71
 
72
72
  async function openVillager (villagerEntity) {
73
- const villagerType = mcData.entitiesByName.villager ? mcData.entitiesByName.villager.id : mcData.entitiesByName.Villager.id
73
+ const villagerType = entitiesByName.villager ? entitiesByName.villager.id : entitiesByName.Villager.id
74
74
  assert.strictEqual(villagerEntity.entityType, villagerType)
75
75
  let ready = false
76
76
 
package/lib/scoreboard.js CHANGED
@@ -5,7 +5,7 @@ const sortItems = (a, b) => {
5
5
  }
6
6
 
7
7
  module.exports = (bot) => {
8
- const ChatMessage = require('prismarine-chat')(bot.version)
8
+ const ChatMessage = require('prismarine-chat')(bot.version) // TODO: update for prismarine-registry
9
9
 
10
10
  class ScoreBoard {
11
11
  constructor (packet) {
package/lib/team.js CHANGED
@@ -3,8 +3,8 @@ let MessageBuilder
3
3
 
4
4
  module.exports = loader
5
5
 
6
- function loader (mcVersion) {
7
- ChatMessage = require('prismarine-chat')(mcVersion)
6
+ function loader (version) {
7
+ ChatMessage = require('prismarine-chat')(version) // TODO: update for prismarine-registry
8
8
  MessageBuilder = ChatMessage.MessageBuilder
9
9
  return Team
10
10
  }