-
Bug
-
Resolution: Unresolved
-
None
-
1.20.4, 24w09a, 24w10a, 24w12a, 24w13a, 1.20.5 Release Candidate 1, 1.20.5, 24w19b, 1.21 Pre-Release 1, 1.21, 24w39a, 1.21.3, 1.21.4
-
None
-
Community Consensus
-
Combat
deep breath
Okay. I've decided to get over my stubbornness and report this bug, even though I don't really want it fixed the intended way, because at the end of the day it's still a bug and Mojang gets to decide what to do with it, not me.
The bug:
The death messages "<player> fell too far and was finished by <player/mob>" and "<player> fell too far and was finished by <player/mob> using <item>" do not use the intended logic to appear. Consequently, they don't appear when a player takes fall damage and then dies to another player or mob.
How to reproduce:
- Summon a husk on the ground (or any other mob that can kill you, I only chose the husk because it doesn't burn in the sunlight so it makes this easier to set up).
- Fly up 20 blocks (not more, you risk death from fall damage if you fly up 23 blocks or more).
- Switch to survival mode.
- Fall down and land next to the husk, taking fall damage.
- Let the husk kill you.
- Look at the death message.
Expected result:
"<player> fell too far and was finished by Husk"
Observed result:
"<player> was slain by Husk"
Cause:
The code analysis below uses 24w09a's code, deobfuscated manually using the official obfuscation mappings.
Living entities have a CombatTracker, which tracks the details of damage recently taken. That class contains a method, getFallMessage, which is called when the latest damage taken is fall damage, to get the death message to be shown. That method is shown below.
private Component getFallMessage(CombatEntry combatEntry, Entity entity) { DamageSource damageSource = combatEntry.source(); if(damageSource.is(DamageTypeTags.IS_FALL) || damageSource.is(DamageTypeTags.ALWAYS_MOST_SIGNIFICANT_FALL)) { FallLocation fallLocation = (FallLocation) Objects.requireNonNullElse(combatEntry.fallLocation(), FallLocation.GENERIC); return Component.translatable(fallLocation.languageKey(), new Object[] { this.mob.getDisplayName() }); } Component entityComponent = getDisplayName(entity); Entity cause = damageSource.getEntity(); Component causeComponent = getDisplayName(cause); if(causeComponent != null && !causeComponent.equals(entityComponent)) { return getMessageForAssistedFall(cause, causeComponent, "death.fell.assist.item", "death.fell.assist"); } if(entityComponent != null) { return getMessageForAssistedFall(entity, entityComponent, "death.fell.finish.item", "death.fell.finish"); } return Component.translatable("death.fell.killer", new Object[] { this.mob.getDisplayName() }); }
The combatEntry argument of this method is the most significant damage recently taken (not the latest one, as that one is always fall damage), and the entity argument is the entity that dealt the latest damage (the fall damage), if any.
The method first checks if the most significant damage is fall damage or void damage, in which case it checks what climbable block the player fell from, if any, and shows the corresponding death message, with "<player> fell from a high place" being the fallback message. If this condition fails, the method then checks if the most significant damage was dealt by an entity, in which case it returns "<player> was doomed to fall by <player/mob> (using <item>)", where <player/mob> is the entity that dealt the most significant damage.
If that condition fails as well, it checks if the fall damage was dealt by an entity, in which case it returns "<player> fell too far and was finished by <player/mob> (using <item>)", where <player/mob> is the entity that dealt the fall damage. This is where the faulty logic lies, since you can't take fall damage that was dealt by a player or mob without the use of commands.
The intended way to get the death message in question is by taking fall damage, then dying to damage dealt by a player or mob. The mistake here happened in the fall damage check: the latest damage is checked to see if it's fall damage instead of the most significant damage. This happens because this method only runs if the latest damage is fall damage in the first place. In order to fix this issue, the game would have to check if the player took fall damage recently, every time they die to a player or mob, to determine if it should show the death message.
If anyone is wondering, there is a way to get the death message in question: the player would have to take environmental damage, fall at least 5 blocks and then use the /damage command to take lethal fall damage dealt by a player or mob.