diff --git a/lib/plugins/inventory.js b/lib/plugins/inventory.js index bab0eef7b..35f74259e 100644 --- a/lib/plugins/inventory.js +++ b/lib/plugins/inventory.js @@ -72,7 +72,10 @@ function inject (bot, { hideErrors }) { }) bot._client.on('entity_status', (packet) => { - if (packet.entityId === bot.entity.id && packet.entityStatus === 9 && !eatingTask.done) { + if (packet.entityId !== bot.entity.id) return + // Hurt and shield-block notifications do not end the active item use. + if (packet.entityStatus !== 9 && packet.entityStatus !== 3) return + if (packet.entityStatus === 9 && !eatingTask.done) { eatingTask.finish() } bot.usingHeldItem = false diff --git a/test/inventoryItemUseTest.js b/test/inventoryItemUseTest.js new file mode 100644 index 000000000..1e5307c3c --- /dev/null +++ b/test/inventoryItemUseTest.js @@ -0,0 +1,70 @@ +/* eslint-env mocha */ + +const assert = require('assert') +const { EventEmitter } = require('events') +const injectInventory = require('../lib/plugins/inventory') +const { testedVersions } = require('../lib/version') + +function createBot (registry) { + const bot = new EventEmitter() + bot._client = new EventEmitter() + bot._client.write = () => {} + bot.registry = registry + bot.version = registry.version.minecraftVersion + bot.supportFeature = registry.supportFeature + bot.entity = { id: 1, yaw: 0, pitch: 0 } + bot.QUICK_BAR_START = 36 + bot.game = { gameMode: 'survival' } + bot.food = 19 + injectInventory(bot, { hideErrors: false }) + bot.quickBarSlot = 0 + return bot +} + +for (const version of testedVersions) { + const registry = require('prismarine-registry')(version) + describe(`inventory item use and entity status ${version}v`, () => { + for (const entityStatus of [2, 3, 9, 29]) { + it(`keeps using an item when another entity receives status ${entityStatus}`, () => { + const bot = createBot(registry) + bot.activateItem() + bot._client.emit('entity_status', { entityId: 2, entityStatus }) + assert.strictEqual(bot.usingHeldItem, true) + bot.deactivateItem() + assert.strictEqual(bot.usingHeldItem, false) + }) + } + + for (const entityStatus of [2, 29]) { + it(`keeps using an item when the bot receives unrelated status ${entityStatus}`, () => { + const bot = createBot(registry) + bot.activateItem() + bot._client.emit('entity_status', { entityId: bot.entity.id, entityStatus }) + assert.strictEqual(bot.usingHeldItem, true) + bot.deactivateItem() + assert.strictEqual(bot.usingHeldItem, false) + }) + } + + it('clears item use when the bot receives its death status', () => { + const bot = createBot(registry) + bot.activateItem() + bot._client.emit('entity_status', { entityId: bot.entity.id, entityStatus: 3 }) + assert.strictEqual(bot.usingHeldItem, false) + }) + + it('finishes consuming only when the bot receives its completion status', async () => { + const bot = createBot(registry) + const Item = require('prismarine-item')(registry) + bot.inventory.slots[36] = new Item(registry.itemsByName.bread.id, 1) + const consumed = bot.consume() + assert.strictEqual(bot.usingHeldItem, true) + bot._client.emit('entity_status', { entityId: 2, entityStatus: 9 }) + const usingAfterOtherEntity = bot.usingHeldItem + bot._client.emit('entity_status', { entityId: bot.entity.id, entityStatus: 9 }) + await consumed + assert.strictEqual(usingAfterOtherEntity, true) + assert.strictEqual(bot.usingHeldItem, false) + }) + }) +}