diff --git a/lib/plugins/ray_trace.js b/lib/plugins/ray_trace.js index e45c83f019..1436c3673f 100644 --- a/lib/plugins/ray_trace.js +++ b/lib/plugins/ray_trace.js @@ -55,8 +55,11 @@ module.exports = (bot) => { } bot.blockAtEntityCursor = (entity = bot.entity, maxDistance = 256, matcher = null) => { - if (!entity.position || !entity.height || !entity.pitch || !entity.yaw) return null + if (!entity.position) return null const { position, height, pitch, yaw } = entity + // Number.isFinite (rather than truthiness) so a legitimate 0 yaw or pitch + // is not mistaken for a missing value. See issue #3935. + if (!Number.isFinite(height) || !Number.isFinite(pitch) || !Number.isFinite(yaw)) return null const eyePosition = position.offset(0, height, 0) const viewDirection = getViewDirection(pitch, yaw) diff --git a/test/externalTests/rayTrace.js b/test/externalTests/rayTrace.js index 8d252e3c52..31c101c27f 100644 --- a/test/externalTests/rayTrace.js +++ b/test/externalTests/rayTrace.js @@ -23,4 +23,34 @@ module.exports = () => async (bot) => { block = bot.blockInSight() assert.deepStrictEqual(block.position, relBlock.position) assert.deepStrictEqual(block.face, relBlock.face) + + // Regression for #3935: a yaw or pitch of exactly 0 is a valid orientation + // and must not be rejected by the validation in blockAtEntityCursor. + // yaw=0, pitch=0 looks straight ahead along -Z. Build a small stone wall a + // couple of blocks ahead at eye level (3 wide, to stay robust to the bot's + // exact sub-block position), clear the path in front of it, then assert the + // ray trace finds the wall instead of returning null. + const pos = bot.entity.position + const bx = Math.floor(pos.x) + const bz = Math.floor(pos.z) + const eyeY = Math.floor(pos.y + bot.entity.height) + // clear the eye-level path in front of the bot (2 deep, 3 wide) + for (const dz of [0, -1]) { + for (const dx of [-1, 0, 1]) { + await bot.test.setBlock({ x: bx + dx, y: eyeY, z: bz + dz, blockName: 'air' }) + } + } + // stone wall 2 blocks ahead + for (const dx of [-1, 0, 1]) { + await bot.test.setBlock({ x: bx + dx, y: eyeY, z: bz - 2, blockName: 'stone' }) + } + bot.entity.yaw = 0 + bot.entity.pitch = 0 + const zeroBlock = bot.blockAtEntityCursor(bot.entity, 16) + assert.ok(zeroBlock, 'blockAtEntityCursor returned null for zero yaw/pitch (#3935)') + assert.strictEqual(zeroBlock.name, 'stone') + // tidy up the wall + for (const dx of [-1, 0, 1]) { + await bot.test.setBlock({ x: bx + dx, y: eyeY, z: bz - 2, blockName: 'air' }) + } }