Uploaded image for project: 'Minecraft: Java Edition'
  1. Minecraft: Java Edition
  2. MC-251996

Item entity's Thrower tag is not specified when a mob (e.g. Zombie) switches its current equipment to another with better tier

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • None
    • 1.18.2, 1.19 Pre-release 1, 1.19 Pre-release 2, 1.19 Pre-release 3, 1.19.3, 23w04a
    • Confirmed
    • Items, Mob behaviour
    • Low
    • Platform

      The Bug

      There are several cases in which mobs would drop their item in hand while not upon death. Zombie-related mobs would drop their current holding item if they locate an item with higher tier (e.g. A zombie holding a stone sword will drop the sword when encountering a diamond sword). Piglins do the similar behavior but they prefer golden items. Foxes will drop their current 'holding' item if they find a preferred food item (e.g. A fox drop the random item they currently keep in its mouth when seeing a raw chicken item). Allays when giving their items to their owners also throws the item.

      The three cases illustrated above yield different results. For the zombie and piglin cases, the item dropped by the mobs are not specified a Thrower tag. On the contrary, foxes and allays do clarify the item's thrower.

      How to Reproduce

      I won't be showing complex steps. Just summon a zombie/piglin/fox with CanPickUpLoot set to 1b and observe their behaviors.

      This is a very trivial bug, but should be considered as one for any how.

      Code Analysis

      Mojang mapping, DecompilerMC, 1.19-pre3

      net.minecraft.world.entity.item.ItemEntity.java
      public class ItemEntity extends Entity {
         ...
         public void setThrower(@Nullable UUID var1) {
            this.thrower = var1;
         }
         ...

      As seen above, the entity should call this method in order to set the Thrower tag. This is not the case for all entities; in fact, only foxes, players and dolphins do so.

      In addition, a static method called upon also sets the thrower tag.

      Mojang mapping, DecompilerMC, 1.19-pre3

      net.minecraft.world.entity.ai.behavior.BehaviorUtils.java
      public class BehaviorUtils {
         ...
         public static void throwItem(LivingEntity var0, ItemStack var1, Vec3 var2) {
            Vec3 var3 = new Vec3(0.30000001192092896D, 0.30000001192092896D, 0.30000001192092896D);
            throwItem(var0, var1, var2, var3, 0.3F);
         }
      
         public static void throwItem(LivingEntity var0, ItemStack var1, Vec3 var2, Vec3 var3, float var4) {
            double var5 = var0.getEyeY() - (double)var4;
            ItemEntity var7 = new ItemEntity(var0.level, var0.getX(), var5, var0.getZ(), var1);
            var7.setThrower(var0.getUUID());
            Vec3 var8 = var2.subtract(var0.position());
            var8 = var8.normalize().multiply(var3.x, var3.y, var3.z);
            var7.setDeltaMovement(var8);
            var7.setDefaultPickUpDelay();
            var0.level.addFreshEntity(var7);
         }
         ...

      This method is called by villagers giving gifts to players with hero of the village effect, trading with villager (somehow), allay giving items to player, and piglin bartering (note that this is different from piglin switching to better gear).

      It seems that the only case without specifying item thrower is the mobs picking up items with better tiers.

      Mojang mapping, DecompilerMC, 1.19-pre3

      net.minecraft.world.entity.ai.behavior.BehaviorUtils.java
      public abstract class Mob extends LivingEntity {
         ...
         protected void pickUpItem(ItemEntity var1) {
            ItemStack var2 = var1.getItem();
            if (this.equipItemIfPossible(var2)) {
               this.onItemPickup(var1);
               this.take(var1, var2.getCount());
               var1.discard();
            }
      
         }
      
         public boolean equipItemIfPossible(ItemStack var1) {
            EquipmentSlot var2 = getEquipmentSlotForItem(var1);
            ItemStack var3 = this.getItemBySlot(var2);
            boolean var4 = this.canReplaceCurrentItem(var1, var3);
            if (var4 && this.canHoldItem(var1)) {
               double var5 = (double)this.getEquipmentDropChance(var2);
               if (!var3.isEmpty() && (double)Math.max(this.random.nextFloat() - 0.1F, 0.0F) < var5) {
                  this.spawnAtLocation(var3);
               }
      
               this.setItemSlotAndDropWhenKilled(var2, var1);
               return true;
            } else {
               return false;
            }
         }
         ...

      When the item can be picked up, the spawnAtLocation method is called, which refers to a method that spawns an item entity without specifying any special tag, including Thrower. This should account for the zombie-like mobs not setting Thrower when switching to a better gear.

            Unassigned Unassigned
            g2245820920 g2245820920
            Votes:
            5 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              CHK: