Issue: The order of different damage types may affect the final damage.
Mechanism: In 26.3, Post Hit Damage Immunity (hereinafter referred to as PHDI) is calculated as follows: if this.damageCooldownTime > 10 and the damage does not have the BYPASSES_COOLDOWN tag, then the incoming damage is compared with this.lastHurt, and the actual damage is obtained as damage - this.lastHurt; finally, this.lastHurt is set to damage, thereby implementing “within one PHDI, the highest damage value takes effect.” However, PHDI adjusts the damage value first, before all other damage reduction effects. This means that regardless of what damage reduction methods the mob has, this.lastHurt will only record the damage before damage reduction, i.e., only the raw damage. When a player wears a full Netherite armor set, if 25 physical damage is dealt first and then 12 magic damage, the 25 physical damage is first reduced by armor to 9.99999, but this.lastHurt remains 25. Then the 12 magic damage is nullified because PHDI has recorded 25, so the final damage is 9.99999. However, if 12 magic damage is dealt first, this 12 damage takes full effect; then the 25 physical damage becomes 25 - 12 = 13 due to PHDI, and after armor reduction it becomes 3.952, so the final total damage is 15.952.
Steps to Reproduce:
Prepare two sets of command blocks:
one set deals 25 physical damage first and then 12 magic damage;
the other set deals 12 magic damage first and then 25 physical damage.
The player wears a full Netherite armor set.
Power the command blocks.
public boolean hurtServer(final ServerLevel level, final DamageSource source, float damage) {
if (this.isInvulnerableTo(level, source)) {
return false;
} else if (this.isDeadOrDying()) {
return false;
} else if (source.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) {
return false;
} else {
if (this.isSleeping()) {
this.stopSleeping();
}
this.noActionTime = 0;
if (damage < 0.0F) {
damage = 0.0F;
}
float originalDamage = damage;
ItemStack itemInUse = this.getUseItem();
float damageBlocked = this.applyItemBlocking(level, source, damage);
damage -= damageBlocked;
boolean blocked = damageBlocked > 0.0F;
if (source.is(DamageTypeTags.IS_FREEZING) && this.is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES)) {
damage *= 5.0F;
}
if (source.is(DamageTypeTags.DAMAGES_HELMET) && !this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
this.hurtHelmet(source, damage);
damage *= 0.75F;
}
if (Float.isNaN(damage) || Float.isInfinite(damage)) {
damage = Float.MAX_VALUE;
}
boolean tookFullDamage = true;
if ((float)this.damageCooldownTime > 10.0F && !source.is(DamageTypeTags.BYPASSES_COOLDOWN)) {
if (damage <= this.lastHurt) {
return false;
}
this.actuallyHurt(level, source, damage - this.lastHurt);
this.lastHurt = damage;
tookFullDamage = false;
} else {
this.lastHurt = damage;
this.damageCooldownTime = 20;
this.actuallyHurt(level, source, damage);
this.hurtDuration = 10;
this.hurtTime = this.hurtDuration;
}
………………
}
}
………………
protected void actuallyHurt(final ServerLevel level, final DamageSource source, float dmg) {
if (!this.isInvulnerableTo(level, source)) {
dmg = this.getDamageAfterArmorAbsorb(source, dmg);
dmg = this.getDamageAfterMagicAbsorb(source, dmg);
float originalDamage = dmg;
dmg = Math.max(dmg - this.getAbsorptionAmount(), 0.0F);
this.setAbsorptionAmount(this.getAbsorptionAmount() - (originalDamage - dmg));
float absorbedDamage = originalDamage - dmg;
if (absorbedDamage > 0.0F && absorbedDamage < 3.4028235E37F) {
Entity var7 = source.getEntity();
if (var7 instanceof ServerPlayer) {
ServerPlayer serverPlayer = (ServerPlayer)var7;
serverPlayer.awardStat(Stats.DAMAGE_DEALT_ABSORBED, Math.round(absorbedDamage * 10.0F));
}
}
if (dmg != 0.0F) {
this.getCombatTracker().recordDamage(source, dmg);
this.setHealth(this.getHealth() - dmg);
this.setAbsorptionAmount(this.getAbsorptionAmount() - dmg);
this.gameEvent(GameEvent.ENTITY_DAMAGE);
}
}
}Expected: The order of damage should not affect the final damage result.
Additional Notes: The underlying mechanism of this bug is quite profound: it stems from the ordering of PHDI and damage reduction calculations, which can actually lead to many abnormal outcomes, and “The order of different damage types may affect the final damage.” is only one of them. Since I cannot include multiple issues in a single report, I have split them up and reported them separately.
Thank you for helping us improve Minecraft! We saved your files: