Skip to content

fix: only set isAlive to false on death respawn, not dimension change - #3967

Open
AnonymoDGH wants to merge 2 commits into
PrismarineJS:masterfrom
AnonymoDGH:fix/respawn-isalive-dimension-change
Open

fix: only set isAlive to false on death respawn, not dimension change#3967
AnonymoDGH wants to merge 2 commits into
PrismarineJS:masterfrom
AnonymoDGH:fix/respawn-isalive-dimension-change

Conversation

@AnonymoDGH

Copy link
Copy Markdown

Fixes #3905

Problem

The respawn packet is sent both when the player dies and when they change dimensions (e.g. via a portal or a proxy/server switch). The current handler unconditionally sets bot.isAlive = false on every respawn packet, so after a dimension change the bot is wrongly marked dead even though it is still alive.

Downstream, physics.js stops sending position/rotation updates once isAlive is false (after the 20-tick grace window), so the bot freezes in place on the server even though it is alive.

Fix

Use the respawn packet's copyMetadata ("Data To Keep") field to distinguish the two cases:

  • Death respawn: the server sends copyMetadata = 0 (KEEP_NOTHING) — the bot is dead.
  • Dimension change: the server sends a non-zero copyMetadata (KEEP_ATTRIBUTES / KEEP_METADATA / KEEP_ALL) — the bot is still alive.
bot._client.on('respawn', (packet) => {
  // The respawn packet is sent both on death and on dimension change. The
  // copyMetadata (Data To Keep) field is 0 on death and non-zero when the
  // player is simply moving between dimensions, so only mark the bot dead on
  // an actual death respawn. On versions before 1.16.1 the field is absent
  // (undefined), which keeps the previous always-false behaviour. See #3905.
  bot.isAlive = Boolean(packet.copyMetadata)
  bot.emit('respawn')
})

This matches how lib/plugins/blocks.js already interprets the same field (copyMetadata === true => dimension change, keep the world loaded).

Version compatibility

  • 1.16.1+: copyMetadata is present in the respawn packet (verified in minecraft-data protocol.json for 1.16.1 through 1.21.11).
  • <= 1.15.2: the field is absent, so packet.copyMetadata is undefined and Boolean(undefined) === false — identical to the previous always-false behaviour, so nothing changes on those versions.

Verified

  • npx standard lib/plugins/health.js passes.
  • Full internal test suite: npx mocha test/internalTest.js -> 555 passing, 0 failing (the existing switchWorld respawn test, which sends copyMetadata: true, still passes).

@AnonymoDGH

Copy link
Copy Markdown
Author

Pushed a follow-up commit (44bd87e) after CI caught a real regression in my first attempt.

What broke: the nether external test failed on every job >= 1.16.5. That test waits for the spawn event after a dimension change. On master, respawn sets isAlive = false, so the next update_health (health > 0) hits the !bot.isAlive branch and emits spawn. My first commit set isAlive = true on dimension change, so that branch never fired and spawn was never emitted.

The fix: keep isAlive = true on dimension change (the actual #3905 fix, so physics keeps updating position), but also set a one-shot flag so the next update_health still emits spawn at the same timing master used. Death respawns (copyMetadata === false) and pre-1.16.1 versions (copyMetadata === undefined) keep the exact previous behaviour.

Verified locally: standard clean and internalTest 555 passing / 39 pending / 0 failing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

In respawn event, bot.isAlive is always set to false

1 participant