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 05fad2a847868e224212369ebe2eeb0748c4c962..ba7dbe660b71bfc4358e68e5c71e84389643b259 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -1658,10 +1658,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()) { @@ -2527,6 +2530,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 c5fa64b2d1559bf47b3dac8a2a10205e93e638dd..1209aafa118d7bf01eebade3b994678a7c200b0b 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java @@ -1014,6 +1014,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 e6a83032d23d434b62cb2b67e256978fe3f31921..3afd85ae7a69ec9007cceb4a1f7c5fef340df023 100644 --- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java +++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java @@ -212,6 +212,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 18f198fb410b579390fc93c848fda34b407b39b4..d1b6ebf4b8df338b3ffcef2a55124636b3199fb3 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java @@ -1990,6 +1990,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);