From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: BillyGalbreath Date: Fri, 28 May 2021 12:24:45 -0500 Subject: [PATCH] Fix advancement triggers on entity death This fixes PaperMC/Paper#3729 and PaperMC/Paper#4252 Paper changes logical order revolving around making the EntityDeathEvent cancellable. Reordering this logic has ended up with entity equipment being cleared _before_ advancement criteria can run, causing things like killing raid captains not giving the voluntary exile advancement. This fixes the issue by storing a copy of the equipment in a new field just before doing the death event logic where the equipment is cleared and then restoring it back to the entity just before the criterion triggers run and then finally clearing the equipment again right after the criterion is done. diff --git a/src/main/java/net/minecraft/world/entity/EntityInsentient.java b/src/main/java/net/minecraft/world/entity/EntityInsentient.java index b895288e0aa49e5a1222f7c5897f3dc43ff946fe..e4f5a5ffd25d4d4e427938a633675be46805af66 100644 --- a/src/main/java/net/minecraft/world/entity/EntityInsentient.java +++ b/src/main/java/net/minecraft/world/entity/EntityInsentient.java @@ -106,9 +106,9 @@ public abstract class EntityInsentient extends EntityLiving { public PathfinderGoalSelector targetSelector; private EntityLiving goalTarget; private final EntitySenses bo; - private final NonNullList bp; + private final NonNullList bp; public List getHandEquipment() { return this.bp; } // Purpur - OBFHELPER public final float[] dropChanceHand; - private final NonNullList bq; + private final NonNullList bq; public List getArmorEquipment() { return this.bq; } // Purpur - OBFHELPER public final float[] dropChanceArmor; // private boolean canPickUpLoot; // CraftBukkit - moved up to EntityLiving public boolean persistent; @@ -1013,6 +1013,41 @@ public abstract class EntityInsentient extends EntityLiving { } } + // Purpur start + public List> cloneEquipment() { + List> list = new java.util.ArrayList<>(); + List handItems = new java.util.ArrayList<>(); + for (ItemStack item : this.getHandEquipment()) { + handItems.add(item.cloneItemStack()); + } + list.add(handItems); + List armorItems = new java.util.ArrayList<>(); + for (ItemStack item : this.getArmorEquipment()) { + armorItems.add(item.cloneItemStack()); + } + list.add(armorItems); + return list; + } + + public void restoreEquipment(List> list) { + this.getHandEquipment().clear(); + List handItems = list.get(0); + for (int i = 0; i < handItems.size(); i++) { + this.getHandEquipment().set(i, handItems.get(1)); + } + this.getArmorEquipment().clear(); + List armorItems = list.get(1); + for (int i = 0; i < armorItems.size(); i++) { + this.getArmorEquipment().set(i, armorItems.get(i)); + } + } + + public void clearEquipment() { + this.getHandEquipment().clear(); + this.getArmorEquipment().clear(); + } + // Purpur end + @Override public void setSlot(EnumItemSlot enumitemslot, ItemStack itemstack) { switch (enumitemslot.a()) { diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java index 6b65b17d6b100adacd628d08a24a68164d2bb9aa..2f7352d7ae99ecdefe0f7b56cebf008906607d4d 100644 --- a/src/main/java/net/minecraft/world/entity/EntityLiving.java +++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java @@ -1560,10 +1560,13 @@ public abstract class EntityLiving extends Entity { } // Paper start + List> equipmentSnapshotBefore = this.cloneEquipment(); // Purpur org.bukkit.event.entity.EntityDeathEvent deathEvent = this.d(damagesource); if (deathEvent == null || !deathEvent.isCancelled()) { if (this.getKillCount() >= 0 && entityliving != null) { + this.restoreEquipment(equipmentSnapshotBefore); // Purpur entityliving.runKillTrigger(this, this.getKillCount(), damagesource); + this.clearEquipment(); // Purpur } if (this.isSleeping()) { this.entityWakeup(); @@ -2274,6 +2277,12 @@ public abstract class EntityLiving extends Entity { public abstract ItemStack getEquipment(EnumItemSlot enumitemslot); + // Purpur start + public abstract List> cloneEquipment(); + public abstract void restoreEquipment(List> list); + public abstract void clearEquipment(); + // Purpur end + // CraftBukkit start public void setSlot(EnumItemSlot enumitemslot, ItemStack itemstack, boolean silent) { this.setSlot(enumitemslot, itemstack); diff --git a/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java index ddc1c3383cdc32fa832485f3922c74185731557a..e28a2d983ae7b83f435c9dea606a92e2fbd3391a 100644 --- a/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java +++ b/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java @@ -171,6 +171,41 @@ public class EntityArmorStand extends EntityLiving { } } + // Purpur start + public List> cloneEquipment() { + List> list = new java.util.ArrayList<>(); + List handItems = new java.util.ArrayList<>(); + for (ItemStack item : this.handItems) { + handItems.add(item.cloneItemStack()); + } + list.add(handItems); + List armorItems = new java.util.ArrayList<>(); + for (ItemStack item : this.armorItems) { + armorItems.add(item.cloneItemStack()); + } + list.add(armorItems); + return list; + } + + public void restoreEquipment(List> list) { + this.handItems.clear(); + List handItems = list.get(0); + for (int i = 0; i < handItems.size(); i++) { + this.handItems.set(i, handItems.get(1)); + } + this.armorItems.clear(); + List armorItems = list.get(1); + for (int i = 0; i < armorItems.size(); i++) { + this.armorItems.set(i, armorItems.get(1)); + } + } + + public void clearEquipment() { + this.handItems.clear(); + this.armorItems.clear(); + } + // Purpur end + @Override public void setSlot(EnumItemSlot enumitemslot, ItemStack itemstack) { // CraftBukkit start diff --git a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java index abac4b996c7935ac6115a9ad96191f2a57afc95f..0443aaa9fc4058cc4ce61977a89cdf6ea6452b65 100644 --- a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +++ b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java @@ -1892,6 +1892,52 @@ public abstract class EntityHuman extends EntityLiving { return enumitemslot == EnumItemSlot.MAINHAND ? this.inventory.getItemInHand() : (enumitemslot == EnumItemSlot.OFFHAND ? (ItemStack) this.inventory.extraSlots.get(0) : (enumitemslot.a() == EnumItemSlot.Function.ARMOR ? (ItemStack) this.inventory.armor.get(enumitemslot.b()) : ItemStack.b)); } + // Purpur start + public List> cloneEquipment() { + List> list = new java.util.ArrayList<>(); + List invItems = new java.util.ArrayList<>(); + for (ItemStack item : this.inventory.items) { + invItems.add(item.cloneItemStack()); + } + list.add(invItems); + List armorItems = new java.util.ArrayList<>(); + for (ItemStack item : this.inventory.armor) { + armorItems.add(item.cloneItemStack()); + } + list.add(armorItems); + List extraItems = new java.util.ArrayList<>(); + for (ItemStack item : this.inventory.extraSlots) { + extraItems.add(item.cloneItemStack()); + } + list.add(extraItems); + return list; + } + + public void restoreEquipment(List> list) { + this.inventory.items.clear(); + List invItems = list.get(0); + for (int i = 0; i < invItems.size(); i++) { + this.inventory.items.set(i, invItems.get(1)); + } + this.inventory.armor.clear(); + List armorItems = list.get(1); + for (int i = 0; i < armorItems.size(); i++) { + this.inventory.armor.set(i, armorItems.get(1)); + } + this.inventory.extraSlots.clear(); + List extraItems = list.get(2); + for (int i = 0; i < extraItems.size(); i++) { + this.inventory.extraSlots.set(i, extraItems.get(1)); + } + } + + public void clearEquipment() { + this.inventory.items.clear(); + this.inventory.armor.clear(); + this.inventory.extraSlots.clear(); + } + // Purpur end + @Override public void setSlot(EnumItemSlot enumitemslot, ItemStack itemstack) { // CraftBukkit start