mojira.dev
MC-259259

Hostile mobs can't replace armor they're wearing with better armor

The bug

When summoning a hostile mob creature that can pick up items, if they are equipped with armor, they cannot replace the armor already equipped. They can only replace any items in their hand. All mobs that can wear armor have this problem. The previous version (1.19.2) does not have this problem.

How to reproduce

  1. Summon a skeleton and use data command set "CanPickUpLoot" to 1b like:

    /data modify entity @e[type=minecraft:skeleton,distance=..10,limit=1] CanPickUpLoot set value 1b
  2. Give it basic armor, for example, leather material.

  3. Give it advanced armor like diamond.

  4. You can see it replaced its bow with advanced armor. ❌

  5. If you give it a sword, it will keep picking up and replacing the items on its hand. ❌

Expected behavior

If a mob that can pick up items picks up a type of armor that is better than what it is currently wearing, it should remove what it's wearing and put on the new better armor.

Observed behavior

If a mob that can pick up items picks up a type of armor that is better than what it is currently wearing, it will hold the better armor in its hand and continue to wear the inferior armor.

 

Linked issues

Attachments

Comments 4

I tested this in 1.19.2, 1.19.3, and 23w05a. In 1.19.2, a zombie with CanPickUpLoot set to 1b is able to replace a leather tunic it is already wearing with an iron chestplate. In 1.19.3 and 23w05a, a zombie with CanPickUpLoot set to 1b will hold the iron chestplate in its hand instead of replacing the leather tunic. Providing the zombie with a wooden sword too causes it to juggle the sword and the iron chestplate.

Code analysis (Mojang mappings, 23w05a): In 1.19.2, Mob#equipItemIfPossible(ItemStack) directly got an EquipmentSlot for the item via getEquipmentSlotForItem(ItemStack). As of 1.19.3, there is an extra intermediate function that equipItemIfPossible uses, which is getEquipmentSlotForItemStack(ItemStack):

private EquipmentSlot getEquipmentSlotForItemStack(ItemStack $$0) {
        EquipmentSlot $$1 = Mob.getEquipmentSlotForItem($$0);
        boolean $$2 = this.getItemBySlot($$1).isEmpty();
        return $$1.isArmor() && !$$2 ? EquipmentSlot.MAINHAND : $$1;
    }

The issue with this is that if the slot is occupied (the mob is already wearing an armor that occupies the same slot) and it is an armor piece, both $$1.isArmor() and !$$2 are true. So, this function returns EquipmentSlot.MAINHAND, which means that the mob will place the picked armor item in its main hand instead of replacing the armor.

Only half the bug was fixed. 
In the 'how to reproduce' step 5 is fixed but not step 4.

[media]

I believe the second part is actually a separate bug, MC-193313. If this did not occur before 1.19.3, it would make sense to create a separate ticket for it.

Edit: turns out this actually does not occur in 1.19.1-pre2 (which was a random version that I tested prior to 1.19.3), so this might be a side effect of this bug. I created MC-260839 for this.

xiaofan7520

eowyn36

Confirmed

Platform

Important

Mob behaviour

1.19.3, 23w04a, 23w05a, 1.19.4 Pre-release 1, 1.19.4 Pre-release 2

1.19.4 Pre-release 4

Retrieved