mojira.dev
MC-312826

`/kill` fails to kill the target if it recently survived 3.4028235E38+ damage due to the Resistance effect

Issue: There is a way to make mobs resist the /kill command.

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. Therefore, even if we have 100% normal damage reduction from Resistance V, which can reduce most damage to 0, this.lastHurt is still the raw damage. The /kill command deals 3.4028235E38 points of generic_kill damage, and this damage type does not have the BYPASSES_COOLDOWN tag. We can give a mob Resistance V, then use the /damage command to deal 3.4028235E38 points of normal damage to the mob. At this point, Resistance V will reduce this damage to 0, but because PHDI processes before Resistance, this.lastHurt still records 3.4028235E38. Then, before PHDI ends, use the /kill command on the mob. The 3.4028235E38 points of generic_kill damage dealt by /kill will be nullified due to PHDI, so the mob survives the /kill command without losing any health. The above process does not work on players in Creative mode or on mobs immune to normal damage, because damage immunity is processed before PHDI. PHDI does not record raw damage that has been nullified by immunity, so it is impossible to use a this.lastHurt value of 3.4028235E38f to override the damage from /kill. Therefore, /kill can always kill players in Creative mode.

Steps to Reproduce:

  1. Use /effect give @s minecraft:resistance infinite 4 true to obtain Resistance V;

  2. Prepare two command blocks:

    1. in the first, enter /damage @p 340282350000000000000000000000000000000 minecraft:cactus (any damage type that can be reduced by Resistance);

    2. in the second, enter /kill @p;

  3. Switch to Survival mode and 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: /kill should be designed to always kill any mob under any circumstances.

Additional Notes: Nevertheless, fixing this bug is very simple—it only requires adding the BYPASSES_COOLDOWN tag to generic_kill. However, 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 “There is a way to make mobs resist the /kill command.” is only one of them. Since I cannot include multiple issues in a single report, I have split them up and reported them separately.

Attachments

Comments 3

Thank you for helping us improve Minecraft! We saved your files:

[media][media]

Steps to Reproduce: See the video.

Can confirm.

  1. /effect give @s minecraft:resistance infinite 4 true

  2. First commmand block: damage @p 340282350000000000000000000000000000000 minecraft:cactus

  3. Second command block: kill @p

  4. Switch to survival

  5. Power the command blocks

SekaiDorem

(Unassigned)

Confirmed

Platform HC

Low

Combat

26.3

Retrieved