aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/0912-Restore-vanilla-entity-drops-behavior.patch
diff options
context:
space:
mode:
authorBjarne Koll <[email protected]>2024-09-15 21:39:53 +0200
committerGitHub <[email protected]>2024-09-15 21:39:53 +0200
commitd1a72eac31cdf532e77dce960c51b66d63f932ea (patch)
treeb2b7c1ccfb8492622625562f4ef94ec1223d0afc /patches/server/0912-Restore-vanilla-entity-drops-behavior.patch
parent4ff58c4c48383b17446b7bbad3e477dbe74aee9f (diff)
downloadPaper-d1a72eac31cdf532e77dce960c51b66d63f932ea.tar.gz
Paper-d1a72eac31cdf532e77dce960c51b66d63f932ea.zip
Updated Upstream (Bukkit/CraftBukkit/Spigot) (#11405)
Upstream has released updates that appear to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Bukkit Changes: 1fc1020a PR-1049: Add MenuType API 8ae2e3be PR-1055: Expand riptiding API cac68bfb SPIGOT-7890: AttributeModifier#getUniqueId() doesn't match the UUID passed to its constructor 7004fcf2 SPIGOT-7886: Fix mistake in AttributeModifier UUID shim 1ac7f950 PR-1054: Add FireworkMeta#hasPower 4cfb565f SPIGOT-7873: Add powered state for skulls CraftBukkit Changes: bbb30e7a8 SPIGOT-7894: NPE when sending tile entity update ba21e9472 SPIGOT-7895: PlayerItemBreakEvent not firing 0fb24bbe0 SPIGOT-7875: Fix PlayerItemConsumeEvent cancellation causing client-side desync 815066449 SPIGOT-7891: Can't remove second ingredient of MerchantRecipe 45c206f2c PR-1458: Add MenuType API 19c8ef9ae SPIGOT-7867: Merchant instanceof AbstractVillager always returns false 4e006d28f PR-1468: Expand riptiding API bd8aded7d Ignore checks in CraftPlayerProfile for ResolvableProfile used in profile components 8679620b5 SPIGOT-7889: Fix tool component deserialisation without speed and/or correct-for-drops 8d5222691 SPIGOT-7882, PR-1467: Fix conversion of name in Profile Component to empty if it is missing 63f91669a SPIGOT-7887: Remove duplicate ProjectileHitEvent for fireballs 7070de8c8 SPIGOT-7878: Server#getLootTable does not return null on invalid loot table 060ee6cae SPIGOT-7876: Can't kick player or disconnect player in PlayerLoginEvent when checking for cookies 7ccb86cc0 PR-1465: Add FireworkMeta#hasPower 804ad6491 SPIGOT-7873: Add powered state for skulls f9610cdcb Improve minecart movement Spigot Changes: a759b629 Rebuild patches Co-authored-by: Jake Potrebic <[email protected]>
Diffstat (limited to 'patches/server/0912-Restore-vanilla-entity-drops-behavior.patch')
-rw-r--r--patches/server/0912-Restore-vanilla-entity-drops-behavior.patch270
1 files changed, 270 insertions, 0 deletions
diff --git a/patches/server/0912-Restore-vanilla-entity-drops-behavior.patch b/patches/server/0912-Restore-vanilla-entity-drops-behavior.patch
new file mode 100644
index 0000000000..ac02649470
--- /dev/null
+++ b/patches/server/0912-Restore-vanilla-entity-drops-behavior.patch
@@ -0,0 +1,270 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jake Potrebic <[email protected]>
+Date: Tue, 22 Mar 2022 09:34:41 -0700
+Subject: [PATCH] Restore vanilla entity drops behavior
+
+Instead of just tracking the itemstacks, this tracks with it, the
+action to take with that itemstack to apply the correct logic
+on dropping the item instead of generalizing it for all dropped
+items like CB does.
+
+diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
+index b65d816bb9feb18ecf74e10e9728c302e5657587..62ec627e80b87a92a2a51ba9fc3626a67636855f 100644
+--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
+@@ -976,20 +976,20 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
+ if (this.isRemoved()) {
+ return;
+ }
+- java.util.List<org.bukkit.inventory.ItemStack> loot = new java.util.ArrayList<>(this.getInventory().getContainerSize());
++ List<DefaultDrop> loot = new java.util.ArrayList<>(this.getInventory().getContainerSize()); // Paper - Restore vanilla drops behavior
+ boolean keepInventory = this.level().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) || this.isSpectator();
+
+ if (!keepInventory) {
+ for (ItemStack item : this.getInventory().getContents()) {
+ if (!item.isEmpty() && !EnchantmentHelper.has(item, EnchantmentEffectComponents.PREVENT_EQUIPMENT_DROP)) {
+- loot.add(CraftItemStack.asCraftMirror(item).markForInventoryDrop());
++ loot.add(new DefaultDrop(item, stack -> this.drop(stack, true, false, false))); // Paper - Restore vanilla drops behavior; drop function taken from Inventory#dropAll (don't fire drop event)
+ }
+ }
+ }
+ if (this.shouldDropLoot() && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { // Paper - fix player loottables running when mob loot gamerule is false
+ // SPIGOT-5071: manually add player loot tables (SPIGOT-5195 - ignores keepInventory rule)
+ this.dropFromLootTable(damageSource, this.lastHurtByPlayerTime > 0);
+- this.dropCustomDeathLoot(this.serverLevel(), damageSource, flag);
++ // Paper - Restore vanilla drops behaviour; custom death loot is a noop on server player, remove.
+
+ loot.addAll(this.drops);
+ this.drops.clear(); // SPIGOT-5188: make sure to clear
+diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
+index f163cb3c75e90b96b3794a7e0c5b803268814c8c..57e7938bc605f320ed5303fcbc617b4d32ba42b8 100644
+--- a/src/main/java/net/minecraft/world/entity/Entity.java
++++ b/src/main/java/net/minecraft/world/entity/Entity.java
+@@ -2562,6 +2562,25 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
+
+ @Nullable
+ public ItemEntity spawnAtLocation(ItemStack stack, float yOffset) {
++ // Paper start - Restore vanilla drops behavior
++ return this.spawnAtLocation(stack, yOffset, null);
++ }
++ public record DefaultDrop(Item item, org.bukkit.inventory.ItemStack stack, @Nullable java.util.function.Consumer<ItemStack> dropConsumer) {
++ public DefaultDrop(final ItemStack stack, final java.util.function.Consumer<ItemStack> dropConsumer) {
++ this(stack.getItem(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), dropConsumer);
++ }
++
++ public void runConsumer(final org.bukkit.World fallbackWorld, final Location fallbackLoc) {
++ if (this.dropConsumer == null || org.bukkit.craftbukkit.inventory.CraftItemType.bukkitToMinecraft(this.stack.getType()) != this.item) {
++ fallbackWorld.dropItem(fallbackLoc, this.stack);
++ } else {
++ this.dropConsumer.accept(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(this.stack));
++ }
++ }
++ }
++ @Nullable
++ public ItemEntity spawnAtLocation(ItemStack stack, float yOffset, @Nullable java.util.function.Consumer<? super ItemEntity> delayedAddConsumer) {
++ // Paper end - Restore vanilla drops behavior
+ if (stack.isEmpty()) {
+ return null;
+ } else if (this.level().isClientSide) {
+@@ -2569,14 +2588,21 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
+ } else {
+ // CraftBukkit start - Capture drops for death event
+ if (this instanceof net.minecraft.world.entity.LivingEntity && !((net.minecraft.world.entity.LivingEntity) this).forceDrops) {
+- ((net.minecraft.world.entity.LivingEntity) this).drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack)); // Paper - mirror so we can destroy it later
++ // Paper start - Restore vanilla drops behavior
++ ((net.minecraft.world.entity.LivingEntity) this).drops.add(new net.minecraft.world.entity.Entity.DefaultDrop(stack, itemStack -> {
++ ItemEntity itemEntity = new ItemEntity(this.level, this.getX(), this.getY() + (double) yOffset, this.getZ(), itemStack); // stack is copied before consumer
++ itemEntity.setDefaultPickUpDelay();
++ this.level.addFreshEntity(itemEntity);
++ if (delayedAddConsumer != null) delayedAddConsumer.accept(itemEntity);
++ }));
++ // Paper end - Restore vanilla drops behavior
+ return null;
+ }
+ // CraftBukkit end
+ ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY() + (double) yOffset, this.getZ(), stack.copy()); // Paper - copy so we can destroy original
+ stack.setCount(0); // Paper - destroy this item - if this ever leaks due to game bugs, ensure it doesn't dupe
+
+- entityitem.setDefaultPickUpDelay();
++ entityitem.setDefaultPickUpDelay(); // Paper - diff on change (in dropConsumer)
+ // Paper start - Call EntityDropItemEvent
+ return this.spawnAtLocation(entityitem);
+ }
+diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
+index 0c67f04ae7eeaa10a90419031447ad5397c6b9e2..6b2dc430126713e11658f94762035ff10bbe018c 100644
+--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
+@@ -278,7 +278,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
+ protected float appliedScale;
+ // CraftBukkit start
+ public int expToDrop;
+- public ArrayList<org.bukkit.inventory.ItemStack> drops = new ArrayList<org.bukkit.inventory.ItemStack>();
++ public ArrayList<DefaultDrop> drops = new ArrayList<>(); // Paper - Restore vanilla drops behavior
+ public final org.bukkit.craftbukkit.attribute.CraftAttributeMap craftAttributes;
+ public boolean collides = true;
+ public Set<UUID> collidableExemptions = new HashSet<>();
+diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java
+index 1b49090a466bc74d9e5f2815314955b6dfbb83dc..62271e74399a827a488159da234465ef18e15e6e 100644
+--- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java
++++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java
+@@ -538,10 +538,9 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob
+ @Override
+ protected void dropCustomDeathLoot(ServerLevel world, DamageSource source, boolean causedByPlayer) {
+ super.dropCustomDeathLoot(world, source, causedByPlayer);
+- ItemEntity entityitem = this.spawnAtLocation((ItemLike) Items.NETHER_STAR);
+-
++ ItemEntity entityitem = this.spawnAtLocation(new net.minecraft.world.item.ItemStack(Items.NETHER_STAR), 0, ItemEntity::setExtendedLifetime); // Paper - Restore vanilla drops behavior; spawnAtLocation returns null so modify the item entity with a consumer
+ if (entityitem != null) {
+- entityitem.setExtendedLifetime();
++ entityitem.setExtendedLifetime(); // Paper - diff on change
+ }
+
+ }
+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 5bcb9a53ebebeef4bd6ec2458df4b63002ebd804..2f398750bfee5758ad8b1367b6fc14364e4de776 100644
+--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
++++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
+@@ -621,7 +621,7 @@ public class ArmorStand extends LivingEntity {
+ ItemStack itemstack = new ItemStack(Items.ARMOR_STAND);
+
+ itemstack.set(DataComponents.CUSTOM_NAME, this.getCustomName());
+- this.drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack)); // CraftBukkit - add to drops
++ this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior
+ return this.brokenByAnything(world, damageSource); // Paper
+ }
+
+@@ -635,7 +635,7 @@ public class ArmorStand extends LivingEntity {
+ for (i = 0; i < this.handItems.size(); ++i) {
+ itemstack = (ItemStack) this.handItems.get(i);
+ if (!itemstack.isEmpty()) {
+- this.drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)); // CraftBukkit - add to drops // Paper - mirror so we can destroy it later - though this call site was safe
++ this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition().above(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior; mirror so we can destroy it later - though this call site was safe & spawn drops correctly
+ this.handItems.set(i, ItemStack.EMPTY);
+ }
+ }
+@@ -643,7 +643,7 @@ public class ArmorStand extends LivingEntity {
+ for (i = 0; i < this.armorItems.size(); ++i) {
+ itemstack = (ItemStack) this.armorItems.get(i);
+ if (!itemstack.isEmpty()) {
+- this.drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)); // CraftBukkit - add to drops // Paper - mirror so we can destroy it later - though this call site was safe
++ this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition().above(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior; mirror so we can destroy it later - though this call site was safe & spawn drops correctly
+ this.armorItems.set(i, ItemStack.EMPTY);
+ }
+ }
+diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+index 2690c471b819f8308f6db44150025dfa323d4e0c..0d6cdb6b0dfd84f619a5e43150165b4606a96bcd 100644
+--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+@@ -975,18 +975,24 @@ public class CraftEventFactory {
+ }
+
+ public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource) {
+- return CraftEventFactory.callEntityDeathEvent(victim, damageSource, new ArrayList<org.bukkit.inventory.ItemStack>(0));
++ return CraftEventFactory.callEntityDeathEvent(victim, damageSource, new ArrayList<>(0)); // Paper - Restore vanilla drops behavior
+ }
+
+- public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource, List<org.bukkit.inventory.ItemStack> drops) {
++ public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource, List<Entity.DefaultDrop> drops) { // Paper - Restore vanilla drops behavior
+ // Paper start
+ return CraftEventFactory.callEntityDeathEvent(victim, damageSource, drops, com.google.common.util.concurrent.Runnables.doNothing());
+ }
+- public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource, List<org.bukkit.inventory.ItemStack> drops, Runnable lootCheck) {
++
++ private static final java.util.function.Function<org.bukkit.inventory.ItemStack, Entity.DefaultDrop> FROM_FUNCTION = stack -> {
++ if (stack == null) return null;
++ return new Entity.DefaultDrop(CraftItemType.bukkitToMinecraft(stack.getType()), stack, null);
++ };
++
++ public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource, List<Entity.DefaultDrop> drops, Runnable lootCheck) { // Paper
+ // Paper end
+ CraftLivingEntity entity = (CraftLivingEntity) victim.getBukkitEntity();
+ CraftDamageSource bukkitDamageSource = new CraftDamageSource(damageSource);
+- EntityDeathEvent event = new EntityDeathEvent(entity, bukkitDamageSource, drops, victim.getExpReward(damageSource.getEntity()));
++ EntityDeathEvent event = new EntityDeathEvent(entity, bukkitDamageSource, new io.papermc.paper.util.TransformingRandomAccessList<>(drops, Entity.DefaultDrop::stack, FROM_FUNCTION), victim.getExpReward(damageSource.getEntity())); // Paper - Restore vanilla drops behavior
+ populateFields(victim, event); // Paper - make cancellable
+ CraftWorld world = (CraftWorld) entity.getWorld();
+ Bukkit.getServer().getPluginManager().callEvent(event);
+@@ -1000,20 +1006,24 @@ public class CraftEventFactory {
+ victim.expToDrop = event.getDroppedExp();
+ lootCheck.run(); // Paper - advancement triggers before destroying items
+
+- for (org.bukkit.inventory.ItemStack stack : event.getDrops()) {
++ // Paper start - Restore vanilla drops behavior
++ for (Entity.DefaultDrop drop : drops) {
++ if (drop == null) continue;
++ final org.bukkit.inventory.ItemStack stack = drop.stack();
++ // Paper end - Restore vanilla drops behavior
+ if (stack == null || stack.getType() == Material.AIR || stack.getAmount() == 0) continue;
+
+- world.dropItem(entity.getLocation(), stack); // Paper - note: dropItem already clones due to this being bukkit -> NMS
++ drop.runConsumer(world, entity.getLocation()); // Paper - Restore vanilla drops behavior
+ if (stack instanceof CraftItemStack) stack.setAmount(0); // Paper - destroy this item - if this ever leaks due to game bugs, ensure it doesn't dupe, but don't nuke bukkit stacks of manually added items
+ }
+
+ return event;
+ }
+
+- public static PlayerDeathEvent callPlayerDeathEvent(ServerPlayer victim, DamageSource damageSource, List<org.bukkit.inventory.ItemStack> drops, net.kyori.adventure.text.Component deathMessage, boolean keepInventory) { // Paper - Adventure
++ public static PlayerDeathEvent callPlayerDeathEvent(ServerPlayer victim, DamageSource damageSource, List<Entity.DefaultDrop> drops, net.kyori.adventure.text.Component deathMessage, boolean keepInventory) { // Paper - Adventure & Restore vanilla drops behavior
+ CraftPlayer entity = victim.getBukkitEntity();
+ CraftDamageSource bukkitDamageSource = new CraftDamageSource(damageSource);
+- PlayerDeathEvent event = new PlayerDeathEvent(entity, bukkitDamageSource, drops, victim.getExpReward(damageSource.getEntity()), 0, deathMessage);
++ PlayerDeathEvent event = new PlayerDeathEvent(entity, bukkitDamageSource, new io.papermc.paper.util.TransformingRandomAccessList<>(drops, Entity.DefaultDrop::stack, FROM_FUNCTION), victim.getExpReward(damageSource.getEntity()), 0, deathMessage); // Paper - Restore vanilla drops behavior
+ event.setKeepInventory(keepInventory);
+ event.setKeepLevel(victim.keepLevel); // SPIGOT-2222: pre-set keepLevel
+ populateFields(victim, event); // Paper - make cancellable
+@@ -1031,16 +1041,14 @@ public class CraftEventFactory {
+ victim.expToDrop = event.getDroppedExp();
+ victim.newExp = event.getNewExp();
+
+- for (org.bukkit.inventory.ItemStack stack : event.getDrops()) {
++ // Paper start - Restore vanilla drops behavior
++ for (Entity.DefaultDrop drop : drops) {
++ if (drop == null) continue;
++ final org.bukkit.inventory.ItemStack stack = drop.stack();
++ // Paper end - Restore vanilla drops behavior
+ if (stack == null || stack.getType() == Material.AIR) continue;
+
+- if (stack instanceof CraftItemStack craftItemStack && craftItemStack.isForInventoryDrop()) {
+- victim.drop(CraftItemStack.asNMSCopy(stack), true, false, false); // SPIGOT-7800, SPIGOT-7801: Vanilla Behaviour for Player Inventory dropped items
+- } else {
+- victim.forceDrops = true;
+- victim.spawnAtLocation(CraftItemStack.asNMSCopy(stack)); // SPIGOT-7806: Vanilla Behaviour for items not related to Player Inventory dropped items
+- victim.forceDrops = false;
+- }
++ drop.runConsumer(entity.getWorld(), entity.getLocation()); // Paper - Restore vanilla drops behavior
+ }
+
+ return event;
+diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
+index c5a09f086d35f84c0a30266f78e06e2dfb5603e6..f33742ee06e8443a5f5adaaa987d7523dc193b5a 100644
+--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
+@@ -130,27 +130,6 @@ public final class CraftItemStack extends ItemStack {
+ this.setItemMeta(itemMeta);
+ }
+
+- /**
+- * Gets if the item is marked as an inventory drop in death events.
+- *
+- * @return true if the item is marked as an inventory drop
+- */
+- @ApiStatus.Internal
+- public boolean isForInventoryDrop() {
+- return this.isForInventoryDrop;
+- }
+-
+- /**
+- * Marks this item as an inventory drop in death events.
+- *
+- * @return the ItemStack marked as an inventory drop
+- */
+- @ApiStatus.Internal
+- public ItemStack markForInventoryDrop() {
+- this.isForInventoryDrop = true;
+- return this;
+- }
+-
+ @Override
+ public MaterialData getData() {
+ return this.handle != null ? CraftMagicNumbers.getMaterialData(this.handle.getItem()) : super.getData();