From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: William Blake Galbreath 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/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java index 214bc2bcbcb88a9a62d2151a62aaa57beadc7da0..6d7a2eece40e5c665d6ec6f21f8a342e350fbec4 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -1661,10 +1661,13 @@ public abstract class LivingEntity extends Entity { } // Paper start + List> equipmentSnapshotBefore = this.cloneEquipment(); // Purpur org.bukkit.event.entity.EntityDeathEvent deathEvent = this.dropAllDeathLoot(source); if (deathEvent == null || !deathEvent.isCancelled()) { if (this.deathScore >= 0 && entityliving != null) { + this.restoreEquipment(equipmentSnapshotBefore); // Purpur entityliving.awardKillScore(this, this.deathScore, source); + this.clearEquipment(); // Purpur } if (this.isSleeping()) { @@ -2548,6 +2551,12 @@ public abstract class LivingEntity extends Entity { @Override public abstract void setItemSlot(EquipmentSlot slot, ItemStack stack); + // Purpur start + public abstract List> cloneEquipment(); + public abstract void restoreEquipment(List> list); + public abstract void clearEquipment(); + // Purpur end + protected void verifyEquippedItem(ItemStack stack) { CompoundTag nbttagcompound = stack.getTag(); diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java index 02a227e1239ca3a1d54d746ea14b6ae7b12d1cd0..74e73e52139445dd2090cfd3abdbf22497a7b4da 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java @@ -1026,6 +1026,41 @@ public abstract class Mob extends LivingEntity { } + // 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.copy()); + } + list.add(handItems); + List armorItems = new java.util.ArrayList<>(); + for (ItemStack item : this.armorItems) { + armorItems.add(item.copy()); + } + 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(i)); + } + } + + public void clearEquipment() { + this.handItems.clear(); + this.armorItems.clear(); + } + // Purpur end + @Override protected void dropCustomDeathLoot(DamageSource source, int lootingMultiplier, boolean allowDrops) { super.dropCustomDeathLoot(source, lootingMultiplier, allowDrops); diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java index 31454b15a20e0484e21c25ffb80d4d536e2ecc0b..4fd44e58e9b83f45a66562f53710ee647b7e2b1b 100644 --- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java +++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java @@ -205,6 +205,41 @@ public class ArmorStand extends LivingEntity { this.noTickEquipmentDirty = true; // Paper - Allow equipment to be updated even when tick disabled } + // 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.copy()); + } + list.add(handItems); + List armorItems = new java.util.ArrayList<>(); + for (ItemStack item : this.armorItems) { + armorItems.add(item.copy()); + } + 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 boolean canTakeItem(ItemStack stack) { net.minecraft.world.entity.EquipmentSlot enumitemslot = Mob.getEquipmentSlotForItem(stack); diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java index c6267fa6832596c1c0944cecbbe0e4ed0eb3e0b8..dc26629d7aa1fc82dbc9902c807312cd814e5465 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java @@ -1991,6 +1991,52 @@ public abstract class Player extends LivingEntity { } + // 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.copy()); + } + list.add(invItems); + List armorItems = new java.util.ArrayList<>(); + for (ItemStack item : this.inventory.armor) { + armorItems.add(item.copy()); + } + list.add(armorItems); + List offhandItems = new java.util.ArrayList<>(); + for (ItemStack item : this.inventory.offhand) { + offhandItems.add(item.copy()); + } + list.add(offhandItems); + 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.offhand.clear(); + List offhandItems = list.get(2); + for (int i = 0; i < offhandItems.size(); i++) { + this.inventory.offhand.set(i, offhandItems.get(1)); + } + } + + public void clearEquipment() { + this.inventory.items.clear(); + this.inventory.armor.clear(); + this.inventory.offhand.clear(); + } + // Purpur end + public boolean addItem(ItemStack stack) { this.equipEventAndSound(stack); return this.inventory.add(stack);