diff --git a/lib/plugins/health.js b/lib/plugins/health.js index ba35b73952..45807a0406 100644 --- a/lib/plugins/health.js +++ b/lib/plugins/health.js @@ -2,9 +2,26 @@ module.exports = inject function inject (bot, options) { bot.isAlive = true + // Set when a dimension-change respawn is received so that the next + // update_health packet re-emits spawn, matching the timing used for deaths. + let spawnAfterDimensionChange = false bot._client.on('respawn', (packet) => { - bot.isAlive = false + // The respawn packet is sent both on death and on dimension change. The + // copyMetadata (Data To Keep) field is false on death and true when the + // player is simply moving between dimensions. On a real death, mark the + // bot dead so the next update_health re-emits spawn. On a dimension change + // the bot is still alive, so keep isAlive true (so physics keeps updating + // its position, see #3905) and schedule a spawn event for the next + // update_health, since consumers (and the nether test) expect spawn to + // fire when the bot re-enters a world. On versions before 1.16.1 the field + // is absent (undefined), which keeps the previous always-false behaviour. + if (packet.copyMetadata) { + bot.isAlive = true + spawnAfterDimensionChange = true + } else { + bot.isAlive = false + } bot.emit('respawn') }) @@ -26,8 +43,9 @@ function inject (bot, options) { } if (!options.respawn) return bot.respawn() - } else if (bot.health > 0 && !bot.isAlive) { + } else if (bot.health > 0 && (!bot.isAlive || spawnAfterDimensionChange)) { bot.isAlive = true + spawnAfterDimensionChange = false bot.emit('spawn') } })