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 8feff873c7bcce3530814b19f01719bab7837fa8..597a99e30741eeae339043240c4e80e4818399ca 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 d3807e4e75f20cd8c7afc17ce0d1e66abe404e90..50526fd30e84f8812454c264afd79f11c2190a35 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 8a06a090993119da256db12671e56720ef74c2e2..0c0d4ec5893f082a8b4071a627a64c7b88fd0067 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java @@ -1988,6 +1988,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);